Wonjoon Jang

Trying out threejs tutorial

Frontend dev's very interesting in my opinion. There's so much to learn, variety of challenges.

Because the requirements are so different. That being said, there's so many things to try out.

Probably people that are reading the post are already familiar with Three.js a powerful 3d rendering library on the web browser.

I was known it's existance for quite sometime now, but never have felt the need to learn it.

However since I've started publishing my posts and started looking for things to learn. I have decided this was going to be One of the things I learned.

So here it goes. The react-three-fiber tryout.

Following the tutorial

We should know that threejs came out not just for react. Since react has it's own rendering strategies we have to modify threejs codes to a React based code.

Which means, we'll have to create components and divide the code and write stuff using JSX which is the syntax React uses.

Hence, we'll be using react-three-fiber.

Understanding the basic concepts of Threejs

If you're still unfamiliar to React, probably should checkout React first.

As for threejs. These scene, camera, mesh, geometry, material are the fundamentals to understand.

I didn't know the core concept of threejs, so let me elaborate.

There are somethings in Threejs for displaying "things" on the browser.

These elements are called scene, camera, renderer.

Essential things for displaying in Threejs

Which means, in code term. In order to show something using Threejs there's always going to be a scene, camera, renderer code inside it.

Scene

Scene is where things are being displayed. You might say it's the background of the whole threejs rendering situation.

camera

So camera object decide how the things that are displayed inside the scene are "seen". It decides the aspect ratio, if it feels near, far. tilted? It's like controling the eyeball.

There are many type of cameras that threejs offers. Usually these cameras are created using generators and they require attributes.

  1. field of View(FOV) => It's where you want to see(?) and the value is in degrees.
  2. aspect ratio => decides the aspect ratio of what you see. In most cases you'd want to just use window.innerWidth / window.innerHeight
  3. near => objects near than the value will not be rendered
  4. far => objects further than value will not be rendered

renderer

renderer is the one which combines everything, scene, camera and the things in scene, and draws this on the browser. Like its name it is in change of rendering the things. There is more than one renderer in threejs, for some people might not have WebGL support.

Now knowing this, let's look at this example code from three.js web.

the setSize method of renderer as it's name can set the size of the rendering area. Which can affect the performance of the app.

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

As you can see there's a scene, camera, renderer.

Time to move on to Geometry, Material, Mesh

Now we've seen how to create a scene and by now you'd probably noticed that the things we're interested in, the objects that look 3d are created these Geometry, Material, Mesh.

let's see another example code from the three.js website

const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);

scene.add(cube);

look how Mesh function takes Geometry and Material as argument. In the end, scene.add() is called and the Mesh object goes in as the argument.

Finally, ready to render,(last step of rendering)

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

In order for the scene to render, render.render() must be called in a infinite loop.

Seems like the three.js library is recommending this by calling the animate function to be called inside requestAnimationFrame;

So that was it. The basic understanding of three.js and the fundamentals of it.

Again, try to remember the names.

How does this work in React?

Ther react-three-fiber library comes with a good example and actually the same example from threejs docs.

Since react uses jsx, creating a scene, light, camera, geometry, mesh it's all done with the jsx syntax.

let's have a look at the rendering scene first

import { Canvas } from "@react-three/fiber";
import Box from "components/Box";

<Canvas>
  <ambientLight />
  <pointLight position={[10, 10, 10]} />
  <Box position={[-1.2, 0, 0]} />
  <Box position={[1.2, 0, 0]} />
</Canvas>

<Canvas> a given component is imported to carry its children JSX elements Inside the Canvas there's a light, and Box which is obviously the Mesh object.

So we can assume that, in @react-three/fiber the renderer, scene, camera is defaultly set inside <Canvas> component(We'll have to dig about this later).

Also, the <ambientLight>, <pointLight> component doesn't even have import statements. We'll look into those too.

looking into the Mesh

function Box(props: JSX.IntrinsicElements["mesh"]) {
  const mesh = useRef<THREE.Mesh>(null!);
  const [hovered, setHover] = useState(false);
  const [active, setActive] = useState(false);
  useFrame((state, delta) => (mesh.current.rotation.x += 0.01));
  return (
    <mesh
      {...props}
      ref={mesh}
      scale={active ? 1.5 : 1}
      onClick={(event) => setActive(!active)}
      onPointerOver={(event) => setHover(true)}
      onPointerOut={(event) => setHover(false)}
    >
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial color={hovered ? "hotpink" : "orange"} />
    </mesh>
  );
}

Now having a look at the Mesh object, which has now beccome a react element, somethings are notable.

  1. useRef hook for the mesh
  2. accepting props and setting to the mesh
  3. mesh's children jsx elements are geometry and material.
  4. custom hook from @react-three/fiber to animate

Do you remember, in pure javascript code, mesh took geometry, material as arguments? Seems like in react it's now handled this way.

Alright, that's it for today.

Next time, we'll try to get the source code of space warping effect, and try to turn it into a react-based code.