鼠标移动时更新WebGL uniform vec2报错,求解决方案
鼠标移动时更新WebGL uniform vec2报错:TypeError: Failed to execute 'uniform2fv' on 'WebGL2RenderingContext': Overload resolution failed
尝试在鼠标移动时更新uniform vec2变量,触发了如下错误:
TypeError: Failed to execute 'uniform2fv' on 'WebGL2RenderingContext': Overload resolution failed
相关代码
1. uniform引用对象初始化
const uniformRef = useRef({ uAlpha: 0, uOffset: { x: 0.0, y: 0.0 }, uTexture: imageTexture, });
2. 鼠标移动事件监听
useEffect(() => { document.addEventListener("mousemove", onMouseMove); return () => document.removeEventListener("mousemove", onMouseMove); }, [onMouseMove]);
3. 鼠标移动处理与uniform更新逻辑
const onMouseMove = useCallback((e: MouseEvent) => { if (!planeRef.current || planeRef.current === undefined) return; // 转换鼠标坐标到WebGL空间 let x = (e.clientX / window.innerWidth) * 2 - 1; let y = -(e.clientY / window.innerHeight) * 2 + 1; const position = new THREE.Vector3(x, y, 0); // 平滑更新平面位置 gsap.to(planeRef.current?.position, { duration: 1, x, y, ease: Power4.easeOut, onUpdate: () => onPositionUpdate(position), }); }, []); // 更新offset uniform const onPositionUpdate = (position: THREE.Vector3) => { if (planeRef.current) { let offset = planeRef.current.position .clone() .sub(position) .multiplyScalar(-0.25); gsap.to(uniformRef.current, { uOffset: { x: offset.x, y: offset.y }, duration: 1, ease: Power4.easeOut, }); } };
4. Shader材质初始化
const ColorShiftMaterial = shaderMaterial( { uTexture: new THREE.Texture(), uOffset: new THREE.Vector2(0.0, 0.0), uAlpha: 0, }, // 后续顶点/片元着色器代码... )
错误原因
这个报错的核心是WebGL的uniform2fv方法接收的参数类型不符合要求:
- 初始化Shader材质时,
uOffset用的是THREE.Vector2类型; - 但通过gsap更新
uniformRef.current.uOffset时,赋值的是普通JS对象{x: offset.x, y: offset.y},而非THREE.Vector2实例; - 当Three.js尝试把普通对象传给WebGL的
uniform2fv时,方法无法识别该类型,导致重载解析失败。
解决方法
方法1:保持uOffset为THREE.Vector2类型
修改onPositionUpdate中的gsap动画,直接更新THREE.Vector2的x/y属性,而非替换整个对象:
const onPositionUpdate = (position: THREE.Vector3) => { if (planeRef.current) { let offset = planeRef.current.position .clone() .sub(position) .multiplyScalar(-0.25); // 直接更新Vector2的x和y属性 gsap.to(uniformRef.current.uOffset, { x: offset.x, y: offset.y, duration: 1, ease: Power4.easeOut, }); } };
同时修正uniformRef的初始化,确保uOffset是THREE.Vector2实例:
const uniformRef = useRef({ uAlpha: 0, uOffset: new THREE.Vector2(0.0, 0.0), // 替换普通对象为Vector2 uTexture: imageTexture, });
方法2:传递数组格式给uniform
如果坚持使用普通对象,需要在更新时将其转为WebGL接受的数组格式[x, y],并手动同步到材质:
// 假设材质实例存储在materialRef中 const onPositionUpdate = (position: THREE.Vector3) => { if (planeRef.current) { let offset = planeRef.current.position .clone() .sub(position) .multiplyScalar(-0.25); gsap.to(uniformRef.current.uOffset, { x: offset.x, y: offset.y, duration: 1, ease: Power4.easeOut, onUpdate: () => { // 手动将对象转为数组更新到材质 materialRef.current.uOffset = [uniformRef.current.uOffset.x, uniformRef.current.uOffset.y]; } }); } };
额外注意
- 确认着色器中
uOffset的声明为uniform vec2 uOffset;,与材质中的类型匹配; - 若使用
shaderMaterial(如drei库提供的),它会自动处理uniform更新,但前提是你保持uniform的类型与初始化时一致。
内容的提问来源于stack exchange,提问作者teo goulois
相关产品推荐
相关产品推荐

