Pmndrs.docs

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.

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'

export default function App() {
  return (
    <div id="canvas-container">
      <Canvas />
    </div>
  )
}

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 resizing
  • It renders our scene every frame
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.

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 />

Adding a Mesh Component

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 BoxGeometry component for the geometry and a MeshPhongMaterial component for 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 Fiber components are available under the camel-case version of their name in three.js.
import { Canvas } from '@react-three/fiber'

export default function App() {
  return (
    <div id="canvas-container">
      <Canvas>
        <mesh>
          <boxGeometry />
          <meshPhongMaterial />
        </mesh>
      </Canvas>
    </div>
  )
}

Let's pause for a moment to understand exactly what is happening here. The code we just wrote is the equivalent to this three.js code:

const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000)

const renderer = new THREE.WebGLRenderer()
renderer.setSize(width, height)
document.querySelector('#canvas-container').appendChild(renderer.domElement)

const mesh = new THREE.Mesh()
mesh.geometry = new THREE.BoxGeometry()
mesh.material = new THREE.MeshPhongMaterial()

scene.add(mesh)

function animate() {
  requestAnimationFrame(animate)
  renderer.render(scene, camera)
}

animate()

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.

Constructor arguments

If we consult the documentation for THREE's BoxGeometry we can optionally pass three arguments for: width, length and depth:

const geometry = new THREE.BoxGeometry(2, 2, 2)

In order to do this in Fiber we use the args prop, which always takes an array whose items represent constructor argument.

<boxGeometry args={[2, 2, 2]} />
Note that every time you change these, the object must be re-constructed!

Adding lights

Next, we will add some lights to our scene, by putting these components as children of <Canvas />

<Canvas>
  ...
  <ambientLight intensity={0.1} />
  <directionalLight color="red" position={[0, 0, 5]} />
</Canvas>

Props

This introduces us to the last fundamental concept of Fiber, how React props work on THREE objects. When you set any prop on a Fiber component, it will set the property of the same name on the three.js object.

Let's focus on our ambientLight, whose documentation tells us that we can optionally construct it with a color, but can also receive props.

// we are using a THREE.js AmbientLight
<ambientLight
  // we are setting the lights intensity to 0.1
  intensity={0.1}
/>

Which is the equivalent to:

const light = new THREE.AmbientLight()
light.intensity = 0.1

Shortcuts

There are a few shortcuts for classes that have a .set() method (colors, vectors, ect).

const light = new THREE.DirectionalLight()
light.position.set(0, 0, 5)
light.color.set('red')

Which is the same as the following in JSX:

<directionalLight
  // we are setting the position
  position={[0, 0, 5]}
  // we are setting the color
  color="red"
/>

Please refer to the API for a deeper explanation.

The result

import { Canvas } from '@react-three/fiber'

export default function App() {
  return (
    <div id="canvas-container">
      <Canvas>
        <ambientLight intensity={0.1} />
        <directionalLight color="red" position={[0, 0, 5]} />
        <mesh>
          <boxGeometry />
          <meshPhongMaterial />
        </mesh>
      </Canvas>
    </div>
  )
}

Exercise