How do you set uTime inside useFrame in R3F for a shader?

ive been trying to set uTime from my uniforms for my shader but i keep getting this typeset error

HandTOPb.jsx?t=1690643611434:37 Uncaught TypeError: Cannot set properties of undefined (setting 'uTime')

here is my code and what i’ve tried from what i’ve looked up :

function TopHand(props) {
  const { nodes, materials, fragmentShader, vertexShader } = useGLTF(
    "./modelsGLTF/handTOPb/handTOPb.gltf"
  );
  const ref = useRef();
  useFrame(({ clock, mouse }) => {
    ref.current.uniforms.uTime = clock.getElapsedTime();
  });
  const uniforms = {
    uTime: { value: 0 },
    coral: { type: "t", value: new THREE.TextureLoader().load(coral) },
    iResolution: { value: new THREE.Vector3() },
  };

  return (
    <group
      {...props}
      dispose={null}
      position={[-7, -22, 8]}
      rotation={[4, 0, 2]}
    >
      <mesh
        scale={[1, 1, 1]}
        geometry={nodes.hand.geometry}
        material={nodes.hand.material}
        rotation={[Math.PI / 2, 0, 0]}
        ref={ref}
      >
        <shaderMaterial
          uniforms={uniforms}
          fragmentShader={fragmentShader}
          vertexShader={vertexShader}
          transparent={true}
        />
      </mesh>
    </group>
  );
}
1 Like

you’re trying to change uniforms on a type of mesh, that doesn’t exist… have you tried modifying the uniforms of the material attached to the mesh instead eg.

  useFrame(({ clock, mouse }) => {
    ref.current.material.uniforms.uTime = clock.getElapsedTime();
  });
1 Like

cheers thnx ur a big help i thought i tried adding .material earlier but i think something else that i fixed was stopping that from working so i didn’t bother to try it again :thinking: a small quick question to add on but am i using the correct texture loader should i use ‘useTexture’ from react three drei? Cause i i cant seem to see the texture in my model and nothing has changed in my shader since i moved to R3F from normal three js if not it be something else im guessing but thnx alot again otherwise :pray: :+1:

Hey, np, yes ifaik it’s best to use useTexture() if using r3f as it’s made to preload textures before trying to render them which is likely the issue

1 Like

Also, drei shader material creates auto setter getters ThreeJS Journey Portal - CodeSandbox

Ps nothing imo wrong with textureloader it’s probably just a as wrong path, but useTexture integrates the component into suspense and preloads

2 Likes

cheers thnx a million :+1:

Oh you can useRef() on materials that’s cool, is that only for shader materials? when you say “creates auto setter getters”?

uTime is an Uniform object. You have to change its value, but not uTime itself

useFrame(({ clock }) => {
    if (ref.current) {
      ref.current.uniforms.uTime.value = clock.elapsedTime
    }
  })

You can put refs on anything, you will get the underlying object. The helper, shaderMaterial(…) creates auto setter/getters for all uniforms so you don’t have to write these long paths, then it’s just shaderRef.current.uTime = foo

1 Like