Three.js海量渲染模型

使用BatchedMesh渲染海量树模型,帧率接近60,页面流畅

批处理网格(BatchedMesh)

此处为官方文档的解释

Mesh 的特殊版本,支持多绘制批量渲染。如果您必须渲染大量具有相同材质但具有不同世界变换和几何形状的对象,请使用 BatchedMesh。使用 BatchedMesh 将帮助您减少绘制调用的数量,从而提高应用程序的整体渲染性能。

构造函数

less 复制代码
BatchedMesh( maxInstanceCount : Integer, maxVertexCount : Integer, maxIndexCount : Integer, material : Material, )
// 参数
maxInstanceCount - 计划添加的单个几何体的最大数量。
maxVertexCount - 所有几何体使用的最大顶点数。
maxIndexCount - 所有几何图形使用的最大索引数。
material - Material 的一个实例。默认是新的 MeshBasicMaterial。

BatchedMesh官方文档

核心代码

"three": "^0.178.0"

node版本 v18.12.0

ini 复制代码
// 加载模型
async initModel() {
  store.setProgress({ value: 80, status: true });

  // **2. 并行加载其他模型**
  const models = await Promise.all([
      this.PIModel.initFbx('model/yichang'),
      this.PIModel.initFbx('model/sphere'),
      this.PIModel.initFbx('model/shu1'),
      this.PIModel.initFbx('model/shu2'),
  ]);

  // **3. 处理加载完成的模型**
  const [yichang, sphere, tree1, shu] = models;

  yichang.children[0].material.transparent = true
  this.scene.add(yichang)
  this.helper.initWater();

  let pos = []
  let pos1 = []
  // sphere.traverse(ch => {
  //   if (ch.isMesh) {
  //     if (ch.name.includes('Sphere')) {
  //       pos.push(ch.position)
  //     } else if (ch.name.includes('Box')) {
  //       pos1.push(ch.position)
  //     }
  //     // const geometry = new THREE.BoxGeometry( 10, 10, 20 );
  //     // const material = new THREE.MeshBasicMaterial( {color: 0x00ffff} );
  //     // const cube = new THREE.Mesh( geometry, material );
  //     // cube.position.set(ch.position.x, ch.position.y, ch.position.z)
  //     // this.scene.add( cube );
  //   }
  // })
  for (let i = 0; i < 1000; i++) {
    const x = (Math.random() * 10000) - 5000
    const y = -60
    const z = (Math.random() * 10000) - 5000
    pos.push({ x, y, z })
  }
  for (let i = 0; i < 500; i++) {
    const x = Math.random() * 10000 - 5000
    const y = -60
    const z = Math.random() * 10000 - 5000
    pos1.push({ x, y, z })
  }
  this.pos = pos
  this.pos1 = pos1

  // this.scene.add(tree1)
  // this.scene.add(shu)
  // console.log(tree1)

  let originModel = []
  tree1.traverse(child => {
    if (child.isMesh) {
      child.castShadow = true
      child.material.transparent = true
      child.material.side = THREE.DoubleSide
      child.material.alphaTest = 0.65
      if (child.name === 'leaves') {
        child.material.color.set(0x3F5B2D)
        child.material.emissive.set(0x3F5B2D)
      } else if (child.name === 'branch') {
        child.material.color.set(0x443d3b)
        child.material.emissive.set(0x443d3b)
      }
      child.material.emissiveIntensity = 1
      child.material.emissiveMap = child.material.map

      originModel.push(child)
    }
  })
  let originModel2 = []
  shu.traverse(child => {
    if (child.isMesh) {
      child.castShadow = true
      child.material.transparent = true
      child.material.alphaTest = 0.7
      child.material.side = THREE.DoubleSide
      child.material.emissiveIntensity = 1
      child.material.emissiveMap = child.material.map

      originModel2.push(child)
    }
  })

  let dummy = new THREE.Object3D();
  let scales = {}

  const drawModel = (len, len1, model, pos, scaleC, rotation) => {
    const geometry = model.geometry.clone();
    // geometry.applyMatrix4(model.matrixWorld);
    const mesh = new THREE.BatchedMesh( len, len1 * 2048, len1 * 2048, model.material.clone() )
    const id = mesh.addGeometry(geometry)
    getInstance(len, mesh, scaleC, pos, id, rotation)
    // mesh.matrixWorldNeedsUpdate = true
    this.scene.add( mesh );
  }
  originModel.forEach(model => {
    drawModel(this.pos.length, originModel.length, model, this.pos, model.scale, { x: -Math.PI / 2 })
  })
  originModel2.forEach(model => {
    drawModel(this.pos1.length, originModel2.length, model, this.pos1, model.scale, { x: -Math.PI / 2 })
  })

  function getInstance(len, mesh, scaleC, pos1, index, rotation = {}) {
    for ( let i = 0; i < len; i ++ ) {

      const id = mesh.addInstance( index );
      const pos = pos1[i]
      const scale = scales[id] || Math.random() * 0.6 + 0.5;
      dummy.position.x = pos.x;
      dummy.position.y = pos.y - 15;
      dummy.position.z = pos.z;
      dummy.rotation.x = rotation.x || 0
      dummy.rotation.y = rotation.y || 0
      dummy.rotation.z = rotation.z || 0

      if (!scales[id]) {
        scales[id] = scale
      }
      dummy.scale.x = scaleC.x * scale
      dummy.scale.y = scaleC.y * scale
      dummy.scale.z = scaleC.z * scale

      dummy.updateMatrix();
      mesh.setMatrixAt(id, dummy.matrix)
    }
  }
  store.setProgress({ value: 100, status: false });
}

github源码

相关推荐
sorryhc1 分钟前
【AI解读源码系列】ant design mobile——Avatar头像
前端·javascript·react.js
Mintopia9 分钟前
🎭 一场浏览器里的文艺复兴
前端·javascript·aigc
Mintopia9 分钟前
🎬《Next 全栈 CRUD 的百老汇》
前端·后端·next.js
AryaNimbus24 分钟前
你不知道的Cursor系列:如何使用Cursor同时开发多项目?
前端·ai编程·cursor
国家不保护废物28 分钟前
Function Call与MCP:给AI插上连接现实的翅膀
前端·aigc·openai
500佰29 分钟前
阿里Qoder AI 新开发工具,长期记忆、Wiki和Quest模式是它的独有特性
前端
Juchecar30 分钟前
Vue3 Class 和 Style 绑定详解
前端·vue.js
coding随想31 分钟前
揭秘DOM键盘事件:从基础到高级技巧全解析!
前端
xianxin_33 分钟前
CSS Position(定位)
前端
xianxin_33 分钟前
CSS Float(浮动)
前端