drei icon indicating copy to clipboard operation
drei copied to clipboard

The reason for the very low performance of R3F with instances ?

Open raptyk opened this issue 7 months ago • 0 comments

I'm experiencing a significant performance drop when using R3F/drei Instances compared to vanilla JavaScript (UPDATE: and pure R3F instancedMesh) for rendering multiple instances of BoxGeometry. Here's the situation:

When I generate multiple instances of BoxGeometry directly in JavaScript (UPDATE: or in pure R3F), I get a high frame rate and no performance issues. However, when I implement the identical code as a component using R3F/drei, I observe a drastic FPS drop (as shown in the attached screenshot - high CPU usage!).

Can anyone suggest what might be causing this performance discrepancy? Is this a normal situation? Does R3F/drei typically cause such a significant performance overhead?

Any insights or suggestions would be greatly appreciated. If you need any additional information or code snippets, please let me know. Thank you in advance for your help!

Good performance:

    React.useEffect(() => {
        const geometry = new THREE.BoxGeometry(1, 1, 0.1);
        const material = new THREE.MeshBasicMaterial({ color: 'blue' });

        const trees = new THREE.InstancedMesh(geometry, material, visibleSquares.length);

        for (let i = 0; i < trees.count; i++) {
            const [x, y, z] = visibleSquares[i];
            trees.setMatrixAt(i, new THREE.Matrix4().makeRotationX(Math.PI / 2).setPosition(x + 0.5, 0.01, y + 0.5));
        }

        trees.instanceMatrix.needsUpdate = true;

        scene.add(trees);

        return () => {
            scene.remove(trees);
            trees.dispose();
            geometry.dispose();
            material.dispose();
        };
    }, [visibleSquares, scene]);

Same code in R3F/drei but very low FPS and high CPU usage:

import { Instance, Instances } from '@react-three/drei';

(...)

return (
        <Instances limit={visibleSquares.length}>
            <boxGeometry args={[1, 1, 0.01]} />
            <meshBasicMaterial color="red" />

            {visibleSquares.map(([x, y], index) => (
                <Instance
                    key={index}
                    position={[x + 0.5, 0.01, y + 0.5]}
                    rotation={[Math.PI / 2, 0, 0]}
                />
            ))}
        </Instances>
    );

UPDATE: pure R3F version - performance ok:

    const dummyObj = new Object3D();
    // const geom = useMemo(() => new BoxGeometry(1, 1, 0.1), [])
    // const mat = useMemo(() => new MeshBasicMaterial({ color: "red" }), [])
    const Boxes: React.FC = () => {
        const ref = useRef<InstancedMesh>(null);

        useLayoutEffect(() => {
            if (ref.current) {

                for (let i = 0; i < visibleSquares.length; i++) {
                    const [x, y] = visibleSquares[i];
                    dummyObj.rotation.set(Math.PI / 2, 0, 0);
                    dummyObj.position.set(x + 0.5, 0.01, y + 0.5);
                    dummyObj.updateMatrix();

                    ref.current.setMatrixAt(i, dummyObj.matrix);
                }

                ref.current.instanceMatrix.needsUpdate = true;
            }
        }, [visibleSquares]);

        return (
            <instancedMesh ref={ref} args={[undefined, undefined, visibleSquares.length]}>
                <boxGeometry args={[1, 1, 0.1]} />
                <meshBasicMaterial color={"green"} />
            </instancedMesh>
        );
    };

    return <Boxes />;

chrome_BOWdWCpLjN

raptyk avatar Jul 18 '24 09:07 raptyk