如何从 useFBX 渲染多个模型? @react-three/drei
How to render multiple models from useFBX? @react-three/drei
我正在尝试使用 @react-three/drei
中的 useFBX
显示多个组件。虽然我调用了两次该函数,但我在场景中只得到了一个组件。
我有以下代码在场景中渲染一棵树
import { useBox } from "@react-three/cannon";
import { useFBX } from "@react-three/drei";
import React, { Suspense } from "react";
const Trees = (props) => {
const [ref] = useBox(() => ({
mass: 1,
type: "Static",
...props,
}));
let fbx = useFBX(props.fbx);
return (
<Suspense fallback={null}>
<mesh ref={ref} scale={props.scale} position={props.position}>
<primitive object={fbx} dispose={null} />
</mesh>
</Suspense>
);
};
export default Trees;
我正在另一个文件中调用该函数
import React from "react";
import Trees from "./Trees";
const TreeDisplay = () => {
return (
<>
<Trees
fbx="/FBX/Tree1.fbx"
position={[10, 0, 20]}
scale={[0.01, 0.01, 0.01]}
/>
<Trees
fbx="/FBX/Tree1.fbx"
position={[20, 0, 0]}
scale={[0.01, 0.01, 0.01]}
/>
</>
);
};
export default TreeDisplay;
上面的函数必须在场景中的定义位置添加两棵树,但我只得到一棵树。
在 javascript 中,当您使用一个对象时,您使用的是它的直接引用,因此您需要复制该对象:
let fbx = useFBX(props.fbx);
let fbxClone = {...fbx};
还有一个 object3D.clone() 函数在这种情况下可能会有用:
let fbxClone = fbx.clone();
除此之外,您可能还想使用 javascript .map 函数,如果您获得一个对象数组,您可以从中创建一个组件数组。
let mytrees = [];
for(let i = 0;i<1000; i++)
mytrees.push(fbx.clone());
return (<>{mytrees.map((tree)=>{return <instancedMesh material={tree.material}
geometry={tree.geometry} />})}</>)
这是一个完整的代码(带有 gltfloader,但它应该以与 fbx 相同的方式工作):
import React, { useRef, useState, useMemo, Suspense, useEffect, memo } from 'react'
import { Canvas, useFrame, useLoader, extend, useThree } from '@react-three/fiber'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"
import * as THREE from 'three'
const Trees = memo((props) => {
let listOfRefs = [];
const tempObject = new THREE.Object3D();
let treeTypes = ["three_1"];
let loadedTrees = [];
let trees = [];
for(let cur of treeTypes)
{
loadedTrees.push(Object.values(useLoader(GLTFLoader, cur+'.glb',(loader) => {
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("/draco-gltf/");
loader.setDRACOLoader(dracoLoader);
}).nodes).filter(m=>{return (m instanceof THREE.Mesh)})
.map(m=>{return (<instancedMesh material={m.material}
geometry={m.geometry}
key={cur+""+Math.floor(Math.random()*10000)}
count={props.amount}
ref={(()=>{
listOfRefs.push(useRef());
return listOfRefs[listOfRefs.length-1];
})()}
args={[null,null,props.amount]} />)}));
}
useEffect(()=>{
if (listOfRefs.length < 1) return;
let i = 0;
for(let c = 0;c<props.amount;c++)
{
let currentPosition = [ Math.round(Math.random())?(Math.random()*props.halfSize):-(Math.random()*props.halfSize),
13.75 ,
Math.round(Math.random())?(Math.random()*props.halfSize):-(Math.random()*props.halfSize)];
let currentRotation = [0,(Math.round(Math.random())*Math.PI/2),0]
for(let curRef of listOfRefs) {
const id = i++;
tempObject.position.set(currentPosition[0],currentPosition[1],currentPosition[2])
tempObject.rotation.set(currentRotation[0],currentRotation[1],currentRotation[2]);
tempObject.updateMatrix();
curRef.current.setMatrixAt(id, tempObject.matrix);
}
}
for(let curRef of listOfRefs)
curRef.current.instanceMatrix.needsUpdate = true;
})
return (
<group>
{loadedTrees[Math.floor(Math.random()*loadedTrees.length)]}
</group>
);
})
export default Trees;
另一个建议是使用此处建议的 instancedMesh :
https://threejs.org/docs/index.html?q=instanced#api/en/objects/InstancedMesh
它作为反应三纤维成分存在
<instancedMesh />
问题出在 fbx 上,克隆 fbx 模型即可完成工作。
import { useBox } from "@react-three/cannon";
import { Loader, useFBX } from "@react-three/drei";
import React, { Suspense } from "react";
const Trees = (props) => {
const [ref] = useBox(() => ({
mass: 1,
type: "Static",
...props,
}));
let fbx = useFBX(props.fbx);
//Add this line
let fbxClone = fbx.clone();
return (
<Suspense fallback={<Loader />}>
<mesh ref={ref} scale={props.scale} material-reflectivity={1}>
//pass the cloned object
<primitive object={fbxClone} dispose={null} />
</mesh>
</Suspense>
);
};
export default Trees;
我正在尝试使用 @react-three/drei
中的 useFBX
显示多个组件。虽然我调用了两次该函数,但我在场景中只得到了一个组件。
我有以下代码在场景中渲染一棵树
import { useBox } from "@react-three/cannon";
import { useFBX } from "@react-three/drei";
import React, { Suspense } from "react";
const Trees = (props) => {
const [ref] = useBox(() => ({
mass: 1,
type: "Static",
...props,
}));
let fbx = useFBX(props.fbx);
return (
<Suspense fallback={null}>
<mesh ref={ref} scale={props.scale} position={props.position}>
<primitive object={fbx} dispose={null} />
</mesh>
</Suspense>
);
};
export default Trees;
我正在另一个文件中调用该函数
import React from "react";
import Trees from "./Trees";
const TreeDisplay = () => {
return (
<>
<Trees
fbx="/FBX/Tree1.fbx"
position={[10, 0, 20]}
scale={[0.01, 0.01, 0.01]}
/>
<Trees
fbx="/FBX/Tree1.fbx"
position={[20, 0, 0]}
scale={[0.01, 0.01, 0.01]}
/>
</>
);
};
export default TreeDisplay;
上面的函数必须在场景中的定义位置添加两棵树,但我只得到一棵树。
在 javascript 中,当您使用一个对象时,您使用的是它的直接引用,因此您需要复制该对象:
let fbx = useFBX(props.fbx);
let fbxClone = {...fbx};
还有一个 object3D.clone() 函数在这种情况下可能会有用:
let fbxClone = fbx.clone();
除此之外,您可能还想使用 javascript .map 函数,如果您获得一个对象数组,您可以从中创建一个组件数组。
let mytrees = [];
for(let i = 0;i<1000; i++)
mytrees.push(fbx.clone());
return (<>{mytrees.map((tree)=>{return <instancedMesh material={tree.material}
geometry={tree.geometry} />})}</>)
这是一个完整的代码(带有 gltfloader,但它应该以与 fbx 相同的方式工作):
import React, { useRef, useState, useMemo, Suspense, useEffect, memo } from 'react'
import { Canvas, useFrame, useLoader, extend, useThree } from '@react-three/fiber'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"
import * as THREE from 'three'
const Trees = memo((props) => {
let listOfRefs = [];
const tempObject = new THREE.Object3D();
let treeTypes = ["three_1"];
let loadedTrees = [];
let trees = [];
for(let cur of treeTypes)
{
loadedTrees.push(Object.values(useLoader(GLTFLoader, cur+'.glb',(loader) => {
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("/draco-gltf/");
loader.setDRACOLoader(dracoLoader);
}).nodes).filter(m=>{return (m instanceof THREE.Mesh)})
.map(m=>{return (<instancedMesh material={m.material}
geometry={m.geometry}
key={cur+""+Math.floor(Math.random()*10000)}
count={props.amount}
ref={(()=>{
listOfRefs.push(useRef());
return listOfRefs[listOfRefs.length-1];
})()}
args={[null,null,props.amount]} />)}));
}
useEffect(()=>{
if (listOfRefs.length < 1) return;
let i = 0;
for(let c = 0;c<props.amount;c++)
{
let currentPosition = [ Math.round(Math.random())?(Math.random()*props.halfSize):-(Math.random()*props.halfSize),
13.75 ,
Math.round(Math.random())?(Math.random()*props.halfSize):-(Math.random()*props.halfSize)];
let currentRotation = [0,(Math.round(Math.random())*Math.PI/2),0]
for(let curRef of listOfRefs) {
const id = i++;
tempObject.position.set(currentPosition[0],currentPosition[1],currentPosition[2])
tempObject.rotation.set(currentRotation[0],currentRotation[1],currentRotation[2]);
tempObject.updateMatrix();
curRef.current.setMatrixAt(id, tempObject.matrix);
}
}
for(let curRef of listOfRefs)
curRef.current.instanceMatrix.needsUpdate = true;
})
return (
<group>
{loadedTrees[Math.floor(Math.random()*loadedTrees.length)]}
</group>
);
})
export default Trees;
另一个建议是使用此处建议的 instancedMesh : https://threejs.org/docs/index.html?q=instanced#api/en/objects/InstancedMesh 它作为反应三纤维成分存在
<instancedMesh />
问题出在 fbx 上,克隆 fbx 模型即可完成工作。
import { useBox } from "@react-three/cannon";
import { Loader, useFBX } from "@react-three/drei";
import React, { Suspense } from "react";
const Trees = (props) => {
const [ref] = useBox(() => ({
mass: 1,
type: "Static",
...props,
}));
let fbx = useFBX(props.fbx);
//Add this line
let fbxClone = fbx.clone();
return (
<Suspense fallback={<Loader />}>
<mesh ref={ref} scale={props.scale} material-reflectivity={1}>
//pass the cloned object
<primitive object={fbxClone} dispose={null} />
</mesh>
</Suspense>
);
};
export default Trees;