Your first scene
This guide will help you setup your first React Three Fiber scene and introduce you to its core concepts.
This tutorial will assume some React knowledge, and will be based on this starter codesandbox, so just fork it and follow along!
Setting up the Canvas
We'll start by importing the <Canvas />
component from react-three-fiber
and putting it in our React tree:
import { Canvas } from 'react-three-fiber'
function App() {
return (
<div id="canvas-container">
<Canvas />
</div>
)
}
export default App
The Canvas component does some important setup work behind the scenes:
- It sets up a Scene and a Camera, the basic building blocks necessary for rendering
- It automatically handles window resizing
- It renders our scene every frame
To actually render something in our scene, we'll add a mesh
component. In Fiber, every THREE.js object has an equivalent component:
const myMesh = new THREE.Mesh()
// is equivalent to
<mesh />
Note that the Canvas will be resized to fit the parent div, so you can control how big it is by just changing the width
and height
of #canvas-container
in your css.
Adding a Mesh
A Mesh
is a basic object in THREE.js, and it's used to hold the polygons and the material that are needed to represent the object in 3D space.
We'll create a new mesh using a BoxBufferGeometry as the geometry and a MeshPhongMaterial as the material.
To actually add these objects to our scene, we mount them inside the <Canvas />
component.
Note that we don't need to import anything, THREE objects will be treated as native JSX elements, just like you can just write <div>
or <span />
in regular React.
The general rule is that the Fiber components are available with the camel-case version of their name in THREE.js.
import { Canvas } from 'react-three-fiber'
function App() {
return (
<div id="canvas-container">
<Canvas>
<mesh>
<boxBufferGeometry attach="geometry" />
<meshPhongMaterial attach="material" />
</mesh>
</Canvas>
</div>
)
}
export default App
It's worth pausing a moment to understand exactly what is happening here. The code we just wrote, is the equivalent to this THREE.js code:
const myMesh = new THREE.Mesh()
const myGeometry = new THREE.BoxBufferGeometry()
const myMaterial = new THREE.MeshPhongMaterial()
myMesh.geometry = myGeometry
myMesh.material = myMaterial
scene.add(myMesh)
When you mount a mesh
component, Fiber is creating a new THREE.Mesh
object, and the same is done for geometry and material.
Then, geometry and material are attached to their parent, by assigning its geometry
and material
properties to the newly created objects.
Changing the camera
Attach and Args
The attach
prop is used to make this relationship explicit, effectively telling Fiber what property of the parent to attach the newly created object to.
The args
prop is used to pass constructor arguments to THREE.js.
To better understand this, we can take a look at the documentation for THREE's BoxBufferGeometry
, that tells us how the geometry is constructed:
const geometry = new THREE.BoxBufferGeometry(2, 2, 2)
Looking at the docs, we understand that (2, 2, 2)
are the width, height and depth of our box. These 3 values, make the arguments
array of the BoxBufferGeoemtry constructor.
We can make use of this info in Fiber:
<boxBufferGeometry args={[2, 2, 2]} />
The value of args
is always an array, and it's equivalent to the values we used in the THREE.js example to construct our geometry.
Adding lights
Next, we will add some lights to our scene, by putting these components as children of <Canvas />
<Canvas>
...
<ambientLight args={[0xff0000]} intensity={0.4} />
<directionalLight position={[0, 0, 5]} intensity={0.1} />
</Canvas>
This introduces us to the last fundamental concept of Fiber, how React props
work on THREE objects. Let's focus on ambientLight
:
<ambientLight // we are using a THREE.js AmbientLight
args={[0xff0000]} // we are passing this color to the constructor
intensity={0.1} // we are setting the light's intensity to 0.1
/>
From the AmbientLight
documentation we learn that it is constructed with a color value (0xff0000
in our case) and has an intensity
property, that defines how strong the light is.
When you set any prop on a Fiber component, it will set the property of the same name on the THREE.js object, like you could do manually:
const myLight = new THREE.AmbientLight(0xff0000)
// when the `intensity` prop changes
myLight.intensity = 0.1
Our directionalLight
doesn't have an args
prop, meaning that the default arguments will be used when creating the object. It does have a position
prop that, as you can imagine, will set the position
property of the DirectionalLight object.
Here's our final result, a simple box with a Phong material:
Exercise:
- try different materials, like
<meshNormalMaterial />
or<meshBasicMaterial />
- try different geometries, like
<sphereBufferGeometry />
or<octahedronBufferGeometry />
- try changing the
position
on ourmesh
component, by setting the prop with the same name - try extracting our mesh to a new component