Your First Scene
This guide will help you setup your first React Three Fiber scene and introduce you to its core concepts.
The Canvas
Every scene starts with the <Canvas />
component, which we can import from react-three-fiber
:
In the example above, we can start getting familiar with some of the basic concepts of React Three Fiber:
We set a camera prop for the
<Canvas />
component. This is the initial position of Fiber's default PerspectiveCamera - which would otherwise be at[0, 0, 5]
We added a
<color />
component withargs
andattach
props. This means that a newTHREE.Color
object will be created and set as thebackground
property of the mainscene
.
const color = new THREE.Color('black') // args is the arguments array, passed to the constructorscene.background = color // set the property on a three.js object parent[attach] = object
We added a
<mesh />
component with a<boxBufferGeometry />
child. Any component withgeometry
ormaterial
in its name, will automatically attach to the corresponding property of its parent:const myMesh = new THREE.Mesh() // <mesh />const myGeometry = new THREE.BoxBufferGeometry() // <boxBufferGeometry />myMesh.geometry = myGeometry // set the `geometry` property on our mesh
The <Canvas />
will fill its parent element (try changing the width and height of .App
in src/styles.css
)
React Three Fiber can render any object from three.js, using these simple rules:
- components will be camel-case, so
THREE.Mesh
will be<mesh />
andTHREE.BoxBufferGeometry
will be<boxBufferGeometry />
- constructor arguments will be passed via the
args
prop, sonew THREE.Color("red")
will become<color args={["red"]} />
This gives you an initial idea of how React Three Fiber will work, but let's dive deeper!
Meshes, Geometries and Materials
In the previous example, we created a <mesh />
component with a <boxBufferGeometry />
child.
This is equivalent to creating those objects in three.js, putting them together and adding them to the scene:
const mesh = new THREE.Mesh()const geometry = new THREE.BoxBufferGeometry()mesh.geometry = geometryscene.add(mesh)
We can add materials in the same way, let's say we want to use THREE.MeshNormalMaterial
, we will have to use a camel-case version of the name, in this case <meshPhysicalMaterial />
:
Exercise:
- try different materials, like
<meshPhongMaterial />
or<meshBasicMaterial />
- try different geometries, like
<sphereBufferGeometry />
or<octahedronBufferGeometry />
Loading Textures
We will now add a simple texture
to our box, to make it look less boring!
This example will introduce you to the concept of three's Loaders, Fiber's useLoader hook and a sprinkle of React's Suspense.
Let's take a closer look:
we moved our box mesh to its own component, since React Three Fiber Hooks can only be used inside
<Canvas />
children.we imported the
useLoader
hook from Fiber. useLoader expects at least two arguments, the first being a three.jsLoader
constructor, and the second being the url of the resource you want to loaduseLoader(THREE.TextureLoader, url)we wrapped our
<MyBox />
component with a React Suspense block.<React.Suspense fallback={null}><MyBox /></React.Suspense>By doing this, we tell React that our component should not be rendered until our texture is finished loading, and that instead we want to render whatever element is passed to
fallback
. We will be just usingnull
for now, but we will build something nicer later!💡React Suspense is a big topic, we will get back to it later, but if you want to learn more, you should read this page.Finally, we assign our newly loaded texture to the
map
property ofMeshBasicMaterial
Exercise:
- try scaling the texture and changing its wrapping modes:
// texture is scaled down to repeat twicemyTexture.repeat.set(2, 2) // texture will now repeat both horizontally and verticallymyTexture.wrapS = myTexture.wrapT = THREE.RepeatWrapping
You can just add these lines right after assigning myTexture
(line 10).
We can also simplify our texture loading by using drei's useTexture
Loading 3D Models
Boxes are boring, we all know that. Let's load a gltf
file, and get introduced to the React Three Fiber ecosystem:
We will add a new dependency to our project, @react-three/drei
.
Drei is a collection of useful helpers and abstractions for Fiber, and we will use a few of its components to improve our example.
- we put our files in
public/model
, so that our resource will be served by the web server - we load our model with drei's
useGLTF
. Here's what's happening, in detail:- Suspense is triggered by
useGLTF
, so our component will not render until it's done loading - The
.gltf
file is fetched - All the related files (binaries and images) are fetched
- Suspense is resolved and our component can now finally render
- Suspense is triggered by
- we destructure nodes (the model's objects) and materials and assign them to a mesh's geometry and material
BONUS: we can add OrbitControls by using drei's <OrbitControls />
component - try dragging and scrolling in the scene
Phew, that's a lot to unpack. We will make this process easier later, when we'll introduce the gltfjsx utility.
Exercise:
- try console logging the result of
useGLTF
, to see just what's returned from the hook - try to load a
.glb
file - you can find some free-to-use files here https://github.com/KhronosGroup/glTF-Sample-Models/
Moving to components
We will now refactor our previous example to better use React's strong suite, components!
In the example, we created a new MyBox
component that will render a new mesh
, and we reuse it twice, with different position
and color
props.