ThreeJS启用depthWrite后Points出现黑色矩形背景问题求助
Three.js Points启用深度写入后出现黑色矩形背景的问题及解决
问题背景
我在Three.js场景中使用Points组件,核心代码如下:
<points ref={gPoints} position={position}> <bufferGeometry attach="geometry"> <bufferAttribute attach="attributes-position" count={positions.length / 3} array={positions} itemSize={3} usage={THREE.DynamicDrawUsage} /> // ... 其他属性 </bufferGeometry> <shaderMaterial depthWrite={false} depthTest={false} fragmentShader={fragmentShader} vertexShader={vertexShader} uniforms={uniforms} blending={THREE.AdditiveBlending} /> </points>
通过片元着色器实现点的模糊效果:
uniform float uResolutionWidth; uniform float uResolutionHeight; varying vec3 vColor; varying vec4 vRealPosition; varying float vDistance; void main() { float d = length(gl_PointCoord.xy - 0.5); float alpha = smoothstep(0.5, 0.15, d); gl_FragColor = vec4(vColor, alpha); }
顶点着色器中通过以下逻辑设置vColor:
#define PI 3.14159265358979323846 uniform float uTime; uniform float uRadius; attribute float pointSizes; attribute float randomX; attribute float randomY; attribute float randomZ; attribute float randomW; varying vec3 vColor; void main() { // 设置顶点颜色 float d = length(abs(position) / vec3(96.0, 22.0, 96.0)); d = clamp(d, 0.0, 1.0); float d2 = abs(position.y); vColor = mix(vec3(244.0, 131.0, 12.0), vec3(82.0, 27.0, 255.0), d2/22.0) / 255.; }
关闭depthWrite和depthTest时,点显示正常(呈现平滑的模糊圆形,无黑色背景);但启用这两个属性后,每个点出现黑色矩形背景。我尝试丢弃alpha值过低的片段:
uniform float uResolutionWidth; uniform float uResolutionHeight; varying vec3 vColor; varying vec4 vRealPosition; varying float vDistance; void main() { float d = length(gl_PointCoord.xy - 0.5); float alpha = smoothstep(0.5, 0.15, d); // 丢弃完全透明的片段 if (alpha < 0.001) { discard; } gl_FragColor = vec4(vColor * alpha, alpha); }
但效果仍不理想(黑色矩形边缘仍可见)。
成因分析
- 深度缓冲区写入逻辑:启用
depthWrite时,WebGL会将每个片元的深度值写入深度缓冲区,无论该片元的alpha值是否为0。Points的每个点本质是矩形面片,即使通过alpha通道让边缘透明,这些透明片元的深度值依然会被写入,后续绘制的物体或场景背景会被这些深度值挡住,从而显示黑色矩形。 discard阈值过高:仅丢弃完全透明(alpha < 0.001)的片元,边缘半透明的片元仍会写入深度值,导致黑色痕迹残留。
解决方法
方法1:优化片元丢弃逻辑
降低丢弃阈值,确保所有非核心模糊区域的片元都被丢弃,避免无效深度写入:
uniform float uResolutionWidth; uniform float uResolutionHeight; varying vec3 vColor; varying vec4 vRealPosition; varying float vDistance; void main() { float d = length(gl_PointCoord.xy - 0.5); float alpha = smoothstep(0.5, 0.15, d); // 丢弃半透明及完全透明的片元,阈值可根据效果调整 if (alpha < 0.1) { discard; } gl_FragColor = vec4(vColor, alpha); }
方法2:使用alphaTest替代手动丢弃
在ShaderMaterial中启用alphaTest,让WebGL自动丢弃alpha值低于指定阈值的片元,效率更高且能彻底避免深度写入问题:
<shaderMaterial depthWrite={true} depthTest={true} fragmentShader={fragmentShader} vertexShader={vertexShader} uniforms={uniforms} blending={THREE.AdditiveBlending} alphaTest={0.1} // 阈值可根据效果调整 />
同时可移除片元着色器中的手动discard代码,保留原有alpha计算逻辑即可。
方法3:调整深度测试函数(补充方案)
如果需要保留AdditiveBlending和深度测试,可尝试将depthFunc设置为THREE.LessEqualDepth,缓解深度冲突问题:
<shaderMaterial depthWrite={true} depthTest={true} depthFunc={THREE.LessEqualDepth} fragmentShader={fragmentShader} vertexShader={vertexShader} uniforms={uniforms} blending={THREE.AdditiveBlending} />
内容的提问来源于stack exchange,提问作者user25766836
相关产品推荐
相关产品推荐

