【问题标题】:Is there a more efficient way to render high quantities of individual meshes?有没有更有效的方法来渲染大量的单个网格?
【发布时间】:2012-10-11 20:48:10
【问题描述】:

总结

我目前正在 Three.js 中创建一个 3D 平铺六角板。出于艺术和功能方面的原因,每个图块都是它们自己的网格,由基本(不变)几何体组成,并在其材质中生成一组贴图:置换、漫反射、法线。

随着我添加更多纹理贴图,我开始注意到 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%  |
//                       \-----------------------------/

行:

  • MeshLambertMaterial({color}) 是我的基准
  • MeshLambertMaterial({map}) 的性能下降了大约 10%
  • ShaderMaterial() 使用默认设置的性能下降了大约 20%
  • ShaderMaterial() 使用 Diffuse Map 的性能下降了大约 30%
  • ShaderMaterial() 使用漫反射+法线+置换贴图的性能下降了 37%

列:

  • 15x15(225 网格)是我的基线
  • 20x20(400 网格)性能下降 33%
  • 25x25(625 个网格)性能下降了 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

概要

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

注意事项

我已经考虑过合并我的几何图形。这几乎完全消除了帧速率的下降。但是,正如我在本文开头所述,我需要每个图块都可以单独翻译、可旋转、可缩放和以其他方式进行修改。据我所知,这对于合并的几何图形是不可能的。

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

  1. 由于板上有 200-400 个单独的网格并被合并,这可能需要 1000 毫秒以上的时间来处理并导致明显的视觉卡顿。
  2. 大型效果,例如可能同时“摇晃”或“摆动”所有图块的效果,将与现在的棋盘一样滞后,因此没有理由实施它们。

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

问题

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

【问题讨论】:

  • 您可能会觉得这个谈话很有趣:Google I/O 2011: WebGL Techniques and Performance。它专门讨论了如何有效地渲染大量对象。
  • 我不知道这是否会有所帮助或只是令人困惑,但这个项目 (boombambeat.googlecode.com/git/index.html) 有一个着色器,它通过 1 个绘制调用绘制很多东西并使用纹理来设置翻译,每个单独对象的方向和颜色。 IIRC 进入boombambeat.js,注释掉“createSpiroGeometryRender();”并在“createRepeatedGeometryRenderer();”中发表评论。
  • Protip:测量(毫秒)秒,而不是反时限单位(fps)

标签: optimization render webgl three.js


【解决方案1】:

我已经考虑过合并我的几何图形。这几乎完全消除了帧速率的下降。但是,正如我在本文开头所述,我需要每个图块都可以单独翻译、可旋转、可缩放和以其他方式进行修改。据我所知,这对于合并的几何图形是不可能的。

确实如此。添加一个顶点属性,该属性是一个整数,用于标识顶点所属的图块。然后,您可以根据可以在顶点着色器中计算的任何内容单独移动图块。

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

对于像“摇晃”效果这样的东西,你甚至不需要纹理;只需添加一个给出当前时间的统一变量,并以由瓷砖索引修改的方式计算抖动。

【讨论】:

  • 这似乎是一个很好的解决方案。使用这种方法,我可以在光线投射时考虑这些位移吗?每个图块都需要单独选择。
  • 我建议改用拾取:这是您渲染场景(到渲染缓冲区)的地方,这样每个图块都有一个平坦、独特的颜色,然后读回光标下的像素并查找什么瓷砖具有该像素的颜色。这样你就不用写光线投射,也不用写任何 JS 代码做变换。
  • 太棒了。你非常有帮助。谢谢!
  • 制作一个完整的渲染缓冲区只是为了有一个高效的查找对于瓦片来说听起来有点过头了,但一般概念(让人想起你可能在延迟渲染器中使用的 g-buffer/index-buffer 类型的东西)是非常聪明和强大的一个。
【解决方案2】:

随着添加更多纹理贴图,我开始注意到 FPS 有所降低...

一般来说,您希望最小化渲染的状态变化。更改纹理或着色器等内容需要向 GPU 发送新信息。这可不便宜。

您可以尝试的“简单”事情是按材质排序渲染网格。我使用“简单”是因为如果您在树遍历中渲染网格,则必须重新构建渲染代码以改为按材质渲染。

请参阅this post from Christer Ericson,了解其他各种优化渲染以最小化状态变化的方法。

【讨论】:

    猜你喜欢
    • 2017-07-29
    • 1970-01-01
    • 2017-12-27
    • 1970-01-01
    • 2015-04-16
    • 1970-01-01
    • 1970-01-01
    • 2017-04-08
    • 1970-01-01
    相关资源
    最近更新 更多