在three.js中开启对数缓冲区,会导致shaderMaterial材质的渲染顺序问题,产生比较诡异的效果.
renderer关闭对数缓冲区的效果:
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
precision: 'highp',
logarithmicDepthBuffer: false // 设置对数深度缓冲区
})
绿色的为自定义的shaderMaterial材质,白色的是MeshBasicMaterial的材质,这是正常渲染的一个效果.
开启对数缓冲区的效果:
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
precision: 'highp',
logarithmicDepthBuffer: true// 设置对数深度缓冲区
})
就会产生不正常的渲染,具体就是绿色的材质比白色的材质更靠近相机,理论上应该是绿色会遮盖住白色的材质,然而开启对数缓冲区后,ShaderMaterial材质渲染循序会出现问题,导致优先显示了白色的MeshBasicMaterial材质
那么问题来了,既然会产生这样的问题,renderdr不开启对数缓冲区不就行了嘛。这就不得不提一下对数缓冲区的作用了,在Three.js中,Renderer的对数缓冲区(logarithmicDepthBuffer)是一项用于提高深度精度的技术。默认情况下,Three.js使用线性深度缓冲(linear depth buffer),但在某些场景中,线性深度缓冲可能导致深度精度不足,特别是在场景中包含大范围深度值时。
使用对数深度缓冲可以在远距离处提高深度精度,减少深度缓冲的精度变化。这对于渲染大型场景或有广泛深度变化的场景特别有用,因为它能够更均匀地分配深度精度,防止Z-fighting的精度问题。
那么开启对数缓冲区后,怎么解决shaderMaterial材质渲染顺序错误的问题呢?
解决的方法就是在定义ShaderMaterial时使用内部着色器块增强自定义着色器,具体如下:
const mat = new THREE.ShaderMaterial({
uniforms: {
baseColor: { value: new THREE.Vector3(0.7681511472425808, 0.9386857284565036, 0.9911020971136257) },
targetColor: { value: new THREE.Vector3(0.011612245176281512, 0.6724431569510133, 0.1499597898006365) },
height: { value: height || 0.15 }
},
side: THREE.DoubleSide,
transparent: true,
depthWrite: true,
depthTest: true,
vertexShader: [
'varying vec3 modelPos;',
'#include <common>', // 添加着色器快
'#include <logdepthbuf_pars_vertex>', // 添加的着色器快
'void main() {',
' modelPos = position;',
' gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
' #include <logdepthbuf_vertex>', // 添加的着色器快
'}'
].join('\n'),
fragmentShader: [
'#include <common>', // 添加的着色器快
'#include <logdepthbuf_pars_fragment>', // 添加的着色器快
'uniform vec3 baseColor;',
'uniform vec3 targetColor;',
'uniform float height;',
'varying vec3 modelPos;',
'void main() {',
' #include <logdepthbuf_fragment>', // 添加的着色器快
' gl_FragColor = vec4(targetColor.xyz, 1);', // (0.0 - modelPos.z/height)*(0.0 - modelPos.z/height)
' if(modelPos.z/height > 0.333 && modelPos.z/height < 0.666) {gl_FragColor = vec4(baseColor.xyz, 1);}',
' if(modelPos.z/height > 0.666) {gl_FragColor = vec4(targetColor.xyz, 1);}',
'}'
].join('\n')
})
有四个logdepthbuffer
块以及common
添加到代码中的块。问题就解决了。
three社区对这个问题的讨论,可以查看原帖shaderMaterial: render-order with logarithmicDepthBuffer is wrong