Wrapper around the gbl/gltf loader that allows handling and customizing only selected nodes in JSX instead of generating the full JSX file.
npm i --save r3f-managed-glb
yarn add r3f-managed-glb
import { ManagedGLB, meshesInNodeByCount, preloadGLB } from 'r3f-managed-glb';
// ....
return <ManagedGLB castShadows recieveShadows path={glb} custom={custom} {...props} />;
interface ManagedGLBProps {
path: string; // path to glb file
custom?: Custom; // structure to customize nodes
onInit?: ({ scene, animations, actions }) => void; // callback on init, provides scene, animations, actions from glb scene
castShadow?: boolean; // set {castShadow} for all meshes (default=true)
receiveShadow?: boolean; // set {receiveShadow} for all meshes (default=true)
debug?: boolean; // console.log the Threejs scene object (default=false)
[key: string]: any; // other props for the root node
}
The render function will called with 2 arguments:
- Node - Node component (Mesh or Group)
- node - threejs node object
You able to override any props of the actual {Node}, set or get variables directly from {node} object or just replace the node with anything you like. Just provide the {custom} prop contains the struct with description of those nodes
type Custom = {
[key: string]: (Node: FC, node: THREE.Object3D) => ReactNode | null;
};
import React from 'react';
import { ManagedGLB, meshesInNodeByCount, preloadGLB } from 'r3f-managed-glb';
import * as THREE from 'three';
const glb = 'assets/model.glb';
export const MyModel = (props) => {
const custom = {
// override material :
['node_001']: (Node, node) => (
<Node>
<meshStandardMaterial transparent opacity={0.1} />
</Node>
),
// or extend material ( you able to add {...node.material} to extend props of existing material)
['node_001']: (Node, node) => (
<Node>
<meshStandardMaterial {...node.material} transparent opacity={0.1} />
</Node>
),
// change scale (position, rotation, etc.):
['node_002']: (Node) => <Node scale={0.1} />,
// remove node:
['node_003']: () => null,
// hide node:
['node_004']: (Node) => <Node visible={false} />,
// several nodes selection
['node_4|node_5|node_6']: (Node) => <Node />,
// you can generate selector with function meshesInNodeByCount('node', 5) //(parentNodeName, children count),
// it returns "node_1|node_2|node_3|node_4|node_5". It useful for meshes splited by glb format
[meshesInNodeByCount('node', 5)]: (Node) => (
<Node>
<meshStandardMaterial transparent opacity={0.1} side={THREE.DoubleSide} />
</Node>
),
// dublicate node:
['node_005']: (Node, node) => {
const pos = [...node.position];
pos[1] += 2;
return (
<>
<Node />
<Node position={pos} />
</>
);
}
// modify the Threejs node object directly (may not good idea):
['node_006']: (Node, node) => {
node.position = [10,10,10]
return <Node />
}
};
return <ManagedGLB castShadows recieveShadows path={glb} custom={custom} {...props} />;
};
preloadGLB(glb); // optional, just useGLTF.preload() function
import { ManagedGLB } from './ManagedGLB';
import React, { useRef } from 'react';
const glb = 'assets/animated_model.glb';
export const Anim = ({ parts, ...props }) => {
const actionsRef = useRef();
const custom = {
['node_001']: (Node) => <Node onClick={() => actionsRef.current['my_action'].play()} />
};
return (
<ManagedGLB
onInit={({ actions }) => (actionsRef.current = actions)}
src={glb}
custom={custom}
{...props}
/>
);
};
git clone [email protected]:dsdevgit/r3f-managed-glb.git
cd r3f-managed-glb
yarn
yarn build