react-three-fiber

Objects and properties

Table of Contents

You can use Threejs's entire object catalogue and all properties. When in doubt, always consult the docs.

You could lay out an object like this:

<mesh
visible
userData={{ hello: "world" }}
position={new THREE.Vector3(1, 2, 3)}
rotation={new THREE.Euler(Math.PI / 2, 0, 0)}
geometry={new THREE.SphereGeometry(1, 16, 16)}
material={
new THREE.MeshBasicMaterial({
color: new THREE.Color("hotpink"),
transparent: true,
})
}
/>

The problem is that all of these properties will always be re-created. Instead, you should define properties declaratively.

<mesh
visible
userData={{ hello: "world" }}
position={[1, 2, 3]}
rotation={[Math.PI / 2, 0, 0]}
>
<sphereGeometry attach="geometry" args={[1, 16, 16]} />
<meshStandardMaterial attach="material" color="hotpink" transparent />
</mesh>

Shortcuts (set)

All properties whose underlying object has a .set() method can directly receive the same arguments that set would otherwise take. For example THREE.Color.set can take a color string, so instead of color={new THREE.Color('hotpink')} you can simply write color="hotpink". Some set methods take multiple arguments, for instance THREE.Vector3, give it an array in that case position={[100, 0, 0]}.

Dealing with non-Object3D's

You can put non-Object3D primitives (geometries, materials, etc) into the render tree as well so that they become managed and reactive. They take the same properties they normally would, constructor arguments are passed as an array via args. If args change, later on, the object gets re-constructed from scratch! Using the attach property objects bind to their parent and are taken off once they unmount.

You can nest primitive objects, too:

<mesh>
<meshBasicMaterial attach="material">
<texture attach="map" image={img} onUpdate={self => img && (self.needsUpdate = true)} />

Sometimes attaching isn't enough. For example, the following example attaches effects to an array called "passes" of the parent effectComposer. Note the use of attachArray which adds the object to the target array and takes it out on unmount:

<effectComposer>
<renderPass attachArray="passes" scene={scene} camera={camera} />
<glitchPass attachArray="passes" renderToScreen />

You can also attach to named parent properties using attachObject={[target, name]}, which adds the object and takes it out on unmount. The following adds a buffer-attribute to parent.attributes.position.

<bufferGeometry attach="geometry">
<bufferAttribute attachObject={['attributes', 'position']} count={v.length / 3} array={v} itemSize={3} />

Piercing into nested properties

If you want to reach into nested attributes (for instance: mesh.rotation.x), just use dash-case.

<mesh
rotation-x={1}
material-uniforms-resolution-value={[1 / size.width, 1 / size.height]}
/>

Putting already existing objects into the scene-graph

You can use the primitive placeholder for that. You can still give it properties or attach nodes to it. Never add the same object multiples times, this is not allowed in Threejs!

const mesh = useMemo(() => new THREE.Mesh(), []);
return <primitive object={mesh} position={[0, 0, 0]} />;

Using 3rd-party objects declaratively

The extend function extends three-fibers catalogue of JSX elements.

import { extend } from 'react-three-fiber'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { TransformControls } from 'three/examples/jsm/controls/TransformControls'
extend({ OrbitControls, TransformControls })
// ...
return (
<>
<orbitControls />
<transformControls />
Edit this page on GitHub