如何使用webgl实现批量?

mic*_*cha 1 3d opengl-es webgl

我正在使用 webgl 开发一个小游戏。在这个游戏中,我有某种森林,由许多(100 多个)树木对象组成。因为我只有几个不同的树模型,所以在显示它们之前我会以不同的方式旋转和缩放这些模型。

目前我遍历所有树来显示它们:

for (var tree in trees) {
  tree.display();
}
Run Code Online (Sandbox Code Playgroud)

display()树的方法如下所示:

display : function() { // tree
  this.treeModel.setRotation(this.rotation);
  this.treeModel.setScale(this.scale);
  this.treeModel.setPosition(this.position);
  this.treeModel.display();
}
Run Code Online (Sandbox Code Playgroud)

许多树对象共享同一个treeModel对象,因此每次显示模型之前我都必须设置模型的旋转/缩放/位置。每棵树的旋转/缩放/位置值都不同。

显示方法treeModel完成所有 gl 的工作:

display : function() { // treeModel
  // bind texture
  // set uniforms for projection/modelview matrix based on rotation/scale/position
  // bind buffers
  // drawArrays
}
Run Code Online (Sandbox Code Playgroud)

所有树模型都使用相同的着色器,但可以使用不同的纹理。

因为单个树模型仅由几个三角形组成,所以我想将所有树组合到一个 VBO 中,并通过一次drawArrays()调用显示整个森林。

一些使谈论数字更容易的假设:

  • 有 250 棵树可供展示
  • 有5种不同的树模型
  • 每个树模型有 50 个三角形

我有的问题:

  • 目前我有 5 个字节50 * 3 * 8 (position + normal + texCoord) * floatSize大小的缓冲区。当我想用一个 vbo 显示所有树时,我将有一个250 * 50 * 3 * 8 * floatSize字节大小的缓冲区。我认为我不能使用索引缓冲区,因为每棵树都有不同的位置值(根据树模型的位置值和树位置/缩放/旋转计算得出)。这是正确的还是还有一种方法可以使用索引缓冲区来至少减少一点缓冲区大小?也许还有其他方法可以优化这个?

  • 如何处理不同纹理的树模型?我可以将所有纹理绑定到不同的纹理单元,但如何在着色器中决定当前显示的片段应使用哪个纹理?

  • 当我想在运行时向此缓冲区添加新树(或任何其他类型的对象)时:我是否必须创建一个新缓冲区并复制内容?我认为不能通过使用添加新值glMapBuffer。它是否正确?

小智 5

索引元素缓冲区只能到达长度等于或小于 65535 的属性,因此您需要使用drawArrays。通常不会造成太大损失。

您可以使用 GL.bufferSubData 将树添加到缓冲区的末尾。

如果您的纹理尺寸合理(例如 128x128 或 256x256),您可以将它们合并为一个大纹理,并使用 UV 坐标处理整个纹理。如果没有,您可以添加另一个属性来说明顶点属于哪个纹理,并在顶点着色器中设置一个条件,或者是一个sampler2D数组(不确定它是否有效,从未尝试过)。请记住,着色器中的条件非常慢。

如果您决定坚持使用当前的解决方案,请确保对树进行排序,以便使用相同纹理的树在彼此之后渲染 - 始终保持状态切换至关重要。