three.js

1.重用Material和Geometry
2.不在render()中实例化或是赋值操作
3.粒子系统代替粒子
4.操作一组对象使用Object3D或group
5.网格合并merge
6.使用Web workers

https://threejs.org/examples/?q=sand#raytracing_sandbox

7.分时加载算法(大数组)
8.延时渲染THREE.DefaultLoadingManager
9.删除模型remove,使用dispose释放几何和材质,RenderTarget,texture
10.BufferGeometry代替Geometry
11.减少浮点计算,写成小数乘法
12.使用clone()方法
13.纹理图片尺寸一定得是2的幂次方,并尽可能的小
14.跳帧设置
15.降低模型的复杂度减少面数
16.使用chrome的插件three.js inspector
17.使用stats.js进行检测帧率
18. JavaScript中的对象创建很昂贵,因此不要在循环中创建对象。相反,创建一个单独的对象,如Vector3,并vector.set()在循环中使用或类似的方法
19.Web浏览器使用的JavaScript引擎经常更改,并在幕后对代码进行了大量优化。不要相信你的直觉会更快,总是测试。不要相信几年前的文章告诉你要避免某些方法,如array.map或array.forEach。自己测试一下。

模型,网格和其他可见的东西

  1. 避免使用常见的基于文本的3D数据格式(如Wavefront OBJ或COLLADA)进行资产交付。相反,请使用针对Web优化的格式,例如glTF
  2. 使用带有glTF的Draco网格压缩
  3. 如果您需要使大组对象可见且不可见(或在场景中添加/删除它们),请考虑使用图层以获得最佳性能
  4. 位于相同位置的物体会导致闪烁。尝试抵消一些微小的东西0.0010 。0 0 1使事物看起来像是在同一个位置,但让你的GPU保持开心
  5. 使场景以原点为中心,以防止在大坐标处出现浮点错误
  6. 切勿移动Scene对象。它创建于(0,0,0)(0 ,0 ,0 ),这是其中所有对象的默认参考框架。
    使您的平截头体尽可能小,以获得更好的性能。在开发中使用大平截头体是很好的,但是一旦你对应用程序进行微调以进行部署,就可以使你的平截头体尽可能小,以获得一些FPS
    不要把东西放在远剪裁平面上(特别是如果你的远剪裁平面真的很大),这可能会导致闪烁
  7. 不要使用TriangleFanDrawMode,它很慢。
  8. 当您有数百或数千个类似的几何时,请使用几何实例化
  9. 在GPU而不是CPU上进行动画处理,尤其是在为顶点或粒子设置动画时(有关此方法的一种方法,请参阅THREE.Bas)

性能

  1. 设置object.matrixAutoUpdate = false 为静态或很少移动的对象,并object.updateMatrix() 在更新其位置/四元数/比例时手动调用
  2. 透明对象很慢,在场景中使用尽​​可能少的透明对象
  3. alphatest如果可能,使用而不是标准透明度,它更快
  4. 在测试应用程序的性能时,您需要做的第一件事就是检查它是受CPU限制还是GPU绑定。使用基本材料替换所有材料scene.overrideMaterial(请参阅初学者提示和页面开头)。如果性能提高,那么您的应用就是GPU限制。
  5. 在快速机器上进行性能测试时,您可能会获得60fps的最大帧速率。使用open -a "Google Chrome" --args --disable-gpu-vsyncfo run 无限帧率运行chrome
  6. 现代移动设备具有高的像素比率 5 - 考虑在这些设备上将最大像素比率限制为2或3,但会牺牲一些非常轻微的场景模糊
  7. 烘焙光照和阴影贴图以减少场景中的灯光数量
  8. 如果您有资源和时间,请使用压缩纹理。不幸的是,为网络设置这些内容是一件很痛苦的事情,因为所有设备都不支持任何格式
  9. 密切关注场景中的drawcalls数量。一个好的经验法则是减少绘制调用=更好的性能
  10. 远处的物体不需要与靠近相机的物体具有相同的细节水平。有许多技巧用于通过降低远处物体的质量来提高性能。例如,LOD(细节级别)对象存储不同距离的不同对象(例如,近,中和远)。您也可能只为远处的物体每隔2帧或3帧更新位置/动画
    尽可能减少多重计数。请记住,模型根本不应该过于详细。

将Obj文件转换为Json和/或为场景中的每个对象创建单独的JSON文件。请记住,geometry是您尝试加载的文件中最重的数据块。因此,如果可能,BufferGeometry为每个文件创建单独的文件并通过它加载BufferGeometryLoader

在加载所有js和json文件之前,您可以使用一些压缩/解压缩技术。查看OpenCTM压缩。您也可以尝试gzip您的文件并对其进行放气。

在创建网格的3d建模阶段,合并尽可能多的几何。最简单的方法是识别具有相同/相似材料的所有网格,合并这些几何,并为这些几何分配相同的材质。您拥有的几何数量越少,渲染管道中绘制调用的次数就越少。因此,您的表现将会提高。

您可以跟踪您的drawcalls使用情况renderer.info

保持纹理文件大小较低的分辨率。我一般建议少于1K。

材料性能成本是这样的MeshBasicMaterial< MeshLambertMaterial< MeshPhongMaterial< MeshStandardMaterial< MeshPhysicalMaterial。在将材质指定给几何体时要小心。Threejs doc清楚地说明了每种材料的所有特征。因此,如果您知道对象不需要材料的某些属性,则回退到更便宜的材质。

使用normalMaps伪造的goemetries。这将减少您vertices所需的数量。

如果您的场景是静态使用aoMap并且LightMap在场景中消除了对光源的需求及其计算成本。

如果场景是静态的,请停止requestAnimationFrame并仅在需要时渲染。例。如果您使用的是orbitcontrol.js,请onChange在触发用户活动时使用方法进行渲染。

使用Chrome扩展程序,如Threejs Inspector和WebGL Inspector进行调试。

如果动态删除场景中的任何内容,请确保正确处理数据。

300 MB的文件非常大。确保将其减少到30 mb或更低,理想情况下,低于10 mb以获得最佳体验。
从场景中删除一些东西?

首先,考虑不这样做,特别是如果你稍后再添加它。您可以暂时隐藏对象object.visible = false(也适用于灯光),或者material.opacity = 0。您可以设置light.intensity = 0禁用灯光而不会导致着色器重新编译。

后期处理

  1. 内置的抗锯齿功能不适用于后期处理(至少在WebGL 1中)。您需要使用FXAA或SMAA手动执行此操作(可能更快,更好)
  2. 由于您没有使用内置AA,请务必禁用它!
  3. three.js有大量的后处理着色器,这真是太棒了!但请记住,每次传递都需要渲染整个场景。完成测试后,请考虑是否可以将一些传递合并到一个自定义传递中
    几何
    避免使用线环,因为它必须由线条模拟

纹理

  1. 你的所有纹理都必须是2的幂(POT)大小: 1,2,4,8,16,...,512,2048 ......1 ,2 ,4 ,8 ,1 6 ,...,5 1 2 ,2 0 4 8 ,...
  2. 不要更改纹理的尺寸。相反,创建新的,它更快
  3. 尽可能使用最小的纹理尺寸(你可以使用256x256平铺纹理逃脱吗?你可能会感到惊讶!)
  4. 非二次幂(NPOT)纹理需要线性或最近的滤波,以及钳位到边界或钳位到边缘的包装。不支持Mipmap过滤和重复包装。但严重的是,只是不要使用NPOT纹理
  5. 具有相同尺寸的所有纹理在内存中的大小相同,因此JPG的文件大小可能比PNG小,但它会占用GPU上相同的内存量
    定制材料
    只有在他们改变时才更新你的制服,而不是每一帧。

物料

内置的three.js材料具有简单的性能/质量权衡:

  1. MeshStandardMaterial 最高质量/最慢
  2. MeshPhongMaterial
  3. MeshLambertMaterial
  4. MeshBasicMaterial 质量最低/最快

使用您能承受的最优质材料,并在需要时切换到质量较差的材料。

  1. MeshLambertMaterial不适用于有光泽的材料,但对于像布料这样的哑光材料,它会产生非常相似的结果,MeshPhongMaterial但速度更快
  2. 如果您正在使用变形目标,请确保morphTargets = true在材料中设置,否则它们将无效!
  3. 同去的变形法线
  4. 如果您使用SkinnedMesh进行骨骼动画,请确保material.skinning = true
  5. 与变形目标,变形法线或蒙皮一起使用的材质无法共享。您需要为每个蒙皮或变形网格创建一个独特的材质(material.clone()这里是您的朋友)。

阴影

  1. 如果场景是静态的,则仅在更改内容时更新阴影贴图,而不是每帧
  2. 使用a CameraHelper可视化阴影相机的视锥体
  3. 请记住,点光阴影比其他阴影类型更昂贵,因为它们必须渲染六次(每个方向一次),而单个时间DirectionalLightSpotLight阴影相比
  4. 虽然我们对的话题PointLight阴影,注意,CameraHelper只能可视化一个6用于可视化的点光源阴影时,阴影的方向。它仍然有用,但你需要将你的想象力用于其他5个方向
    灯,尤其是SpotLight,PointLight,DirectionalLight很慢。在场景中使用尽​​可能少的灯光
    避免在场景中添加和删除灯光,因为这需要WebGLRenderer重新编译所有着色器程序(它会缓存程序以便随后执行此操作,它会比第一个更快)
    打开renderer.physicallyCorrectLights使用SI单位的精确照明

渲染

  1. preserveDrawingBuffer除非您需要,否则请勿启用
  2. 除非您需要,否则禁用alpha缓冲区
  3. 除非您需要,否则不要启用模板缓冲区
  4. 除非你需要它,否则禁用深度缓冲区(但你可能确实需要它)
  5. powerPreference: "high-performance"在创建渲染器时使用。这可能使用户系统在多GPU系统中选择高性能GPU。
  6. 考虑仅在相机位置通过epsilon或动画发生时更改时进行渲染
  7. 如果您的场景是静态的并且使用OrbitControls,您可以监听change事件以仅在相机移动时渲染:
OrbitControls.addEventListener( 'change', () => renderer.render( scene, camera ) );

你不会从最后两个获得更高的帧速率,但你会得到的是更少的笔记本电脑风扇开启,以及移动设备上的电池消耗更少。

注意:我已经看到网络上的一些地方建议您禁用抗锯齿并应用后处理AA通道。在我的测试中,这不是真的。在现代硬件上,即使在低功耗移动设备上,内置MSAA似乎也非常便宜,而后处理FXAA或SMAA通过导致相当大的帧丢失

Three.js OffscreenCanvas

产生阴影的:

THREE.DirectionLight() 平型光
THREE.PointLight() 点光源
THREE.SpotLight() 聚光灯

不产生阴影的:

THREE.AmbientLight() 环境光
THREE.HemiphereLight() 半球光
THREE.RectAreaLight() 平面光源

你可能感兴趣的:(three.js)