Three.js需求:让始终渲染的网格遮挡区域显示不同颜色
实现带遮挡变色效果的始终可见网格(Three.js 着色器方案)
核心思路是手动在片元着色器中进行深度测试:通过渲染器生成的场景深度纹理,对比当前网格片元与场景中其他物体的深度值,判断是否被遮挡,进而切换显示颜色。相比逐顶点射线检测,这种片元级方案效率更高,且能精确控制每个像素的颜色。
步骤1:配置渲染器生成深度纹理
首先需要让Three.js渲染器输出场景的深度纹理,后续着色器将通过这个纹理获取其他物体的深度信息:
const renderer = new THREE.WebGLRenderer(); // 开启必要的渲染配置 renderer.shadowMap.enabled = true; renderer.outputEncoding = THREE.sRGBEncoding; // 创建并绑定深度纹理 renderer.depthTexture = new THREE.DepthTexture(); renderer.depthTexture.format = THREE.DepthFormat; renderer.depthTexture.type = THREE.UnsignedIntType;
步骤2:编写自定义着色器材质
创建包含深度测试逻辑的着色器,顶点着色器负责传递必要的坐标信息,片元着色器完成深度对比和颜色切换:
顶点着色器
varying vec4 vScreenPosition; varying vec3 vWorldPosition; void main() { vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz; vScreenPosition = projectionMatrix * modelViewMatrix * vec4(position, 1.0); gl_Position = vScreenPosition; }
片元着色器
uniform sampler2D depthTexture; uniform vec3 visibleColor; uniform vec3 occludedColor; varying vec4 vScreenPosition; void main() { // 将裁剪空间坐标转换为NDC(归一化设备坐标) vec2 ndc = (vScreenPosition.xy / vScreenPosition.w) * 0.5 + 0.5; // 采样深度纹理,获取场景中该位置的深度值 float sceneDepth = texture2D(depthTexture, ndc).r; // 获取当前片元的深度值(裁剪空间w分量转换) float currentDepth = vScreenPosition.z / vScreenPosition.w; currentDepth = currentDepth * 0.5 + 0.5; // 转换为[0,1]范围 // 深度对比:如果当前片元深度大于场景深度,说明被遮挡 vec3 finalColor = (currentDepth > sceneDepth + 0.001) ? occludedColor : visibleColor; gl_FragColor = vec4(finalColor, 1.0); }
步骤3:创建网格并应用材质
保持你原本的depthTest=false和renderOrder=999设置,同时将深度纹理传入着色器uniform:
const geometry = new THREE.PlaneGeometry(5, 5); const material = new THREE.ShaderMaterial({ uniforms: { depthTexture: { value: renderer.depthTexture }, visibleColor: { value: new THREE.Color(0x00ff00) }, // 未遮挡颜色 occludedColor: { value: new THREE.Color(0x9933ff) } // 遮挡区域颜色 }, vertexShader: /* 上述顶点着色器代码 */, fragmentShader: /* 上述片元着色器代码 */, depthTest: false, renderOrder: 999 }); const mesh = new THREE.Mesh(geometry, material); scene.add(mesh);
关键细节说明
- 深度对比时添加了
+0.001的偏移量,是为了避免因浮点精度问题导致的z-fighting(深度冲突)。 - 深度纹理存储的是非线性深度值,这里通过裁剪空间的
z/w转换为线性深度进行对比,结果更准确。 - 该方案是片元级检测,能精确到每个像素,不会出现顶点检测带来的三角区域颜色断层问题。
内容的提问来源于stack exchange,提问作者z3db0y
相关产品推荐
相关产品推荐

