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

鼠标移动时更新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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 23:20:34