R3F(React Three Fiber)经验篇

之前一直在做ThreeJS方向,整理了两篇R3F(React Three Fiber)的文档,这是经验篇,如果您的业务场景需要使用R3F,可以参考一下这个文档。下面是目录,按照需求自取。

基础篇 ⬇️

R3F(React Three Fiber)基础篇

React Three Fiber Development Experience

文章目录

  • [React Three Fiber Development Experience](#React Three Fiber Development Experience)
    • [一、Asset Website](#一、Asset Website)
    • 二、Libraries
      • [1. three-stdlib](#1. three-stdlib)
    • 三、Usage
      • [1. 动画周期震荡](#1. 动画周期震荡)
      • [2. 内部摄像机](#2. 内部摄像机)
      • [3. camera far和fov的区别](#3. camera far和fov的区别)
      • [4. Bvh](#4. Bvh)
      • [5. leva](#5. leva)
      • [6. 一个镜面反射的球](#6. 一个镜面反射的球)
      • [7. 在场景里居中](#7. 在场景里居中)
      • [8. 自带环境](#8. 自带环境)
      • [9. 给一个物体添加一个可移动的,带有坐标系的控制器](#9. 给一个物体添加一个可移动的,带有坐标系的控制器)
      • [10. Float](#10. Float)
      • [11. Mask](#11. Mask)
      • [12. 更改GLTF模型颜色](#12. 更改GLTF模型颜色)
      • [13. Better TypeScript Support for useGLTF](#13. Better TypeScript Support for useGLTF)
      • [14. Sparkles](#14. Sparkles)
      • [15. 随机色](#15. 随机色)

一、Asset Website

https://gltf.pmnd.rs/:GLTF -> React Three Fiber

https://polyhaven.com/ : Assert Website

二、Libraries

1. three-stdlib

Stand-alone version of threejs/examples/jsm written in Typescript & built for ESM & CJS.

可以为 threejs中 不支持 TS 的 代码提供TS支持

install

shell 复制代码
npm install three-stdlib

usage

typescript 复制代码
// Export collection
import * as STDLIB from 'three-stdlib'
// Flatbundle
import { OrbitControls, ... } from 'three-stdlib'

三、Usage

1. 动画周期震荡

typescript 复制代码
useFrame((state) => (textRef.current.position.x = Math.sin(state.clock.elapsedTime) * 2))

完整例子:

typescript 复制代码
const Cube: FC = () => {
	const textRef = useRef<Mesh>(null!)
	useFrame((state) => (textRef.current.position.x = Math.sin(state.clock.elapsedTime) * 2))
	return (
		<mesh>
			<boxGeometry />
			<meshStandardMaterial>
				<RenderTexture attach="map" anisotropy={16}>
					<PerspectiveCamera makeDefault manual aspect={1} position={[0, 0, 5]} />
					<color attach="background" args={['orange']} />
					<Text fontSize={4} color={'#555'} ref={textRef}>
						hello
					</Text>
				</RenderTexture>
			</meshStandardMaterial>
		</mesh>
	)
}

2. 内部摄像机

关键属性:makeDefault manual

TSX:<PerspectiveCamera makeDefault manual aspect={1} position={[0, 0, 5]} />

例子见动画周期震荡d艾玛

3. camera far和fov的区别

jsx 复制代码
<Canvas shadows camera={{ position: [0, 0, 3], fov: 10 }}>

在Three.js中,farfov是两种不同的概念,都与渲染3D场景时的视觉效果有关,但是它们的作用是不同的。

  1. far:这个参数是在设置相机的裁剪面时使用的,表示相机能看到的最远距离。当一个物体离相机的距离超过这个值时,这个物体就不会被渲染出来。换句话说,far定义了你的视野的"深度"。
  2. fov:这是相机的视场角度(Field of View),以度为单位。它定义了相机视野的"宽度",即相机能够看到的角度大小。在Three.js中,这个值默认是50度,但可以根据需要进行调整。

所以,farfov在控制渲染效果上有不同的作用:far控制的是视野的深度,而fov控制的是视野的宽度。在实际应用中,你需要根据你的需求来调整这两个参数。

far和设置position z轴的效果是一样的。

4. Bvh

参考:https://github.com/pmndrs/drei#bvh

使用Bvh包裹的组件,性能会更好,原因不明

jsx 复制代码
<Canvas>
  <Bvh firstHitOnly>
    <Scene />
  </Bvh>
</Canvas>

5. leva

一种GUI库,可以用作参数调试或简易设置界面

useControls最终的配置项会合并到一起。

具体用法参考一、RTF Debugger

typescript 复制代码
import { useControls } from 'leva'
function CSphere() {
	const { roughness } = useControls({ roughness: { value: 1, min: 0, max: 1 } })
	return (
		<Center top>
			<mesh castShadow>
				<sphereGeometry args={[0.75, 64, 64]} />
				<meshStandardMaterial metalness={1} roughness={roughness} />
			</mesh>
		</Center>
	)
}
枚举类型
typescript 复制代码
const { model } = useControls({ model: { value: 'Beech', options: Object.keys(MODELS) } })

6. 一个镜面反射的球

关键参数:

metalness:数值为 1 反光率最大,距离1越大,镜面反射转为漫反射效果越明显。

roughness:有点抛光那个意思,数值越大,镜面效果越明显

typescript 复制代码
<mesh castShadow>
    <sphereGeometry args={[0.75, 64, 64]} />
    <meshStandardMaterial metalness={1} roughness={roughness} />
</mesh>

7. 在场景里居中

typescript 复制代码
<Center top>
	<mesh castShadow>
    	<sphereGeometry args={[0.75, 64, 64]} />
    	<meshStandardMaterial metalness={1} roughness={roughness} />
    </mesh>
</Center>

8. 自带环境

复制代码
<Environment preset={preset} background blur={blur} />
typescript 复制代码
preset?: PresetsType;
background?: boolean | 'only';
export declare const presetsObj: {
    apartment: string;
    city: string;
    dawn: string;
    forest: string;
    lobby: string;
    night: string;
    park: string;
    studio: string;
    sunset: string;
    warehouse: string;
};
export type PresetsType = keyof typeof presetsObj;

background为only时,不反射环境光

9. 给一个物体添加一个可移动的,带有坐标系的控制器

typescript 复制代码
<PivotControls offset={[0, 0, 1]} activeAxes={[true, true, false]} disableRotations depthTest={true}>
    <CFrame position={[0, 0, 1]} />
    <Mask id={1} position={[0, 0, 0.95]}>
    	<circleGeometry args={[0.8, 64]} />
    </Mask>
</PivotControls>

10. Float

让内容上下浮动

typescript 复制代码
<Float
  speed={1} // Animation speed, defaults to 1
  rotationIntensity={1} // XYZ rotation intensity, defaults to 1
  floatIntensity={1} // Up/down float intensity, works like a multiplier with floatingRange,defaults to 1
  floatingRange={[1, 10]} // Range of y-axis values the object will float within, defaults to [-0.1,0.1]
>
  <mesh />
</Float>

11. Mask

可以用来遮罩效果

CAtom 定义需要遮挡的物体

typescript 复制代码
const CAtom: FC<{ invert?: boolean } & MeshProps> = ({ invert, ...props }) => {
    // 定义 stencil,1为id,false为将物体遮挡(隐藏)
	const stencil = useMask(1, false)
	const { nodes } = useGLTF('/glb/react-transformed.glb') as unknown as { nodes: Record<string, any> }
	const gltf = useGLTF('/glb/react-transformed.glb')
	return (
		<mesh
			castShadow={true}
			receiveShadow={true}
			geometry={nodes.atom.geometry}
			dispose={null}
			{...props}
		>
			<meshPhongMaterial color="#33BBFF" {...stencil} />
		</mesh>
	)
}

在另一个组件,用Mask 投影被遮挡的物体的图像

typescript 复制代码
<PivotControls offset={[0, 0, 1]} activeAxes={[true, true, false]} disableRotations depthTest={true}>
    <CFrame position={[0, 0, 1]} />
    { // 这里和id和之前那个Mask的id对应 }
    <Mask id={1} position={[0, 0, 0.95]}>
    <circleGeometry args={[0.8, 64]} />
    </Mask>
</PivotControls>
<Bounds fit clip observe>
    <Float floatIntensity={4} rotationIntensity={0} speed={4}>
        <CAtom invert={invert} scale={1.5} />
    </Float>
</Bounds>

12. 更改GLTF模型颜色

参考案例:https://codesandbox.io/s/re-using-gltfs-forked-wpzjcg?file=/src/Shoe.js

声明式写法

typescript 复制代码
const MShoe: FC<{ color: string } & Record<string, any>> = (
	{ color, ...props }) => {

	const gltf = useGLTF('glb/shoe.gltf');

	const { nodes, materials } = gltf as unknown as {
		nodes: Record<string, any>
		materials: Record<string, any>
	};

	// 建立nodes和materials映射关系
	const nodeArr = Object.entries(nodes).filter(([key, value], index) => index > 1);
	const materialArr = Object.values(materials)
	const changeColorNode = 'shoe_1';

	// 重新构建组合 Mesh
	return (
		<group {...props} dispose={null}>
			{ nodeArr.map(([key, node], index) => (
				<mesh
					key={key}
					castShadow={true}
					receiveShadow={true}
					geometry={node.geometry}
					material={index !== 1 ? materialArr[index] : undefined}
					material-envMapIntensity={0.8}
				>
					{
						key === changeColorNode &&
						<meshStandardMaterial
							{...materials.mesh}
              				color={color}
							envMapIntensity={0.8}
              				normalMap-encoding={LinearEncoding}
						/>
					}
				</mesh>
			))}
		</group>
	)
}

编程式写法

typescript 复制代码
	const MShoe2: FC<ModelProps> = (props) => {
	const gltf = useGLTF('glb/shoe.gltf')
	const { scene } = gltf;
	const { materials } = gltf as unknown as Record<string, any>;
	const ref = useRef<Group>(null!);

	useEffect(() => {
		ref.current.traverse(child => {
			if(child.name === 'shoe_1' && (child as any).isMesh) {
				(child as any).material = new MeshStandardMaterial({
					...materials.mesh,
					color: 0xff6666,
					envMapIntensity: 0.8,
				});
			}
		})
	}, [materials]);

	return <primitive object={scene} {...props} ref={ref}/>
}

13. Better TypeScript Support for useGLTF

Refer to the Libraries chapter for three-stdlib

Declare

typescript 复制代码
declare type C_GLTF = import('three-stdlib').GLTF & {
	nodes: Record<string, import("three").Mesh>;
	materials: Record<string, import("three").MeshStandardMaterial>;
};

Usage

typescript 复制代码
const { nodes, materials } = useGLTF('/cyberpunk.glb', true) as C_GLTF;

14. Sparkles

繁星效果,Floating, glowing particles(发光粒子).

typescript 复制代码
<Sparkles
    size={ 6 }
    scale={ [ 4, 2, 6 ] }
    position-y={ 1 }
    speed={ 0.1 }
/>

15. 随机色

typescript 复制代码
type TorusMesh = Mesh<TorusGeometry, MeshMatcapMaterial>

const eventHandler = (event: ThreeEvent<MouseEvent>) => {
    event.stopPropagation();
    const mesh= event.eventObject as TorusMesh;
    const newMaterial = mesh.material.clone()
    newMaterial.color.set(`hsl(${Math.random() * 360}, 100%, 75%)`) // hsl color
    mesh.material = newMaterial;
}
相关推荐
沐土Arvin几秒前
深入理解 requestIdleCallback:浏览器空闲时段的性能优化利器
开发语言·前端·javascript·设计模式·html
专注VB编程开发20年2 分钟前
VB.NET关于接口实现与简化设计的分析,封装其他类
java·前端·数据库
小妖66611 分钟前
css 中 content: “\e6d0“ 怎么变成图标的?
前端·css
L耀早睡1 小时前
mapreduce打包运行
大数据·前端·spark·mapreduce
HouGISer1 小时前
副业小程序YUERGS,从开发到变现
前端·小程序
outstanding木槿1 小时前
react中安装依赖时的问题 【集合】
前端·javascript·react.js·node.js
霸王蟹2 小时前
React中useState中更新是同步的还是异步的?
前端·javascript·笔记·学习·react.js·前端框架
霸王蟹2 小时前
React Hooks 必须在组件最顶层调用的原因解析
前端·javascript·笔记·学习·react.js
专注VB编程开发20年2 小时前
asp.net IHttpHandler 对分块传输编码的支持,IIs web服务器后端技术
服务器·前端·asp.net
爱分享的程序员3 小时前
全栈项目搭建指南:Nuxt.js + Node.js + MongoDB
前端