如何声明和使用作为 OpenGL 中原始元素数组的顶点属性

Posted

技术标签:

【中文标题】如何声明和使用作为 OpenGL 中原始元素数组的顶点属性【英文标题】:How does one declare and use vertex attributes that are an array of primitive elements in OpenGL 【发布时间】:2021-02-22 20:20:11 【问题描述】:

在着色器中,我想将一组图元作为顶点属性传递给它。

在我声明的着色器中

in float FloatItems[8]
in int IntItems[8]

在 C++ 代码中使用:

void glGetActiveAttrib(     GLuint program,
    GLuint index,
    GLsizei bufSize,
    GLsizei *length,
    GLint *size,
    GLenum *type,
    GLchar *name);

returns 
    name == "FloatItems[0]"
    size == 1
    type == 0x1406 (GL_FLOAT) - GL_INT for the int one.

当我尝试使用 glVertexAttribPointer 绑定到它的位置时,它失败并显示 0x0501“无效值”

显然 gls 正在创建一个名称为“FloatItem[0]”的属性,而不是一个大小为 8 个元素的数组 FloatItem。

有没有“正确”的方法来做到这一点??

【问题讨论】:

根据你想要做什么,你可以使用制服来传递数组(只是谷歌它),但将它们作为顶点属性传递可能会更好(更快)。在这种情况下,您通常会有单个值或 vec2/3/4s,具体取决于您的数据“逻辑上”的样子(您通常不会将 8 个任意浮点数传递给着色器,而是像 pos (vec2/3), tex- coords (vec2) 等,在这种情况下命名和分离它们可以更容易地使用它)。我认为不可能将数组作为属性传递,但我可能在这里弄错了。 @KamiKaze 是的,我知道人们使用多元素原始类型。但是想知道是否有一种方法可以像在着色器中那样声明和使用一组基元作为顶点属性。这专门针对每个顶点数据,并且对于缓冲区中的所有顶点具有固定大小。 这可能是因为您正在引用该数组的第一个元素。 基本上是@Nicol Bolas 所说的。我认为也在这里回答:***.com/questions/9043845/… 除了我在第一条评论中所说的那样,您仍然有制服,或者使用基元(例如 2 个 vec4)或使用纹理传递数据的“常规”方式。 【参考方案1】:

这个:

in float FloatItems[8]

表示着色器采用八个单独的属性,着色器可以将其作为值数组进行访问。这是具有 8 个不同属性位置的 8 个属性。这些属性的位置将连续分配,从FloatItems[0] 的位置开始。

显然,为 8 个浮点数消耗 8 个属性位置是对位置和可能其他顶点输入资源的巨大浪费。因此,处理此问题的最佳方法是在属性本身的限制范围内工作。

属性位置的长度最多为 4 个元素(这就是您得到 GL_INVALID_VALUE 的原因:size 只能是 1-4 个)。这表示向量类型中的组件数:2-4,其中 1 是标量版本。

所以如果你想要一个“8 个浮点数的数组”,你想要的是一个由两个 vec4s 组成的数组:

layout(location = X) in vec4 FloatItems[2];

要访问数组元素,请使用多索引。要从数组中获取索引 Y,请使用 FloatItems[Y / 4][Y % 4]。使用 4 是因为您使用的是 vec4

当然,这里涉及到两个属性位置。第一个位于 X 位置(前 4 个元素),下一个位于 X + 1 位置。因此,您将需要两个 glVertexAttribFormatglVertexAttribPointer 调用来为其设置 VAO。

【讨论】:

唉,这似乎就是这种情况。 GLSL 中的一个缺陷——为了提高效率,我可以理解将位置舍入到 4 个浮点数,但这很容易克服该语言支持 mat4(16 个元素)和 mat3(9 个元素)——缺少数组声明——即使有对齐和填充的警告- 让很多人感到困惑,当然,未经策划的 howtos 和博客的众包疯狂使得寻找答案变得困难 - 我不得不使用两个 vec4 和两个 ivec4 来获得您所描述的所需内容。 @peterk: "GLSL 中的缺陷" 到底有什么缺陷?正如我所展示的,您可以拥有输入数组。不存在“缺少数组声明;”只是缺乏自动将它们打包到尽可能少的位置。每个数组元素都有自己的位置,句号。那不是“不足”;这只是它的行为 @peterk:“未经策划的howtos和博客的众包疯狂使得寻找答案变得困难”是的,如果有一个完整的页面不是更有意义致力于解释顶点着色器是如何工作的,includes a section on how input variables can generate multiple locations. 但这只是众包;它不在 Khronos 的 OpenGL 网站或其他任何地方。 我确实阅读了 Khronos 文档 - 一种语言是程序员可以理解的工具,用于定义他们想要代码做什么。许多人不理解 GLSL 数组声明的细微差别,允许声明一个 8 字节以下 (vec2) 实体的数组并让编译器很好地生成代码以为其保留空间,四舍五入到 16 字节和可使用索引在源代码中寻址。并由编译器计算所有偏移量。即使是简单的汇编程序也能很好地做到这一点。 @peterk:“我确实阅读了 Khronos 文档” 那么......“让寻找答案变得困难”是什么意思?如果您阅读了文档,那么您就会了解输入的数组声明是如何工作的。你可能不喜欢答案,但你不应该表现得好像答案对你隐藏。 “让编译器很好地生成代码,为它保留空间,四舍五入到 16 个字节,并且可以使用索引在源代码中寻址”这可能是有道理的......直到你记住字节大小这些东西在 GLSL 中没有定义。它是 VAO 的一部分。

以上是关于如何声明和使用作为 OpenGL 中原始元素数组的顶点属性的主要内容,如果未能解决你的问题,请参考以下文章

Go语言 | 03 数组指针切片用法

使用 VBO 和元素数组索引的 OpenGL 纹理

如何在不更改原始数组的情况下更改函数中的数组? [复制]

如何在Java中声明和初始化数组?

如何从 API 声明数组来代替硬编码数组?

如何将元素映射到 OpenGL VBO 中的颜色?