typescript 使用React-Three-Fiber的示例网格多次渲染一个GRTF模型

8i9zcol2  于 2023-04-13  发布在  TypeScript
关注(0)|答案(1)|浏览(194)

我有一个3d gltf模型,我想渲染多次,可能是100K,但这会导致性能滞后,因为多个绘制调用。我如何使用示例网格在单个绘制调用中做到这一点,同时还能够向每个渲染模型发送颜色 prop 。
我使用下面的代码。

# Model.tsx

import * as THREE from 'three'
import { useGLTF } from '@react-three/drei'
import { GroupProps } from '@react-three/fiber'
import { GLTF } from 'three-stdlib'

type GLTFResult = GLTF & {
  nodes: {
    Cylinder: THREE.Mesh
    Cylinder_1: THREE.Mesh
    Cylinder_2: THREE.Mesh
  }
  materials: {
    Floor: THREE.MeshStandardMaterial
    Glass: THREE.MeshPhysicalMaterial
    Metal: THREE.MeshStandardMaterial
  }
}

export type Props = {
  color: string
  windowsTint: string
}

const Model = ({ color, windowsTint, ...props }: GroupProps & Props) => {
  const { nodes, materials } = useGLTF('./3d/room.gltf') as GLTFResult
  return (
    <group {...props} dispose={null}>
      <mesh castShadow receiveShadow geometry={nodes.Cylinder.geometry}>
        <meshStandardMaterial
          color={color}
          roughness={0.6}
          metalness={0.3}
          side={THREE.DoubleSide}
        />
      </mesh>
      <mesh castShadow receiveShadow geometry={nodes.Cylinder_1.geometry}>
        <meshPhongMaterial color={windowsTint} transparent opacity={0.7} side={THREE.DoubleSide} />
      </mesh>
      <mesh
        castShadow
        receiveShadow
        geometry={nodes.Cylinder_2.geometry}
        material={materials.Metal}
      >
        <meshStandardMaterial metalness={0.8} roughness={0.4} color='#888888' />
      </mesh>
    </group>
  )
}

useGLTF.preload('./3d/room.gltf')
export default Model

这就是我目前渲染1000个示例的方式

#App.tsx

const rooms = [
    ...
    {color: '#f7f7f7', windowTint: 0.9}
]
....

            {rooms.map((room, idx) => {
                return (
                  <Model
                    position={[0, idx * 2, 0]}
                    rotation={[0, Math.PI * 0.08 * idx, 0]}
                    key={`_RL${idx}`}
                    color={room.color}
                    windowsTint={room.windowTint}
                  />
                )
              })}

....
bq3bfh9z

bq3bfh9z1#

首先,确保所有的转换,如位置或旋转应用于几何体。组或网格不能有这样的转换。
第二,用InstancedMesh替换所有的网格,并为每个InstancedMesh添加相同的变换。

import { Color, InstancedMesh, Matrix4 } from 'three';

export class InstancedMeshGroup {
    children: InstancedMesh<any, any>[] = [];

    add(...object: InstancedMesh<any, any>[]): this {
        this.children.push(...object);
        return this;
    }

    setMatrixAt(index: number, matrix: Matrix4) {
        this.children.forEach((child) => child.setMatrixAt(index, matrix));
    }

    setColorAt(index: number, color: Color) {
        this.children.forEach((child) => child.setColorAt(index, color));
    }

    instanceMatrixNeedsUpdate() {
        this.children.forEach((child) => (child.instanceMatrix.needsUpdate = true));
    }

    instanceColorNeedsUpdate() {
        this.children.forEach((child) => {
            if (child.instanceColor) {
                child.instanceColor.needsUpdate = true;
            }
        });
    }
}

为了使这种操作更容易,我创建了一个工具来将模型导出为一组InstancedMesh
https://webgl-opti.web.app/app
我的应用程序还有助于在导出为代码之前优化模型

相关问题