You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Three.js ShaderMaterial显示异常:旋转相机时材质不跟随移动

问题分析与解决方案

你遇到的核心问题是片元着色器依赖屏幕坐标gl_FragCoord计算颜色,这会让渲染效果和模型的空间位置、相机视角完全无关——颜色只和像素在屏幕上的位置有关,所以旋转相机时,模型上的颜色不会跟着模型移动,看起来就像材质“固定”在屏幕上了。另外你的顶点着色器还有一个小错误,会导致UV变量无法正确传递到片元着色器。

具体错误点

  1. 顶点着色器的变量赋值错误:
    你在顶点着色器里写了vec2 vUv = uv;,这是重新声明了一个局部的vUv变量,而不是给全局的varying vec2 vUv;赋值。这会导致片元着色器里的vUv是未初始化的垃圾值。

  2. 片元着色器用屏幕坐标而非模型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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:48:28