threejs的渲染顺序

threejs的渲染顺序有时候会对场景成像效果产生严重的影响。这一切的源头都来自于opengl的一种深度优化的工作原理。opengl会对需要渲染的对象做深度探测,也就是所谓的depthTest。当它发现需要渲染的部分被距离摄像头更近的对象遮挡住的时候,就会不再对其进行渲染。这种机制,本能的减少了gpu的工作量,优化了渲染性能。为了更好的利用这个特性,threejs会对需要渲染的非透明对象进行一次按距离摄像头从近到远的排序(近远的判断是根据object的boundingSphere属性)。如此,距离摄像头越近的对象就会越被先渲染,距离摄像头越远的对象会被后渲染,这样就能更快发现后面的对象的哪些个点会被遮住,从而避免对该点的渲染计算。然而,对于透明对象(transparent === true),threejs会按照距离摄像头从远到近的顺序来进行渲染,这样就能避免距离摄像头远的透明物体被因为depthTest的机制而取消渲染。

还有一点,就是透明的物体都是渲染在非透明的物体之后。这样做的原因无它,也就是想要避免因depthTest机制的存在而导致放在透明物体后面的非透明物体没有被渲染。

那么问题来了,如果两个对象距离摄像头的距离一样呢?这确实就是很多图像显示的罪恶之源。threejs就会不知道先渲染哪个,这会导致偶发性的z-fighting。在一些个别或者任何的摄像头位置,一些像素点显示的颜色不断的在两个对象间切换,甚至是有些对象出现可视与不可视之间不断的跳变。像这种情况,通常的解决方法,有三种。第一,关闭某个对象的depthTest, 让它能无视渲染顺序,从而确保其会被渲染,而不会因为depthTest的存在而变得不可见。第二,关闭某个对象的depthWrite,让该对象的的数据不会被写入gpu的深度缓存中,从而,其他对象在做depthTest的时候,就不会发现它挡在了前面。第三,人为的设定对象的渲染顺序。每个threejs对象都会有一个renderOrder属性,我们可以人为地配置对象A的renderOrder小于B的renderOrder,这样,就算A按照前文的机制因该渲染在B之后,但由于renderOrder的原因,能而改变此规则,让A渲染在B之前。

发表评论

邮箱地址不会被公开。 必填项已用*标注