首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用webgl实现批处理?

如何使用webgl实现批处理?
EN

Stack Overflow用户
提问于 2012-03-17 00:15:04
回答 3查看 1.5K关注 0票数 1

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

此刻,我环游了所有的树来展示它们:

代码语言:javascript
复制
for (var tree in trees) {
  tree.display();
}

虽然树的display()方法看起来像:

代码语言:javascript
复制
display : function() { // tree
  this.treeModel.setRotation(this.rotation);
  this.treeModel.setScale(this.scale);
  this.treeModel.setPosition(this.position);
  this.treeModel.display();
}

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

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

代码语言:javascript
复制
display : function() { // treeModel
  // bind texture
  // set uniforms for projection/modelview matrix based on rotation/scale/position
  // bind buffers
  // drawArrays
}

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

由于单个树模型仅由几个三角形组成,所以我希望将所有树合并到一个VBO中,并使用一个drawArrays()调用显示整个森林。

有些假设使得谈论数字变得更容易:

  • 有250个树来显示
  • ,有5个不同的树模型
  • 每个树模型都有50个三角形

我有以下问题:

目前,

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

  • ,如何处理不同纹理的树模型?我可以将所有纹理绑定到不同的纹理单元,但是如何在着色器中决定应该为当前为displayed?
  • When的片段使用哪种纹理,我想在运行时向这个缓冲区添加一棵新树(或任何其他类型的对象):是否必须创建一个新的缓冲区并复制内容?我认为使用glMapBuffer不能添加新的值。对吗?
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-03-17 18:11:30

索引元素缓冲区只能覆盖长度等于或小于65535的属性,因此需要使用drawArrays。这通常不是什么大损失。

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

如果你的纹理尺寸合理(比如128x128或256x256),你可能可以把它们合并成一个大的纹理,然后用紫外线和弦来处理整个事情。如果没有,您可以添加另一个属性,表示顶点属于什么纹理,并且在顶点着色器中有一个条件,或者添加一个sampler2Ds数组(不确定它是否工作,从未尝试过)。记住,着色器的条件是相当缓慢的。

如果您决定坚持您的当前解决方案,确保排序的树木,因此一旦使用相同的纹理后,相互渲染-保持状态切换是必不可少的,始终。

票数 5
EN

Stack Overflow用户

发布于 2012-03-18 20:30:53

几点想法:

  1. ,一旦你在你的世界里种了一棵树,你有没有修改过它?它会有生命吗?还是只是静态几何?如果它是真正的静态的,那么您总是可以构建一个带有每个树的几个副本的单一缓冲区。在追加树时,首先(在Javascript中)将实例的世界转换为顶点。如果使用三角形条,可以使用退化多边形将树连接在一起。
  2. 您可以滚动自己的伪实例绘图:
    1. 在数组缓冲区中编码实例ID。只需为属于同一树实例的所有顶点设置相同的值即可。我似乎还记得,在ES GLSL中不可能有非浮动顶点属性(也许这是Chrome限制),所以您需要将其作为浮点数,但将其用作int。由于它是作为浮点数出现的,因此您必须处理这样一个事实,即它是在三角形内插的,因此值会有微小的波动--但只需将其舍入到最接近的整数上。
    2. 使用一个单独的纹理(我称之为数据纹理)来对所有每个实例信息进行编码。在顶点着色器中,查看当前顶点的实例ID,并使用该ID计算数据纹理中的纹理坐标。提取转换当前顶点所需的任何内容,并应用它。我认为这被称为“依赖纹理读取”,这通常是不赞成的,因为它可能会导致性能问题,但它可能会帮助您批量处理您的几何图形,这可以帮助解决性能问题。如果你有兴趣的话,你必须试一试看看happens.

是什么

  1. 希望有一个扩展来支持真实的实例绘图。
票数 2
EN

Stack Overflow用户

发布于 2012-03-17 01:19:27

你现在的方法还不错。我会说:坚持到底,直到你撞到墙上。

50三角形已经是一个合理的批次大小一个单一的绘图/绘图already调用。这不是最理想的,但也不是很糟糕。所以每一棵树都会通过制服来改变位置、纹理和形状等参数。然后对每棵树进行抽签。另外,总共250个drawElements调用也不是那么糟糕。

所以我会使用一个VBO,它包含所有使用过的树形变体。我实际上把这些树分成了几块,这样我就可以重新组合它们以增加品种。对于每棵树,在调用drawArrays或drawElements之前,都要将适当的偏移量放到VBO中。

此外,不要忘记,你可以做一个非常便宜的视野,每棵树的剔除。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9746088

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档