Christian Llanos
Christian Llanos

Reputation: 91

How to dynamically change a mesh color with React and Three.js

I know this is a trivial question but I assure you I've been trying to solve this for several hours. The color prop is a string (e.g '#f56d3d') and it should change the mesh material color. I'm using useEffect to initialize the scene and I've tried to use another to change the color

function Scene({ color, shape }) {
  const cubeRef = useRef(null);

  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
  const renderer = new THREE.WebGLRenderer({ alpha: true });
  const geometry = new THREE.BoxGeometry();
  const material = new THREE.MeshBasicMaterial({ color });
  const cube = new THREE.Mesh(geometry, material);

  const animate = () => {
    requestAnimationFrame(animate);
    cube.material.color.setStyle(color);
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    renderer.render(scene, camera);
  };

  useEffect(() => {
    renderer.setSize(window.innerWidth,  window.innerHeight);
    cubeRef.current.appendChild(renderer.domElement);
    scene.add(cube);
    camera.position.z = 5;

    animate();
  },[]);

  return (
    <div ref={cubeRef}>
    </div>
  )
}

export default Scene

What comes to my mind is a way to let know the renderer that the cube inside the scene has changed. What I've tried so far is:

Thanks

Upvotes: 1

Views: 3036

Answers (1)

noobprogrammer
noobprogrammer

Reputation: 241

If you dont mind creating a new object then you can rearrange the variables in the useEffect like this:

  const cubeRef = useRef(null);
  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
  const renderer = new THREE.WebGLRenderer({ alpha: true });
  const geometry = new THREE.BoxGeometry();
  let cube, material;
  
  const animate = () => {
    requestAnimationFrame(animate);
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    renderer.render(scene, camera);
  };

  useEffect(() => {
    material = new THREE.MeshBasicMaterial({color});
    cube = new THREE.Mesh(geometry, material);
    renderer.setSize(window.innerWidth,  window.innerHeight);
    cubeRef.current.innerHTML = '';
    cubeRef.current.appendChild(renderer.domElement);
    scene.add(cube);
    camera.position.z = 5;
    animate();
  }, [color])

Also you might need to save the previous positioning or rotation somewhere.

Upvotes: 1

Related Questions