在我的应用程序中,我想向加载的 .obj 模型添加纹理。我的 .fbx 加载模型也有同样的情况。下面是我的示例代码,但这仅适用于 sphereGeometry 等内容,不适用于加载的模型。
提前致谢!
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'
import { useTexture } from '@react-three/drei'
const OBJModel = ({ file }: { file: string }) => {
const obj = useLoader(OBJLoader, file)
const texture = useTexture(textureFile)
return (
<mesh>
<primitive object={obj} />
<meshStandardMaterial map={texture} attach="material" />
</mesh>
)
}
primitive
不是网格的子集。它可以是 group
的子级。primitive
需要几何形状和材料作为道具。 Mesh
需要几何体和材质作为道具。很明显两者不能用作彼此的子集。Mesh
或 primitive
。我建议使用 Mesh
,它有丰富的文档。 primitive
记录不够。OBJ
获得的
useLoader
内部可能有复杂的基团。模型通常包含较大的集合,例如
group
或
scene
。组和场景不能有纹理。
Mesh
可以。
OBJ(result of useLoader) = scene => group => mesh => geometry, texture
需要遍历才能从网格中获取几何图形。
// I've implemented this with Typescript,
// but it is not necessary to use 'as' for type conversion.
const obj = useLoader(OBJLoader, "/rock.obj");
const texture = useTexture("/guide.png");
const geometry = useMemo(() => {
let g;
obj.traverse((c) => {
if (c.type === "Mesh") {
const _c = c as Mesh;
g = _c.geometry;
}
});
return g;
}, [obj]);
// I've used meshPhysicalMaterial because the texture needs lights to be seen properly.
return (
<mesh geometry={geometry} scale={0.04}>
<meshPhysicalMaterial map={texture} />
</mesh>
);
我已经在codesandbox中实现了它。这是工作代码:
https://codesandbox.io/s/crazy-dawn-i6vzb?file=/src/components/Rock.tsx:257-550
有三种可能的解决方案:
const OBJModel = ({ file, textureFile, ...props }) => {
const obj = useLoader(OBJLoader, file)
const texture = useTexture(textureFile)
useEffect(() => {
obj.traverse(child => {
if (child.type === 'Mesh') child.material.map = texture
})
}, [obj])
return <primitive object={obj} {...props} />
}
可以与类似的东西一起使用
<OBJModel file='./a.obj' textureFile='./a.png' position-z={10} />