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源码

相关推荐
不断努力的根号七20 分钟前
qt框架,使用webEngine如何调试前端
开发语言·前端·qt
伍哥的传说2 小时前
React性能优化终极指南:memo、useCallback、useMemo全解析
前端·react.js·性能优化·usecallback·usememo·react.memo·react devtools
2301_781668618 小时前
前端基础 JS Vue3 Ajax
前端
上单带刀不带妹9 小时前
前端安全问题怎么解决
前端·安全
Fly-ping9 小时前
【前端】JavaScript 的事件循环 (Event Loop)
开发语言·前端·javascript
SunTecTec9 小时前
IDEA 类上方注释 签名
服务器·前端·intellij-idea
在逃的吗喽10 小时前
黑马头条项目详解
前端·javascript·ajax
袁煦丞10 小时前
有Nextcloud家庭共享不求人:cpolar内网穿透实验室第471个成功挑战
前端·程序员·远程工作
小磊哥er10 小时前
【前端工程化】前端项目开发过程中如何做好通知管理?
前端
拾光拾趣录10 小时前
一次“秒开”变成“转菊花”的线上事故
前端