Three.js
There are no doubts about it, Three.js is complicated as hell. As it stands, I have but a tenuous grasp on this library and what it is capable of accomplishing -- know that going forward. That being said, my lack of knowledge is not a deterrent for attempting to implement it in various projects. The best way to learn is by doing, right?
Three.js is a cross-browser JavaScript library and application programming interface (API) used to create and display animated 3D computer graphics in a web browser using WebGL.
Essentially, Three.js allows us to make 3D objects and environments and implement them in various ways. Want to create a game? Three.js can handle it. Want to add an interesting project to your personal portfolio with more dimensions? Yeah, no problem.
So, how do we use it?
Basics of Three.js
You'll, of course, first need your HTML file.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My first three.js app</title>
<style>
body { margin: 0; }
</style>
</head>
<body>
<script src="js/three.js"></script>
<script>
// Our Javascript will go here.
</script>
</body>
</html>
In order to get started, you're going to need a few things in your script file: a scene, a camera, and a renderer.
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 );
You might be asking yourself, what the hell is going on here? Think of the scene as your environment. But, in order to actually display your scene you need a camera (which takes in arguments for FOV, aspect ratio, and near/far clipping planes), and a renderer. The renderer, described as "what makes the magic happen", can be thought of as your <Canvas />
-- which is typically set to the full-size of your window for obvious reasons (but, of course can be made smaller to fit your needs). Next we append the renderer to the body
of our document.
Add a shape to the scene
We'll be rendering a simple cube -- which will require three things: a geometry, a material, and a mesh to fuse the geometry and material together.
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial( { color: #000 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 5;
A few things to note here: a material takes an object of properties (not just limited to color), we need to add the cube to the scene by using the .add method and passing in the mesh we created, and we need to move the camera out a bit on the z-index to view the object (you could also change the default position of the cube object if you did not want to move the camera).
Render Loop
Here comes the last bit. If you used all the code above, you would not be seeing anything just yet. In order to actually view your cube on your canvas element, you'll need to use what is referred to as a render, game, or animate loop.
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
What this loop is doing is drawing your screen every time your screen refreshes (usually around 60 times per second, but can be more depending upon the quality of your monitor).
Your First Scene
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My first three.js app</title>
<style>
body { margin: 0; }
</style>
</head>
<body>
<script src="js/three.js"></script>
<script>
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 );
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 5;
const animate = function () {
requestAnimationFrame( animate );
renderer.render( scene, camera );
};
animate();
</script>
</body>
</html>
React-Three/Fiber
You know all that complicated stuff creating a scene, camera, renderer, and animation loop we used earlier? Yeah, much easier using R3F. First off, install the following dependencies by running
npm i three @react-three/fiber @react-three/drei
Next, prepare your App
component with the following imports and stage your incoming 3d model with a Model
component:
import { Canvas } from '@react-three/fiber'
import { useLoader } from '@react-three/fiber'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { Suspense } from "react";
const Model = () => {
const gltf = useLoader(GLTFLoader, "./scene.gltf")
return (
<>
<primitive position={[0, 0, 0]} object={gltf.scene} scale={1} />
</>
);
};
function App = () => {
return(
<Canvas>
<Suspense>
<Model />
</Suspense>
</Canvas>
)
}
Now here's the great part, the <Canvas />
component imported from @react-three/fiber
does all the work of creating the render loop, scene, renderer, and camera for you. If you want to reposition the camera (let's say pull it back a bit), you can pass camera
as props to the canvas component like so:
//specify the position of the camera with x, y, and z coordinates
<Canvas camera={{ position: [0, -40, 20] }}>
</Canvas>
Add Your 3D Model
If you haven't already done so, head on over to SketchFab -- which is a great resource for acquiring 3D models. Find one that you like and download the .gltf version of the model and add it into the public folder of your React app (where your index.html file is stored). You'll need to add both the scene.bin and scene.gltf files in order for the model to appear.
Once this is done, run your React app and you should see your 3D model on the canvas!
Top comments (2)
Can't load any 3d model (GLTF, OBJ or FBX) because "Error: ReactDOMServer does not yet support Suspense".
Look: github.com/pmndrs/react-three-fibe...
Has anyone encoutered the same issue? Thnkx
You are using suspense around the wrong functions....use it in the parent component for instance, inside the canvas tag