掘金 人工智能 前天 12:46
Three.js实例化技术:高效渲染数千3D对象
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文深入探讨了Three.js中的实例化技术,特别是在React Three Fiber框架下的应用。通过实例演示,说明了如何利用实例化技术将成千上万个共享相同几何体和材质的3D对象通过单次绘制调用高效渲染,从而显著提升性能。文章介绍了基础实例化用法、多组实例管理以及如何为自定义着色器添加实例支持,并以创建森林场景为例,展示了实例化如何将绘制调用从数千次减少到仅三次。这对于构建复杂、高性能的3D场景至关重要。

✨ **实例化技术优化性能:** 实例化是一种关键的性能优化手段,它允许一次性渲染大量具有相同几何体和材质的对象。通过将多个对象的绘制指令合并为一个,大大减少了CPU到GPU的绘制调用次数,从而显著提升3D场景的渲染效率,特别适用于渲染如森林、城市等包含大量重复元素的场景。

📦 **React Three Fiber快速实现:** 在React Three Fiber框架中,可以使用`@react-three/drei`库中的`Instances`和`Instance`组件来轻松实现实例化。只需将共享的几何体和材质包裹在`Instances`中,然后为每个要渲染的对象使用`Instance`组件并指定其位置、缩放等属性,即可实现高效渲染。

🌲 **多组实例与自定义着色器:** 对于包含不同类型重复对象的复杂场景(如森林),可以创建多个`Instances`组来分别管理。此外,文章还展示了如何为自定义着色器(如使用`RawShaderMaterial`)添加实例支持,通过在着色器中处理`instanceMatrix`等属性,实现更灵活的顶点动画和效果。

🌳 **实际场景优化案例:** 通过一个创建森林场景的例子,文章清晰地展示了实例化技术的强大之处。一个包含一千棵树的模型,在应用实例化后,整个森林场景仅通过三次绘制调用(天空盒、地面、所有树木)即可完成渲染,相比传统方式的成千上万次绘制调用,性能提升巨大。

Three.js实例化技术:同时渲染多个3D对象

学习如何使用React Three Fiber中的实例化技术高效渲染数千个3D对象,正如性能优化的basement.studio网站所展示的那样。

引言

实例化是一种性能优化技术,允许你同时渲染共享相同几何体和材质的多个对象。如果需要渲染森林场景,你会需要大量的树木、岩石和草地。如果它们共享相同的基础网格和材质,你就可以通过单次绘制调用渲染所有对象。

绘制调用是CPU向GPU发出的绘制指令,比如绘制一个网格。每个独特的几何体或材质通常需要自己的调用。过多的绘制调用会损害性能。实例化通过将多个副本批量处理为一个来减少这种情况。

基础实例化

让我们从一个传统方式渲染一千个方块的例子开始:

const boxCount = 1000function Scene() {  return (    <>      {Array.from({ length: boxCount }).map((_, index) => (        <mesh          key={index}          position={getRandomPosition()}          scale={getRandomScale()}        >          <boxGeometry />          <meshBasicMaterial color={getRandomColor()} />        </mesh>      ))}    </>  )}

查看示例 | 源代码

如果添加性能监视器,会发现"calls"数量与boxCount匹配。

使用drei/instances可以快速实现实例化:

import { Instance, Instances } from "@react-three/drei"const boxCount = 1000function Scene() {  return (    <Instances limit={boxCount}>      <boxGeometry />      <meshBasicMaterial />      {Array.from({ length: boxCount }).map((_, index) => (        <Instance          key={index}          position={getRandomPosition()}          scale={getRandomScale()}          color={getRandomColor()}        />      ))}    </Instances>  )}

现在"calls"减少到1,即使我们显示了一千个方块。

多组实例

要渲染森林场景,可能需要不同的实例组:

import { createInstances } from "@react-three/drei"const boxCount = 1000const sphereCount = 1000const [CubeInstances, Cube] = createInstances()const [SphereInstances, Sphere] = createInstances()function InstancesProvider({ children }: { children: React.ReactNode }) {  return (    <CubeInstances limit={boxCount}>      <boxGeometry />      <meshBasicMaterial />      <SphereInstances limit={sphereCount}>        <sphereGeometry />        <meshBasicMaterial />        {children}      </SphereInstances>    </CubeInstances>  )}

自定义着色器实例

要为自定义着色器添加实例支持:

const baseMaterial = new THREE.RawShaderMaterial({  vertexShader: /*glsl*/ `    attribute vec3 position;    attribute vec3 instanceColor;    attribute vec3 normal;    attribute vec2 uv;    uniform mat4 modelMatrix;    uniform mat4 viewMatrix;    uniform mat4 projectionMatrix;    attribute mat4 instanceMatrix;    uniform float uTime;    uniform float uAmplitude;    vec3 movement(vec3 position) {      vec3 pos = position;      pos.x += sin(position.y + uTime) * uAmplitude;      return pos;    }    void main() {      vec3 blobShift = movement(position);      vec4 modelPosition = modelMatrix * instanceMatrix * vec4(blobShift, 1.0);      vec4 viewPosition = viewMatrix * modelPosition;      vec4 projectionPosition = projectionMatrix * viewPosition;      gl_Position = projectionPosition;    }  `,  fragmentShader: /*glsl*/ `    void main() {      gl_FragColor = vec4(1, 0, 0, 1);    }  `})

创建森林场景

使用实例化网格创建森林场景:

const [TreeInstances, Tree] = createInstances()const treeCount = 1000function Scene() {  const { scene, nodes } = useGLTF(    "/stylized_pine_tree_tree.glb"  ) as unknown as TreeGltf  return (    <group>      <TreeInstances        limit={treeCount}        scale={0.02}        geometry={nodes.tree_low001_StylizedTree_0.geometry}        material={nodes.tree_low001_StylizedTree_0.material}      >        {Array.from({ length: treeCount }).map((_, index) => (          <Tree key={index} position={getRandomPosition()} />        ))}      </TreeInstances>    </group>  )}

整个森林仅用三次绘制调用渲染:天空盒一次,地面平面一次,所有树木一次。

延伸阅读

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Three.js 实例化 React Three Fiber 性能优化 3D渲染
相关文章