Threejs 开发技巧

本文介绍了在使用Three.js进行3D开发时的一系列性能优化建议,包括性能监控、避免频繁操作Lights、阴影设置、纹理优化、顶点动画处理、共享几何体和合并drawcalls,以及从Blender导出模型的注意事项,旨在提升WebGL应用程序的性能。
摘要由CSDN通过智能技术生成

1. 性能监控

yarn add stats.js

代码:


import Stats from "stats.js";

const stats = new Stats();
stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom
document.body.appendChild(stats.dom);

const update = () => {
  stats.begin();

  // ...

  stats.end();
};

2. 渲染信息 

console.log(renderer.info);

3. 释放删除mesh 


scene.remove(cube);
cube.geometry.dispose();
cube.material.dispose();

4. 尽量避免使用Threejs 的Lights

可以使用烘焙的灯光或者自带的AmbientLight, DirectionalLight

5. 不要动态添加或者删除灯光

如果添加或者删除灯光,所有相关的材质都将重新编译。

6. 少用阴影,可以用烘培的阴影替代。 

7. 优化阴影的方式:

使用Cambera Helper调试来减少的最小区域。


directionalLight.shadow.camera.top = 3;
directionalLight.shadow.camera.right = 6;
directionalLight.shadow.camera.left = -6;
directionalLight.shadow.camera.bottom = -3;
directionalLight.shadow.camera.far = 10;

const cameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera);
scene.add(cameraHelper);

// Make sure to use the smallest possible resolution with descent result for the mapSize
directionalLight.shadow.mapSize.set(1024, 1024);

8.  castShadow 和receiveShadow的使用情况 


//if there's nothing surrounding the sphere, then it doesn't need to receive any shadow
sphere.castShadow = true;
sphere.receiveShadow = false;
//floor doesn't need to cast shadow since it's the floor :) and nothing under them
floor.castShadow = false;
floor.receiveShadow = true;

9. 让阴影自动更新 


renderer.shadowMap.autoUpdate = false;
renderer.shadowMap.needsUpdate = true;

10. 贴图 Textures 

尽量小,保证2的平方大小

11.  不更新顶点

如果需要顶点动画,在顶点着色器里进行。

12.  共享集合体

const geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);

for (let i = 0; i < 50; i++) {
  const material = new THREE.MeshNormalMaterial();

  const mesh = new THREE.Mesh(geometry, material);
  mesh.position.x = (Math.random() - 0.5) * 10;
  mesh.position.y = (Math.random() - 0.5) * 10;
  mesh.position.z = (Math.random() - 0.5) * 10;
  mesh.rotation.y = (Math.random() - 0.5) * Math.PI * 2;
  mesh.rotation.z = (Math.random() - 0.5) * Math.PI * 2;

  scene.add(mesh);
}

13. 合并几何体为一个draw call 


import * as BufferGeometryUtils from "three/examples/jsm/utils/BufferGeometryUtils.js";

// ...
const geometries = [];
for (let i = 0; i < 50; i++) {
  const geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);

  geometry.rotateX((Math.random() - 0.5) * Math.PI * 2);
  geometry.rotateY((Math.random() - 0.5) * Math.PI * 2);

  geometry.translate(
    (Math.random() - 0.5) * 10,
    (Math.random() - 0.5) * 10,
    (Math.random() - 0.5) * 10
  );

  geometries.push(geometry);
}

const mergedGeometry = BufferGeometryUtils.mergeBufferGeometries(geometries);
console.log(mergedGeometry);

const material = new THREE.MeshNormalMaterial();

const mesh = new THREE.Mesh(mergedGeometry, material);
scene.add(mesh);

14. 材质 


const geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);

const material = new THREE.MeshNormalMaterial();

for (let i = 0; i < 50; i++) {
  const mesh = new THREE.Mesh(geometry, material);
  mesh.position.x = (Math.random() - 0.5) * 10;
  mesh.position.y = (Math.random() - 0.5) * 10;
  mesh.position.z = (Math.random() - 0.5) * 10;
  mesh.rotation.x = (Math.random() - 0.5) * Math.PI * 2;
  mesh.rotation.y = (Math.random() - 0.5) * Math.PI * 2;

  scene.add(mesh);
}

15. 使用材质类型 

MeshBasicMaterial, MeshLamberMaterial, MeshPhongMaterial

16. 网格Meshes 

实例化网格,需要为每个实例创建一个矩阵 

const geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);

const material = new THREE.MeshNormalMaterial();

const mesh = new THREE.InstancedMesh(geometry, material, 50);
scene.add(mesh);

for (let i = 0; i < 50; i++) {
  const position = new THREE.Vector3(
    (Math.random() - 0.5) * 10,
    (Math.random() - 0.5) * 10,
    (Math.random() - 0.5) * 10
  );

  const quaternion = new THREE.Quaternion();
  quaternion.setFromEuler(
    new THREE.Euler(
      (Math.random() - 0.5) * Math.PI * 2,
      (Math.random() - 0.5) * Math.PI * 2,
      0
    )
  );

  const matrix = new THREE.Matrix4();
  matrix.makeRotationFromQuaternion(quaternion);
  matrix.setPosition(position);

  mesh.setMatrixAt(i, matrix);
}

const tick = () => {
  //...

  //add this to change matrices after frames.
  mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
};

17.  从Blender 导出

当把模型进行UV拆分的时候,删除隐藏的面,并应用缩放。

选择所有mesh并按crtl+j合并为一个mesh

18. 着色器Shader:

如果变量不需要改变,我们使用全局定义代替在uniforms定义。

在顶点着色器中,这样定义:

#define uDisplacementStrength 1.5
//或者
const shaderMaterial = new THREE.ShaderMaterial({

    // ...

    defines:
    {
        uDisplacementStrength: 1.5
    },

    // ...

19. 着色器中尽量不用Perlin noise,会影响性能,除非用在动画中。可以使用texture2D()代替。

20. 着色器代码中尽量避免使用if语句,用 clamp代替

modelPosition.y += clamp(elevation, 0.5, 1.0) * uDisplacementStrength;

  • 11
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

布达拉三世

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值