React 三纤维为 obj 模型添加纹理

问题描述 投票:0回答:3

在我的应用程序中,我想向加载的 .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>
  )
}
reactjs three.js react-three-fiber
3个回答
8
投票
  1. primitive
    不是网格的子集。它可以是
    group
    的子级。
  2. primitive
    需要几何形状和材料作为道具
    Mesh
    需要几何体和材质作为道具。很明显两者不能用作彼此的子集。
  3. 要实现您的想法,您只需使用一个
    Mesh
    primitive
    。我建议使用
    Mesh
    ,它有丰富的文档。
    primitive
    记录不够。
  4. 通过
  5. 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


2
投票
我相信 obj 加载器返回一个组或一个网格,将其放入顶级网格中是没有意义的,并且为顶级提供纹理不会更改加载的 obj 网格。

有三种可能的解决方案:

    使用 obj.traverse(...) 并通过突变来改变模型,这就是人们在香草三中所做的,这是有问题的,因为突变是不好的,你正在破坏源数据,并且你将无法重新 -使用模型
  1. 我建议将您的模型转换为 gltf,然后您可以使用 gltfjsx
  2. https://github.com/pmndrs/gltfjsx 它可以以声明方式布局完整模型。点击视频,这就是你想要的
  3. 如果您必须使用 obj 文件,您可以手动创建声明性图表。有一个钩子可以为您提供 { 节点,材料 }
  4. https://docs.pmnd.rs/react- Three-Fiber/API/hooks#use-graph

0
投票
我刚刚想出了这样的东西,希望对你也有用,

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} />
    
© www.soinside.com 2019 - 2024. All rights reserved.