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;