Three.js ShaderMaterial显示异常:旋转相机时材质不跟随移动
问题分析与解决方案
你遇到的核心问题是片元着色器依赖屏幕坐标gl_FragCoord计算颜色,这会让渲染效果和模型的空间位置、相机视角完全无关——颜色只和像素在屏幕上的位置有关,所以旋转相机时,模型上的颜色不会跟着模型移动,看起来就像材质“固定”在屏幕上了。另外你的顶点着色器还有一个小错误,会导致UV变量无法正确传递到片元着色器。
具体错误点
顶点着色器的变量赋值错误:
你在顶点着色器里写了vec2 vUv = uv;,这是重新声明了一个局部的vUv变量,而不是给全局的varying vec2 vUv;赋值。这会导致片元着色器里的vUv是未初始化的垃圾值。片元着色器用屏幕坐标而非模型UV:
使用gl_FragCoord意味着颜色计算是基于屏幕像素位置的,不管模型怎么动、相机怎么转,屏幕上同一个位置的像素颜色都是固定的,自然不会跟随模型移动。
修正后的代码
顶点着色器(修复UV赋值)
<script type="x-shader/x-vertex" id="vertexShader"> varying vec2 vUv; void main() { // 去掉局部变量声明,直接给全局varying变量赋值 vUv = uv; vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0); gl_Position = projectionMatrix * modelViewPosition; } </script>
片元着色器(改用模型UV计算颜色)
这里我改成基于模型UV的渐变效果,你可以根据需求调整逻辑,核心是使用vUv而非gl_FragCoord:
<script type="x-shader/x-fragment" id="fragmentShader" > precision mediump float; // 不再需要resolution uniform,因为我们用模型UV而非屏幕坐标 varying vec2 vUv; void main(void) { // 使用模型UV坐标计算颜色,这样颜色会绑定在模型表面 vec2 p = -1.0 + 2.0 * vUv; float v = p.x; vec3 col = vec3(0.01 * max(0.0, 1.0), 0.1 * max(0.0, p.x), 0.0) / abs(v * 2.0); float op = 0.01/abs(v * 2.0); gl_FragColor = vec4(col, op); } </script>
JavaScript部分(移除无用的resolution uniform)
因为现在不需要屏幕分辨率了,所以可以去掉对应的uniform:
var geometry = new THREE.BoxBufferGeometry( 2,2,2 ); var shaderMat = new THREE.ShaderMaterial({ // 移除resolution uniform vertexShader: document.getElementById( 'vertexShader' ).textContent, fragmentShader: document.getElementById( 'fragmentShader' ).textContent }); shaderMat.side = THREE.DoubleSide; // 建议用THREE的常量代替魔法数字2 mesh = new THREE.Mesh( geometry, shaderMat ); scene.add( mesh );
效果说明
修改后,颜色计算会基于模型自身的UV坐标,所以当你旋转相机或者移动模型时,材质效果会正确跟随模型表面变化,不会再出现“固定在屏幕上”的异常情况。
内容的提问来源于stack exchange,提问作者chen
相关产品推荐
相关产品推荐

