在Three.js中,常常会遇到一个问题,那就是当场景中两个物体叠在一起,造成重叠部分不断闪烁。那么这是为什么呢
原因:
-
深度缓冲精度问题:
- 3D 图形应用通常依赖深度缓冲区(Depth Buffer)来判断哪个物体在前,哪个物体在后。深度缓冲区的精度在远离相机的物体上会变得不够准确,导致深度值的冲突。
- 当两个物体的表面距离相近时,如果二者的 Z 值差异小于缓冲区的精度,就会产生闪烁。通俗讲当场景中的两个模型在同一个像素生成的渲染结果对应到一个相同的深度值时,渲染器就不知道该使用哪个模型的渲染结果了,或者说,不知道哪个面在前,哪个面在后,于是便开始“胡作非为”,这次让这个面在前面,下次让那个面在前面,于是模型的重叠部位便不停的闪烁起来。
-
重叠几何体:
- 如果两个或多个物体几何体在 Z 方向上的高度重叠,或者如果它们的表面非常接近,这种重叠会导致 Z-fighting,因为 GPU 不知道渲染哪个物体。
-
使用了透明材质:
- 使用透明材质时,渲染顺序变得更加复杂。透明物体的渲染通常依赖于它们在深度缓冲中的顺序,可能会导致冲突和闪烁。
-
近裁剪和远裁剪平面设置不当:
- 如果相机的近裁剪平面和远裁剪平面设置不合理,可能会导致深度精度问题。例如,近远裁剪平面之间的距离过大或近裁剪平面过小,都会增加 Z-fighting 的可能性
解决方案:
- 增加深度缓冲区精度:通过调整相机的近裁剪和远裁剪平面来提高深度缓冲的精度。可以尝试将近裁剪平面设置得稍微远一些,远裁剪平面设置得稍微近一些。例如
const camera = new THREE.PerspectiveCamera(fov, aspect, 0.1, 1000); ```
-
使用不同的材质参数:使用 Polygon Offset 来调整物体渲染排序。例如,在材质中设置
polygonOffset
:material.polygonOffset = true; material.polygonOffsetFactor = 1; // 正值向前偏移 material.polygonOffsetUnits = 1; // 偏移单位 ```
- 使用透明度排序:对于透明物体,确保它们按照从远到近的顺序进行渲染。这可以通过在渲染时启用 depthWrite:
material.depthWrite = true; // 启用深度写入 ```
-
设置渲染顺序(renderOrder):给模型网格等加到场景的东西加上
renderOrder
。代码如下:this.mesh.renderOrder = this.addOrder() || 0; this.renderOrder = 100; addOrder() { this.renderOrder += 10; return this.renderOrder; }
5. 对数深度缓冲区(logarithmicDepthBuffer)在创建WebGLRendere. 时设置 logarithmicDepthBuffer: true
。代码如下:
let renderer = new THREE.WebGLRenderer({ logarithmicDepthBuffer: true });
深度测试属性.depthTest
关于深度测试属性.depthTest
的具体介绍可以查看Threejs官方文档的基类Material
。
当你通过Threejs的点线网格等材质类创建材质对象的时候,默认情况下,渲染的时候材质对象对应的模型都会进行深度测试。
.depthTest
属性值默认true
,设置为false
可以关闭深度测试.
深度写入属性.depthWrite
渲染此材质的时候,是否对深度缓冲区有任何的影响. 默认 true.阻止深度值写入,这样深度缓冲区中对应位置存的是别的材质的深度信息
在绘制2D叠加时,为了将多个在一起的事物分层而不创建z-index伪像,禁用深度写入会很有用。
颜色缓冲区写入属性.colorWrite
是否渲染材质的颜色. 该属性可以和网格模型Mesh的渲染顺序属性renderOrder结合使用来创建遮挡其它对象的不可见对象. 默认true.