【问题标题】:Why does merging geometries improve rendering speed?为什么合并几何图形可以提高渲染速度?
【发布时间】:2015-08-13 08:38:48
【问题描述】:

在我的 Web 应用程序中,我只需要将静态对象添加到我的场景中。它运行缓慢,所以我开始搜索,我发现合并几何和合并顶点是解决方案。当我实施它时,它确实工作得更好。所有的文章都说这种改进的原因是 WebGL 调用次数的减少。由于我对 OpenGL 和 WebGL 之类的东西不是很熟悉(我使用 Three.js 来避免它们的复杂性),我想知道为什么它会减少 WebGL 调用? 因为您发送一个大对象而不是许多小对象,所以开销减少了。所以我知道将一个大网格加载到场景中比许多小网格更快。 但我不明白为什么合并几何对渲染计算也有积极影响?我也想知道合并几何和合并顶点的区别?

提前致谢!

【问题讨论】:

    标签: merge three.js geometry vertices


    【解决方案1】:

    three.js 是一个帮助您使用 WebGL API 的框架。

    对于three.js 而言,“网格”是什么,对于webgl 而言,它是一系列设置状态并向GPU 发出调用的低级调用。

    我们以一个球体为例。使用three.js,您只需几行即可创建它:

    var sphereGeometry = new THREE.SphereGeometry(10); 
    var sphereMaterial = new THREE.MeshBasicMaterial({color:'red'});
    var sphereMesh = new THREE.Mesh( sphereGeometry, sphereMaterial);
    
    myScene.add( sphereMesh );
    

    你有你的 renderer.render() 调用,噗,一个球体出现在屏幕上。

    但很多事情都发生在幕后。

    第一行,创建球体“几何”——cpu 将使用一堆数学和逻辑来描述一个球体,其中包含点和三角形。点是向量,三个浮点数组合在一起,三角形是按不定数(整数组)对这些点进行分组的结构。

    有一个循环根据三角函数(sin、cos)计算向量,另一个循环将生成的向量数组编织成三角形(取每个 N、N + M、N + 2M,创建一个三角形等)。

    现在这些数字存在于 JavaScript 领域,它只是一堆浮点数和整数,以特定方式组合在一起来描述立方体、球体和外星人等形状。

    您需要一种在屏幕上绘制此构造的方法 - 一个二维像素数组。

    WebGL 实际上并不了解 3D。它知道如何管理 gpu 上的内存,如何并行计算(或为您提供工具),它确实知道如何进行对 3d 图形至关重要的数学运算,但同样的数学运算可用于挖掘比特币,甚至没有画任何东西。

    为了让 WebGL 在屏幕上绘制某些东西,它首先需要将数据放入适当的缓冲区,它需要有着色器程序,它需要针对特定​​调用进行设置(是否会混合 - 透明度three.js 土地、深度测试、模板测试等),然后它需要知道它实际在绘制什么(所以你需要提供步幅、属性大小等,让它知道“网格”在内存中的实际位置),如何它正在绘制它(三角形条、扇形、点......)以及用什么来绘制它 - 它会将哪些着色器应用于您提供的数据。

    因此,您需要一种“教”WebGL 做 3d 的方法。

    我认为熟悉这个概念的最好方法是查看this tutorial,如有必要,请重新阅读,因为它解释了每个透视的 3d 对象几乎发生了什么.

    总结教程:

    • 透视相机基本上是两个 4x4 矩阵 - 一个透视矩阵,将事物放入透视中,一个视图矩阵,将整个世界移动到相机空间中。您制作的每台相机都由这两个矩阵组成。
    • 每个对象都存在于它的对象空间中。 TRS矩阵,(三个.js术语中的世界矩阵)用于将此对象转换为世界空间。

    所以这些东西 - 诸如“投影矩阵”之类的概念是教 webgl 如何绘制透视图的。

    Three.js 进一步抽象了这一点,并为您提供“视野”和“纵横比”等内容,而不是左右上下。

    Three.js 还抽象了转换矩阵(相机上的视图矩阵和每个对象上的世界矩阵),因为它允许您设置“位置”和“旋转”并在后台根据此计算矩阵。

    由于每个网格都必须经过顶点着色器和像素着色器处理才能出现在屏幕上,因此每个网格都需要提供所有这些信息。

    当为特定网格发出绘制调用时,该网格将具有与使用同一相机渲染的任何其他对象相同的透视矩阵和视图矩阵。他们每个人都有自己的世界矩阵——在你的场景中移动它们的数字。

    这只是变换,发生在顶点着色器中。然后将这些结果光栅化,并进入像素着色器进行处理。

    让我们考虑两种材料 - 黑色塑料和红色塑料。它们将具有相同的着色器,可能是您使用 THREE.ShaderMaterial 编写的着色器,也可能是来自三个库的着色器。它是同一个着色器,但它暴露了一个统一的值——颜色。这允许您拥有许多塑料材质的实例,绿色、蓝色、粉红色,但这意味着每个实例都需要单独的绘制调用。

    Webgl 必须发出特定的调用来将该制服从红色更改为黑色,然后它就可以使用该“材质”来绘制东西了。

    现在想象一个粒子系统,显示一千个具有独特颜色的立方体。如果您将它们视为单独的网格并通过制服更改颜色,则必须发出一千次绘制调用才能将它们全部绘制出来。

    另一方面,如果为每个立方体分配顶点颜色,则不再依赖统一,而是依赖属性。现在,如果您将所有立方体合并在一起,您可以发出一个绘制调用,使用相同的着色器处理所有立方体。

    您可以通过浏览一下three.js 中的webglrenderer 以及将您的3d 调用转换为webgl 所必须做的所有事情来了解为什么这样做更有效。做一次比做一千次更好。

    回到那 3 行,sphereMaterial 可以带一个颜色参数,如果您查看源代码,这将转换为着色器中的统一 vec3。但是,您也可以通过渲染顶点颜色并事先指定您想要的颜色来实现相同的目的。

    sphereMesh 将把计算出的几何图形包装成一个可以被三个 webglrenderer 理解的对象,然后相应地设置 webgl。

    【讨论】:

      猜你喜欢
      • 2014-09-30
      • 1970-01-01
      • 2011-08-12
      • 2016-11-17
      • 1970-01-01
      • 1970-01-01
      • 2011-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多