有没有更有效的方法来渲染大量的单个网格?

rro*_*and 6 optimization render webgl three.js

摘要

我目前正在Three.js中创建一个3D平铺六角板.出于艺术和功能的原因,每个图块都是它们自己的网格,由一个基本(不变)几何体组成,其材质中有一个生成的地图数组:Displacement,Diffuse,Normal.

当我添加更多纹理贴图时,我开始注意到FPS的减少,这促使我查看源代码.我有一个15x15的游戏板,这意味着每帧渲染225个单独的网格.当时每个网格由于设计不佳而由215个面组成,导致场景中有48,375个面.

认为它可以解决性能问题,我重新设计了网格只包含30个面孔,整个场景共有6,750个面孔; 惊人的改进.我很失望地发现,面部减少86%对性能几乎没有影响.

所以,我决定找到导致性能下降的确切原因.我设置了一个抽象的测试环境,并使用了一个3x10的平面网格(给它们30个面,就像我自己的模型一样).我尝试了不同的网格尺寸(网格数)和应用不同复杂度的材料.这是我发现的:

材料测试

// /---------------------------------------------------\
// |      Material       |  15x15  |  20x20  |  25x25  |
// |---------------------|---------|---------|---------|------\
// | Flat Lambert Color  |  60FPS  |  48FPS  |  30FPS  | -00% |
// | Lambert Diffuse     |  57FPS  |  41FPS  |  27FPS  | -10% |
// | Blank Shader        |  51FPS  |  37FPS  |  24FPS  | -20% |
// | Full Shader (-H)    |  49FPS  |  32FPS  |  21FPS  | -30% |
// | Full Shader (+H)    |  42FPS  |  28FPS  |  19FPS  | -37% |
// \----------------------------------------------------------/
//                       |   -00%  |   -33%  |   -55%  |
//                       \-----------------------------/
Run Code Online (Sandbox Code Playgroud)

行:

  • MeshLambertMaterial({color}) 是我的基线
  • MeshLambertMaterial({map}) 遭受了大约10%的性能损失
  • ShaderMaterial() 使用默认设置的性能大约下降了20%
  • ShaderMaterial() 使用漫反射贴图的性能大约下降了30%
  • ShaderMaterial() 使用漫反射+法线+位移贴图的性能下降了37%

列:

  • 15x15(225网格)是我的基线
  • 20x20(400 Meshes)的性能下降了33%
  • 25x25(625 Meshes)的性能下降了55%

概要

所以我了解到我正在使用的着色器和我正在应用的地图有很大的影响.然而,"事物"的数量会产生更大的影响.我不确定这是面孔,网格还是其他因此我进行了另一次测试.使用我的基线材质(MeshLambertMaterial({ color: red })),我决定测试两个变量:边数和网格数.这是我发现的:

面/网格计数测试

// 15x15 (225)  Meshes @ 30 Faces =   6,750 Faces   = 60 FPS
// 20x20 (400)  Meshes @ 30 Faces =  12,000 Faces   = 48 FPS
// 25x25 (625)  Meshes @ 30 Faces =  18,750 Faces   = 30 FPS
// 30x30 (900)  Meshes @ 30 Faces =  27,000 Faces   = 25 FPS
// 40x40 (1600) Meshes @ 30 Faces =  48,000 Faces   = 15 FPS
// 50x50 (2500) Meshes @ 30 Faces =  75,000 Faces   = 10 FPS

// 15x15 (225) Meshes @ 100 Faces =  22,500 Faces   = 60 FPS
// 15x15 (225) Meshes @ 400 Faces =  90,000 Faces   = 60 FPS
// 15x15 (225) Meshes @ 900 Faces = 202,500 Faces   = 60 FPS
Run Code Online (Sandbox Code Playgroud)

Synposis

这似乎非常确凿地表明,如果有的话,所涉及的面部数量不会对帧速率产生太大影响.相反,绘制到场景的单个网格的数量几乎创造了所有的性能拖累.我不确定究竟是什么导致这种滞后; 我想每个网格有大量的开销.也许还有消除一些这样的开销?

注意事项

我已经考虑过合并我的几何形状了.这几乎完全消除了帧速率的下降.然而,正如我在本文开头所述,我需要每个瓷砖可单独翻译,可旋转,可扩展和其他可修改.据我所知,合并几何不可能实现这一点.

我还考虑默认为合并几何,并在调用更改图块的函数时重新创建几何/场景.但是,这种方法存在两个问题:

  1. 在电路板上有200-400个单独的网格并被合并,这可能需要超过1000毫秒来处理并导致明显的视觉口吃.
  2. 大的效果,例如可能同时"摇动"或"摆动"所有图块的效果,将与现在的电路板一样滞后,并且没有理由实施它们.

我希望找到一种解决方案来消除这种性能损失,而不是试图避免它.

这让我想到了一个问题:是否有更有效的方法来渲染大量的单个网格?

Kev*_*eid 5

我已经考虑过合并我的几何形状了.这几乎完全消除了帧速率的下降.然而,正如我在本文开头所述,我需要每个瓷砖可单独翻译,可旋转,可扩展和其他可修改.据我所知,合并几何不可能实现这一点.

当然是啦.添加顶点属性,该属性是标识顶点所属的平铺的整数.然后,您可以根据您在顶点着色器中计算的任何内容单独移动切片.

如果您需要每个图块的单独数据(例如变换),您可以将其加载到纹理中并使用图块索引从纹理中查找值 - 您甚至可以进行排列以使纹理看起来像是(倾斜的)副本十六进制网格,便于调试!

对于像"摇晃"效果这样的东西,你甚至不需要纹理; 只需添加一个给出当前时间的统一变量,然后以tile索引修改的方式计算抖动.