Search code examples
reactjsthree.jsreact-three-fiber

Threejs Decal not showing


I'm trying to create a decal on my mesh using three.js and react-three-fiber. I believe I correctly set up the mesh and material but for some reason the decal is not showing up on the canvas.

enter image description here

This is the parent component that holds both the model, backplate, and decal.

<Canvas camera={{ position: [0, 0, 2], fov: 70 }}>
    <Lights />
    <Suspense fallback={null}>
        <Model flipped={flipped} returnMesh={setMesh} />
        <Decal mesh={mesh} />
        <Back />
    </Suspense>
</Canvas>

This is part of the component where I create the t-shirt mesh from a .glb file. The mesh is passed back to the parent and then to the Decal component.

let geometry, material, mesh;

// GEOMETRY
geometry = useGLTF("/tshirt.glb").nodes.tshirt.geometry;

useEffect(() => {
    material = new THREE.MeshStandardMaterial({ color: "orange" });
    mesh = new THREE.Mesh(geometry, material);
}, []);

This is how I am trying to set up the decal mesh:

extend({ DecalGeometry });

const Decal = ({ mesh }) => {
    let decalGeometry;

    useEffect(() => {
        if (mesh) {
            decalGeometry = new DecalGeometry(
                mesh,
                new THREE.Vector3(0, 0, 0),
                new THREE.Euler(0, 0, -1, "XYZ"),
                new THREE.Vector3(0.5, 0.5, 0.5)
            );
        }
    }, [mesh]);

    return (
        <mesh geometry={decalGeometry}>
            <meshStandardMaterial attach="material" color="red" />
        </mesh>
    );
};

I am getting no errors, the decal just doesn't appear. I hope someone has some insight. There isn't a lot about Decal Geometry with threejs out there, even less specific to r3f.


Solution

  • You are using decalGeometry before it is assigned. This is because callbacks given to useEffect are executed after Decal is called.

    Suggested fix: use the useMemo hook.

    e.g.

    extend({ DecalGeometry });
    
    const Decal = ({ mesh }) => {
        const decalGeometry = useMemo(() => {
            return new DecalGeometry(
                mesh,
                new THREE.Vector3(0, 0, 0),
                new THREE.Euler(0, 0, -1, "XYZ"),
                new THREE.Vector3(0.5, 0.5, 0.5)
            );
        }, [mesh]);
    
        return (
            <mesh geometry={decalGeometry}>
                <meshStandardMaterial attach="material" color="red" />
            </mesh>
        );
    };