现在的问题是:正交投影下如果两个平面的Z值相同,先绘制哪个平面?试验一下
const mesh1 = new Mesh(
new PlaneGeometry(1000, 1000),
new MeshBasicMaterial({ color: 0xff0000})
);
mesh1.name = "test1";
const mesh2 = new Mesh(
new PlaneGeometry(1000, 1000),
new MeshBasicMaterial({ color: 0x00ff00})
);
mesh2.translateX(500);
mesh2.name = "test2";
scene.add(mesh1);
scene.add(mesh2);
上面代码的执行结果是mesh2在上面。
const mesh1 = new Mesh(
new PlaneGeometry(1000, 1000),
new MeshBasicMaterial({ color: 0xff0000})
);
mesh1.name = "test1";
const mesh2 = new Mesh(
new PlaneGeometry(1000, 1000),
new MeshBasicMaterial({ color: 0x00ff00})
);
mesh2.translateX(500);
mesh2.name = "test2";
scene.add(mesh2);
scene.add(mesh1);
注意:这个代码与第一个代码块的差别只是mesh加入到场景的顺序不同。
上面代码的执行结果如下图
两个代码块的执行结果相同,都是mesh2在上面。这与我刚开始想象的不同,我以为后加入场景的后绘制,因此第二个代码块的执行结果应该是mesh1红色在上面。
如果现在我就想mesh1红色在上面,怎么办?
这时可以引入renderorder。
const mesh1 = new Mesh(
new PlaneGeometry(1000, 1000),
new MeshBasicMaterial({ color: 0xff0000})
);
mesh1.name = "test1";
mesh1.renderOrder = 1;
const mesh2 = new Mesh(
new PlaneGeometry(1000, 1000),
new MeshBasicMaterial({ color: 0x00ff00})
);
mesh2.translateX(500);
mesh2.name = "test2";
scene.add(mesh1);
scene.add(mesh2);
注意:这个代码块与第一个代码块不同的是将mesh1的renderorder设为1。
结果如上图,跟我想象的一致。mesh1红色在上面了。
直接给出源码,解释一下上面现象的原因。
//下面代码在three.module.js
if ( _this.sortObjects === true ) {
currentRenderList.sort( _opaqueSort, _transparentSort );
}
在threejs的render函数中会对渲染对象进行排序,就是上面的sort函数,具体实现在下面
function sort( customOpaqueSort, customTransparentSort ) {
if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable );
if ( transmissive.length > 1 ) transmissive.sort( customTransparentSort || reversePainterSortStable );
if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable );
}
我们在这里暂时只需要关注opaque.sort,customOpaqueSort是自定义的排序函数,painterSortStable是threejs内置的排序函数。由于我并没有指定customOpaqueSort,因此执行的是painterSortStable。
painterSortStable源码如下
function painterSortStable( a, b ) {
if ( a.groupOrder !== b.groupOrder ) {
return a.groupOrder - b.groupOrder;
} else if ( a.renderOrder !== b.renderOrder ) {
return a.renderOrder - b.renderOrder;
} else if ( a.material.id !== b.material.id ) {
return a.material.id - b.material.id;
} else if ( a.z !== b.z ) {
return a.z - b.z;
} else {
return a.id - b.id;
}
}
看到这里就都明白了,解释了前面的现象。为什么改了renderorder之后mesh1就显示在上面,因为mesh1的renderorder大于mesh2的renderorder,因此被放到了renderlist后面,后渲染。
另外也解释了另外一个问题,为什么在第二个代码块中mesh1后加入场景,但是还是先绘制mesh2。其实是mesh2的material.id大于mesh1的material.id,并且判断material.id的优先级高于mesh.id。(但是我不知道为什么要这样安排)。