twitter.com/gdlazcano_

Import 3D models in React Three Fiber vs Three.js

Published on: January 10, 2023

Reading time: 4 min

What is React Three Fiber?

React Three Fiber is a new React renderer for Three.js, it’s an abstraction layer on top of Three.js, so you can use Three.js without having to worry about the underlying implementation.

Base application

Three.js

Here is a simple bare Three.js template to get your started:

You can also see clone this template from here

<!-- index.html -->
<html>
  <head>
    <style>
      * {
          margin: 0;
          padding: 0;
      }

      html,
      body {
          overflow: hidden;
      }

      .webgl {
          position: fixed;
          top: 0;
          left: 0;
          outline: none;
      }
    </style>

  </head>
  <body>
    <canvas class="webgl"></canvas>
    <script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
    <script type="importmap">
      {
        "imports": {
          "three": "https://unpkg.com/three/build/three.module.js"
        }
      }
    </script>
    <script type="module" src="main.js">
  </body>
</html>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

const canvas = document.querySelector("canvas.webgl");
// Scene
const scene = new THREE.Scene();

const sizes = {
  width: window.innerWidth,
  height: window.innerHeight,
};

window.addEventListener("resize", () => {
  // Update sizes
  sizes.width = window.innerWidth;
  sizes.height = window.innerHeight;

  // Update camera
  camera.aspect = sizes.width / sizes.height;
  camera.updateProjectionMatrix();

  // Update renderer
  renderer.setSize(sizes.width, sizes.height);
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});

const camera = new THREE.PerspectiveCamera(
  75,
  sizes.width / sizes.height,
  0.1,
  100
);
camera.position.x = 1;
camera.position.y = 1;
camera.position.z = 1;
scene.add(camera);

// Controls
const controls = new OrbitControls(camera, canvas);
controls.enableDamping = true;

// Lights
const light = new THREE.AmbientLight(0x404040, 2); // soft white light
scene.add(light);

const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
scene.add(directionalLight);

// Renderer
const renderer = new THREE.WebGLRenderer({
  canvas: canvas,
  antialias: true,
});
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));

// Animate
const clock = new THREE.Clock();
let lastElapsedTime = 0;

const tick = () => {
  const elapsedTime = clock.getElapsedTime();
  const deltaTime = elapsedTime - lastElapsedTime;
  lastElapsedTime = elapsedTime;

  // Update controls
  controls.update();

  // Render
  renderer.render(scene, camera);

  // Call tick again on the next frame
  window.requestAnimationFrame(tick);
};

tick();

In React Three Fiber

Which is basically the same as doing this in React Three Fiber, as you can see it’s really abstracted away from Three.js:

import { OrbitControls } from "@react-three/drei";
import { Canvas } from "@react-three/fiber";

export default function App() {
  return (
    <div className="App">
      <Canvas camera={{ position: [0, 0, 10], fov: 55 }}>
        <ambientLight intensity={0.6} />
        <pointLight position={[10, 10, 10]} />
        <OrbitControls />
      </Canvas>
    </div>
  );
}

Import 3D model

You can download the capybara 3D model i’m using for this tutorial here

It’s a GLB file so you will have to use the GLTFLoader to load it. There’s many other loaders for different file types, but the GLTFLoader is the most common one.

In Three.js

// Import GLTFLoader from unpkg
import { GLTFLoader } from "https://unpkg.com/three/examples/jsm/loaders/GLTFLoader.js";

const loader = new GLTFLoader();
loader.load(
  "/models/capybara.glb", // load the model
  function (gltf) {
    const capy = gltf.scene;

    // change the color of the model
    var newMaterial = new THREE.MeshPhysicalMaterial({ color: 0xbf743d });
    capy.traverse((o) => {
      if (!o.isMesh) return;

      o.material = newMaterial;
    });

    // add capybara to the scene
    scene.add(capy);
  },
  undefined,
  function (error) {
    // handle errors
    console.error(error);
  }
);

In React Three Fiber

import { useLoader } from "@react-three/fiber";
import { Suspense, useMemo } from "react";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";

export default function Capybara() {
  const { materials, scene } = useLoader(
    GLTFLoader,
    "https://gabriellazcano.com/models/capybara.glb"
  ); // load the model

  useMemo(() => {
    for (const material in materials) {
      // iterate the materials
      if (Object.prototype.hasOwnProperty.call(materials, material)) {
        // change the color of all the materials (there's only one in this model)
        materials[material].color.set("#bb6f3e");
        // you can also change the color of a specific material if you know the name of the material
      }
    }
  }, [materials]);

  // return the primitive with our scene and changed materials
  return <primitive object={scene} />;
}

Simply import the component and render it in the scene wrapped with a Suspense component.

import Capybara from "../Capybara";

export default function App() {
  return (
    <div className="App">
      <Canvas camera={{ position: [0, 0, 10], fov: 55 }}>
        <ambientLight intensity={0.6} />
        <pointLight position={[10, 10, 10]} />

        <Suspense fallback={null}>
          <Capybara />
        </Suspense>

        <OrbitControls />
      </Canvas>
    </div>
  );
}

Conclusion

It’s really really easy to use React Three Fiber, it manages most of the things for you. However a knowledge of Three.js is somewhat required to use React Three Fiber as some documentation and functions are written in Three.js. I would encourage you to learn both at the same time and test your knowledge.

Thanks for reading, let’s connect

Thanks for reading my blog. Feel free to reach out to me if you have any questions or want to connect. You can also make a pull request if you want to improve the article :)))

Edit this page on Github

Share this article

11 Tweets