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:

  1. 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]

  2. We added a <color /> component with args and attach props. This means that a new THREE.Color object will be created and set as the background property of the main scene.

const color = new THREE.Color('black') // args is the arguments array, passed to the constructor
scene.background = color // set the property on a three.js object parent[attach] = object
  1. We added a <mesh /> component with a <boxBufferGeometry /> child. Any component with geometry or material 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 /> and THREE.BoxBufferGeometry will be <boxBufferGeometry />
  • constructor arguments will be passed via the args prop, so new 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 = geometry
scene.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:

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.js Loader constructor, and the second being the url of the resource you want to load

    useLoader(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 using null 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 of MeshBasicMaterial

Exercise:

  • try scaling the texture and changing its wrapping modes:
// texture is scaled down to repeat twice
myTexture.repeat.set(2, 2)
// texture will now repeat both horizontally and vertically
myTexture.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
  • 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:

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.