How update uniform value in react-three-fiber

Hello people,
I want to change color of some shaders when the theme of the website change (Light and Dark). I read how to that but I am not sure if I implemented it correctly.
Unfortunately, I can’t get the shader to work with Drei, so I’m using a “manual implementation”.
This is my functional component where I defined on of my 3d object.

export default function Sphere() {
  const material = useRef<ShaderMaterial>(null!);

  const [texture1, texture2] = useTexture(....);

  const colors = useThemeColors();

  const uniforms = useMemo(() => ({
    uniforms: {
      uMap: {
        value: texture1,
      },
      tPerlin: {
        value: texture2,
      },
      uColor: {
        value: null,
      },
      uColorLight: {
        value: null,
      },
    }
  }), [tex, perlinTex]);

  useEffect(() => {
    if (!material.current) {
      return;
    }

    material.current.uniforms.uColor.value = colors.sphere.uColor;
    material.current.uniforms.uColorLight.value = colors.sphere.uColorLight;
  }, [colors.sphere.uColor, colors.sphere.uColorLight]);
  
  return (
    <group>
      <mesh rotation={[0, -Math.PI / 2, 0]}>
        <sphereGeometry args={[100, 50, 50]} />
        <shaderMaterial
          ref={material}
          {...uniforms}
          vertexShader={vertex}
          fragmentShader={fragment}
        />
      </mesh>
    </group>
  );
};

With const colors = useThemeColors(); I am getting the right color based on the actual theme selected. It is just an object with some Color defined.
I read about “stable reference” regard uniforms, so does it make sense to use null for uColor and uColorLight? I do that because if I use color returned by the useThemeColors in the useMemo it does not works (colors do not update upon switch theme).
To update color and so uniforms useEffect()` is the way?

Thanks in advance for your answers.

Possibly when you send your color to the shader, it is not in the format it expects. It might need to be a vec3 or vec4. I can’t see your shader code to be sure.

In this example below, I convert the html color into a normalised array of r,g,b

I.e., #112233 becomes [ 0.06640625, 0.1328125, 0.19921875 ]

1 Like

Hello @seanwasere, thanks for the answer.
The format is correct. The shader want a uniform vec3 color; and I provide a Color (new Color()).
My issue is: to change the color of the mesh according to a switch of the theme, I need to set the ref into a useEffect()?
Also, the initialization of uColor to null is required? Because if I use colors.sphere.uColor when I switch theme the color does not change (instead if I initialize to null when I switch theme it works as expected).
In the example shader, you also initialize color to null. Why is required? To a stable reference?

Thank you so much!