react-three-fiber
自定义渲染器核心逻辑主要是在于 createRenderer 方法中如何将 Three.js 中的对象结构与 JSX 绑定到一起,并返回 Reconciler
和 applyProps
用于对虚拟 DOM 的维护和更新。绑定 Three 命名空间
interface Catalogue { [name: string]: { new (...args: any): Instance } } export const catalogue: Catalogue = {}; const extend = (objects: object): void => void Object.assign(catalogue, objects); React.useMemo(() => extend(THREE), []);
这里主要是将
THREE.Mesh
等缓存到 catalogue 中。createInstance
该方法接收三个参数,
type
、InstanceProps
以及 rootStore
。代表要创建的 Three.js 对象的类型(例如 'mesh'、'camera'、'light'),以及一个
InstanceProps
对象,其中包含了将要设置在实例上的属性,包括 args、attach 以及其他自定义属性。如果类型是 'primitive',意味着函数必须处理一个通过 object 属性直接传入的原始对象,原始对象是指不是由 R3F 创建而是直接传入的对象,可能是因为它在 React 外部被创建或者是被其他状态管理;函数将创建 Three.js 对象,根据类型设置属性。类型包括 'mesh'、'camera'、'light',如果是 'primitive',则需要处理传入的原始对象。其他类型需以大写字母开头匹配 Three.js 类名,如:
<mesh ..../> const mesh = new THREE.Mesh(...);
如果是 BufferGeometry 或者 Material,则会被自动挂载到其父节点上。
<mesh> <meshBasicMaterial attach="material" /> <boxGeometry attach="geometry" /> </mesh> const geometry = new THREE.BoxGeometry( 1, 1, 1 ); const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); const mesh = new THREE.Mesh( geometry, material );
appendChild
function appendChild(parentInstance: HostConfig['instance'], child: HostConfig['instance']) { let added = false if (child) { // The attach attribute implies that the object attaches itself on the parent if (child.__r3f?.attach) { attach(parentInstance, child, child.__r3f.attach) } else if (child.isObject3D && parentInstance.isObject3D) { // add in the usual parent-child way parentInstance.add(child) added = true } // This is for anything that used attach, and for non-Object3Ds that don't get attached to props; // that is, anything that's a child in React but not a child in the scenegraph. if (!added) parentInstance.__r3f?.objects.push(child) if (!child.__r3f) prepare(child, {}) child.__r3f.parent = parentInstance updateInstance(child) invalidateInstance(child) } }
通过 attach 来决定 child 是其父节点属性或者 children,并更新实例。
applyProps
创建好 instance 之后调用
applyProps
函数,该函数将传入的属性应用到新实例上。这个函数处理设置属性、添加事件监听器、管理引用等switchInstance
在 Reconciler 中存在
commitUpdate
,当需要重建节点时,会调用 switchInstance
,依据最新的 props 来生成最新的 instance,并将 r3f
子结构重新构建为新的节点 children。并删除旧结点,同时重新绑定事件。一旦实例被创建和初始化,它就可以被插入到场景图中,并且其生命周期可以由调和器的其他方法(appendChild、removeChild 等)根据 React 调和器定义的 diffing 和更新过程来管理。