整理自油管博主📺:I wish I knew this before using React Three Fiber - YouTube
因为正在学习Three.js,但是发现油管上的大神都在用React Three Fiber(R3F)做3D,有些好奇这两个库的关系,于是上网找了将这两者作类比的资料,希望对你有帮助~
先说结论👉 React Three Fiber的核心库仍然采用了Three.js的概念和技术,旨在通过使用React语法来实现Three.js的功能,从而创建和管理3D场景。而且相较于Three.js,它具有易于使用的API和更好的性能。
场景、相机、渲染
Three.js
创建场景scene
照相机camera(fov,aspect,near,far)
渲染器renderer
逐帧渲染动画函数
// Create "Canvas"
const scene = new Scene();
const camera = new PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.z = 5;
// Render
const renderer = new WebGLRenderer({ alpha: true, antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
const container = document.getElementById("__next");
if (container) {
container.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
R3F
只需从@react-three/fiber引入Canvas画布组件,可以视为scene,所有嵌套在canvas内的子组件都相当于添加到了scene中( scene.add() )
相机、逐帧渲染等React会默认帮我们处理
import { Canvas, useFrame } from "@react-three/fiber";
export default function R3fDemo() {
return (
<Canvas>
</Canvas>
);
}
如果想要自己管理相机,可以在Canvas组件上添加camera属性,属性值为配置对象
<Canvas camera={{position: [0, 0, 5]}}></Canvas>
或者使用@react-three/drei中的组件PerspectiveCamera,通过属性设置参数
import { PerspectiveCamera } from "@react-three/drei";
<Canvas>
<PerspectiveCamera fov={75} position={[0, 0, 5]}>
</Canvas>
对象
Three.js
const geometry = new BoxGeometry(2, 2, 2);
const material = new MeshStandardMaterial({color: "blue"});
const mesh = new Mesh(geometry, material)
scene.add(mesh);
R3F
元素的嵌套对应于Three.js的add()功能,除非他们具有attach属性
React中所有原始元素如div, h1都采用首字母小写。而Three.js中的原有的元素,如Mesh, BoxGeometry都被视为原始元素,采用首字母小写
使用args给原始元素传参
export default function R3fDemo() {
return (
<Canvas>
<mesh>
<boxGeometry attach="geometry" args={[2, 2, 2]}/>
<meshStandardMaterial attach="material" color="blue" />
<mesh>
</Canvas>
);
}
动画
Three.js
class Cube extends Mesh {
constructor() {
super();
const geometry = new BoxGeometry();
const material = new MeshStandardMaterial();
material.color.set("blue");
this.geometry = geometry;
this.material = material;
}
update() {
this.rotation.x += 0.01;
this.rotation.y += 0.01;
}
// 当模型不再使用时,释放geometry对象占用的内存
dispose() {
this.geometry.dispose();
}
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
cube.update();
}
animate();
R3F
使用 useRef获取mesh元素,ref指向three,js中的实例mesh,修改其旋转状态
在 useFrame 的回调函数中更新场景中的物体,使其在每一帧上渲染。对应于Three.js中,在动画函数中调用requestAnimationFrame ,并在其中更新物体
我们不需要手动清除,React会自动回收被移除的模型
function Cube() {
const meshRef = useRef<Mesh>(null);
useFrame(() => {
if (!meshRef.current) {
return;
}
meshRef.current.rotation.x += 0.01;
meshRef.current.rotation.y += 0.01;
});
return (
<mesh ref={meshRef}>
<PerspectiveCamera />
<boxGeometry />
<meshStandardMaterial color="blue" />
</mesh>
);
}
渲染表现
Three.js
为了提高three.js的渲染表现,我们通常会更改下面的属性:
默认关闭关闭抗锯齿效果,需要手动将antialias选项为改为true
three.js默认像素比为1,需要setPixelRatio来匹配用户浏览器支持的像素比
需要手动开启ACESFilmic色调映射
输出编码设置为sRGB编码
// Render
const renderer = new WebGLRenderer({ alpha: true, antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.toneMapping = ACESFilmicToneMapping;
renderer.outputEncoding = sRGBEncoding;
renderer.setSize(window.innerWidth, window.innerHeight);
R3F
R3F默认为我们开启了上面的渲染配置
当然我们也可以通过Canvas的gl属性,传入配置对象更改这些默认设置
<Canvas gl={{toneMapping: ACES}}></Canvas>
向量
Three.js
向量是一个有方向和大小的量,在3D模型中的作用非常重要,因为它们允许我们在三维空间中计算位置、方向和距离等信息,从而实现对3D模型的控制和操作。
在Three.js中,使用Vector3类来表示一个三维向量,其中x、y和z分别表示向量在三个坐标轴上的分量。
position是Vector3的实例,使用set方法设置xyz的分量值
const pointLight = new PointLight();
pointLight.position.set(10, 10, 10);
scene.add(pointLight);
R3F
R3F使用三元数组表示向量,实质是将三个值传给了set(x, y, z)
<Canvas>
<pointLight position={[10, 10, 10]} />
</Canvas>