three.js
(of problems)
React
editionthree.js
?JavaScript 3D library
The aim of the project is to create an easy to use, lightweight, 3D library with a default WebGL renderer. The library also provides Canvas 2D, SVG and CSS3D renderers in the examples.
Repository: github.com/mrdoob/three.js
import * as THREE from 'three';
const aspect = window.innerWidth / window.innerHeight;
const camera = new THREE.PerspectiveCamera(70, aspect, 0.01, 10);
camera.position.z = 1;
const scene = new THREE.Scene();
const geometry = new THREE.BoxGeometry(0.2, 0.2, 0.2);
const material = new THREE.MeshNormalMaterial();
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setAnimationLoop(animation);
function animation(time) {
mesh.rotation.x = time / 2000;
mesh.rotation.y = time / 1000;
renderer.render(scene, camera);
}
import React from 'react';
import ReactDOM from 'react-dom';
class Example extends React.Component {
componentDidMount() {
this.mount.appendChild(renderer.domElement);
// FIXME: Stop animating on unmount!
frame(0);
function frame(time) {
requestAnimationFrame(frame);
animation(time);
}
}
render() {
return <div ref={ref => (this.mount = ref)} />;
}
}
ReactDOM.render(<Example />, document.getElementById('example'));
react-three-fiber
!Repository: github.com/pmndrs/react-three-fiber
import React, { useRef, useState } from 'react';
import { useFrame } from 'react-three-fiber';
function Box(props) {
// This reference will give us direct access to the mesh
const mesh = useRef();
// Set up state for the hovered and active state
const [hovered, setHover] = useState(false);
const [active, setActive] = useState(false);
// Rotate mesh every frame, this is outside of React without overhead
useFrame(() => {
mesh.current.rotation.x = mesh.current.rotation.y += 0.01;
});
return (
<mesh
{...props}
ref={mesh}
scale={active ? [1.5, 1.5, 1.5] : [1, 1, 1]}
onClick={() => setActive(!active)}
onPointerOver={() => setHover(true)}
onPointerOut={() => setHover(false)}
>
<boxBufferGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
</mesh>
);
}
import ReactDOM from 'react-dom';
import React from 'react';
import { Canvas } from 'react-three-fiber';
import { Box } from './Box';
ReactDOM.render(
<Canvas>
<ambientLight />
<pointLight position={[10, 10, 10]} />
<Box position={[-1.2, 0, 0]} />
<Box position={[1.2, 0, 0]} />
</Canvas>,
document.getElementById('root'),
);
Is it slower than raw three.js
?
No. Rendering performance is up to threejs and the GPU. Components participate in the renderloop outside of React, without any additional overhead. React is otherwise very efficient in building and managing component-trees, it could potentially outperform manual/imperative apps at scale.
Repository: *repo*
DEMO
drei
A growing collection of useful helpers and abstractions for react-three-fiber
.
Repository: github.com/pmndrs/drei
three.js
wrappers and addonsNever, ever, setState
animations!
Never let React
anywhere near animated updates!
Never bind often occuring reactive state to a component!
More in pitfalls.md
and recipes.md
If something is not covered by react-three-fiber
or drei
, you're doomed forced to work with three.js
on your own.
const gltf = useGLTFLoader(url);
const colorMap = useImageLoader(colorTextureLink);
const normalMap = useImageLoader(normalTextureLink);
// Meshes cannot be shared therefore we clone the objects.
const elements = gltf.scene.children;
const elementsClone = useMemo(
() =>
elements.map(object => {
const cover = object.clone() as Mesh;
cover.castShadow = true;
cover.receiveShadow = true;
const material = cover.material.clone() as MeshPhysicalMaterial;
cover.material = material;
if (material.map) {
if (supportsTextureClone())
material.map = material.map.clone();
material.map.image = colorMap;
material.map.needsUpdate = true;
}
// Same for normalMap.
material.envMapIntensity = isFocused ? 1.5 : 0.2;
material.needsUpdate = true;
return cover;
}),
[elements, isFocused, normalMap, colorMap],
);
three.js
is very powerfulthree.js
is quite low-levelreact-three-fiber
is greatdrei
is even betterPS It works with React Native as well.