Search code examples
reactjsthree.jscomponentsreact-propsreact-three-fiber

@react-three/fiber Reusable 3D Text Component


Fairly new to programming here (recently completed a code bootcamp but teaching myself about Three.js). I'm trying to create a reusable function using @react-three/fiber but I think the problem might be coming from basic React. Can anyone see why my props of {text, coordinates} may not be working as intended? I just want to be able to edit the text and the position of the text each time the function is used, so in effect I'd have have multiple text objects on my page that I can control separately. I have no errors however the text object does not show on the app when rendering, although it is listed as a component when I inspect the site. Anyone got any ideas? I'm hoping it's something simple. :)

This is the code for the reusable text component.

export default function Text3D({text, coordinates}){
  const font = new FontLoader().parse(Montserrat);

  return (
    <mesh position={[coordinates]} visible>
      <textGeometry attach='geometry'args={[{text}, {font, size: 5, height: 0.1}]} />
      <meshStandardMaterial attach='material' color="white" />
     </mesh>
  )};

And this is an example of another component I'm trying to use the text component in.

export default function ETPlanet(){
    const eTPlanet = useLoader(THREE.TextureLoader, saturnPlanetTexture);
    const eTPlanetRing = useLoader(THREE.TextureLoader, saturnRingTexture);
    const ref = useRef(null);
    const planetRef = useRef(null);
    useFrame(() => {
        ref.current.rotation.z += 0.01;
        planetRef.current.rotation.y -= 0.005;
    }); /* ref and useFrame lines are to create a reference and then allow the saturn ring to spin every frame.*/

    return(
        <>
            <mesh ref={planetRef} position={[-15, -2, 4]}>{/* Creates shape and sets position using x, y, z co-ordinates.*/}
                <sphereGeometry args={ [0.85, 32, 32] } />{/*Sets shape as a sphere using three.js and specifies dimensions.*/}
                <meshStandardMaterial map={eTPlanet} />{/*Sets material type from three.js and maps the texture image to surface of the shape.*/}
            </mesh>
            <mesh position={[-15, -2, 4]} rotation={[1.3, 0, 0]} ref={ref} castShadow visible>{/* Creates shape and sets position using x, y, z co-ordinates. Also makes ring more horizontal and cast a shadow.*/}
                <ringBufferGeometry args={ [1.1, 1.5, 64] } />
                <meshStandardMaterial map={eTPlanetRing} side={THREE.DoubleSide} transparent={true} opacity={1} />
            </mesh>
            <Text3D text={'Experience Timeline'} coordinates={[0, 0, 0]}/>
        </>
    )
}

Solution

  • I'm not familiar with react three fiber but it appears you have coordinates as array (object) and text as string, you should pass it like this:

    export default function Text3D({text, coordinates}){
      const font = new FontLoader().parse(Montserrat);
    
      return (
        <mesh position={coordinates} visible>
          <textGeometry attach='geometry'args={[text, {font, size: 5, height: 0.1}]} />
          <meshStandardMaterial attach='material' color="white" />
        </mesh>
    )};
    

    Basically, what you did was try to "nest" the array (for example [[1, 3, 4]]) since coordinates is an array.

    You also tried to "nest" the text into an object, by writing it as args={[{text}, {font, size: 5, height: 0.1}]}, it should be args={[text, {font, size: 5, height: 0.1}]} instead.

    Hope that helps.