【问题标题】:How would I store vertex, color, and index data separately? (OpenGL)如何分别存储顶点、颜色和索引数据? (OpenGL)
【发布时间】:2022-01-05 22:16:43
【问题描述】:

我开始学习 openGL(使用 3.3 版),目的是进行小型 3d 落沙模拟,类似于:
https://www.youtube.com/watch?v=R3Ji8J2Kprw&t=41s

我在一些 Udemy 的 Unity 教程中对设置像 Minecraft 这样的体素环境有一点经验,但我想从头开始构建一些简单的东西,而不是处理已经使用 Unity 构建的所有系统。

我遇到的第一个问题来得早。我想建立一个渲染四边形的系统,因为实例化大量的立方体效率低得离谱。我还希望高效存储顶点、颜色等。到目前为止,在 opengl 教程中,我使用的方法是将每个顶点存储在具有位置和颜色数据的浮点数组中,并设置使用 glVertexAttribPointer 读取每组六个条目的缓冲区对象,三个浮点数表示位置,三个浮点数表示颜色。问题是对于每个相邻的四边形,相同的顶点会重复,因为如果它们由不同的“块”组成,它们将是不同的颜色,我想避免这种情况。

为了提高效率,我想做的是将立方体的顶点存储在一个 int 数组中(位置都将是 int),然后将地形中的每个四边形添加到索引数组中(这可能会变成稍后进入每个块的网格)。索引数组将存储每个四边形的位置,一个单独的数组将存储每个四边形的颜色。我对如何设置它有点困惑,因为我对opengl相当陌生,但我知道这应该是可行的,基于其他人对我的世界克隆所做的事情,如果不是更容易,因为我不需要纹理。

我真的很想启动并运行块、块、世界等的框架,这样我就可以得到有趣的东西,比如添加新元素。任何能够验证这是执行此操作的明智方法(大声笑)并提供有关如何在渲染中进行设置的指导的人,我将不胜感激。

【问题讨论】:

    标签: c++ opengl data-structures opengl-3 voxel


    【解决方案1】:

    到目前为止,在 opengl 教程中,我使用的方法是将每个顶点存储在具有位置和颜色数据的浮点数组中,并设置缓冲区对象以将每组六个条目读取为三个使用 glVertexAttribPointer 浮动位置和三个颜色。问题是对于每个相邻的四边形,相同的顶点会重复,因为如果它们由不同的“块”组成,它们将是不同的颜色,我想避免这种情况。

    是的,也许是有原因的。您似乎正在尝试保存.. 什么,几个字节的 RAM?您的显卡上有 8GB 的​​ RAM,它没有一个通用处理单元或无限总线来在其他缓冲区中随机查找 每个渲染像素

    索引数组将存储每个四边形的位置,一个单独的数组将存储每个四边形的颜色。

    如果你坚持这样做,没有什么能阻止你。您甚至不需要四边形顶点,您可以在几何着色器中合成它们。

    只需用X|Y|Width|Height|Color(RGB)glVertexAttribPointer 填充缓冲区,就像您已经知道的那样,然后运行几何着色器为输入缓冲区中的每个条目(四边形)合成两个三角形,然后您的顶点着色器将其投影到世界单位(你提到了整数,所以你最初不是世界单位),然后你的片段着色器可以根据颜色条目为每个光栅像素着色。

    效率低得离谱

    确实,如果这听起来效率低得离谱,那是因为它确实如此。您实际上是在 CPU 上打包数据,将其传输到 GPU,解包,然后正常处理。您可以跳过至少两个步骤,如果您认为顶点着色器输出缓存在光栅化图元中,则可以跳过更多步骤。

    这种精神错乱还有很多变体,例如:

    • 按正常方式存储解压后的顶点位置,并存储颜色索引。然后将颜色存储在某种线性缓冲区(纹理、SSBO、通用缓冲区等)中并查找每个颜色索引。这效率更低,但更接近您建议的算法。
    • 存储一个四边形的顶点位置,并使用多重绘制命令和缓冲区设置实例化渲染,以提供单个实例数据(位置和颜色)。如果您还有纹理,则可以为每个四边形实例使用 bindless textures。它仍在渲染多个对象,但您的图形驱动程序对其进行了稍微优化。
    • 或者只是将每个顶点的数据存储在缓冲区中并进行渲染。完毕。没有预先计算,没有无限的扩展,没有疯狂的代码,你有你的顶点数据并渲染它。

    【讨论】:

    • 几个字节的 RAM 似乎并不多,但如果说我心目中的世界玩家将比渲染一个体面大小的块高 20+ 体素与 Minecraft 世界相比,这将需要 16^3 倍的处理量。在这个阶段,考虑优化可能还为时过早,但就我最终的想法而言,我认为我没有任何理由从一开始就考虑这样的事情而受到侮辱。
    • 恰恰相反,这是您通过在 CPU 上打包并在 GPU 上解包来创建的处理量。与尝试“优化”理论上任意大的体素批次相比,您的时间会花在剔除不可见体素上要好得多。
    • 我也没有提到它,但是着色器直到最近才支持整数,而且显卡几乎不能使用它们。在着色器中使用整数几乎和使用分支一样糟糕。
    • 好的。在对此进行了更多研究并尝试了一些实际代码后,我了解我的原始方法使这变得多么复杂,所以我只是创建了一个四边形类来存储两个三角形的顶点数据。只需指定我要生成的四边形的朝向和颜色,它就可以轻松生成大量数据。对于世界的每一块,我可以循环体素数据,为每个暴露的边生成一个四边形,并将它们存储在一个四边形的顶点中。然后我只需要将它传递给 VBO;我非常感谢您的帮助:)
    • 这几乎是 Minecraft 类世界的幼稚方法(即大立方体体素,不要与用于现场角色的小体素混淆)。请注意,如果您添加任何类型的透明度(玻璃、水等),您所描述的内容将不起作用,在这种情况下,您必须手动对眼睛空间中的各个面部进行分类(因此它会随着帧的变化而变化为相机移动),这自然会导致您进行积极的修剪(否则所有这些工作都需要您在 fps 计数器中添加更多小数,因此您看不到纯 0)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-22
    • 2013-09-14
    • 2021-12-01
    • 2014-03-19
    • 2012-12-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多