opengl 将无符号整型输入属性传递给顶点着色器

pkln4tw6  于 2022-11-04  发布在  其他
关注(0)|答案(1)|浏览(148)

在一个典型的顶点数组缓冲区的构建中,我试图传递一个unsigned int属性沿着其他经典属性(顶点、法线、纹理坐标...)。然而,这个属性的值最终出现了某种错误:我不确定是值错误还是属性没有设置。
从一个简单的例子开始,假设我定义了下面的C++输入结构:

struct buffer_data_t
{
    glm::vec3 vertex;
    glm::vec3 normal;
    glm::vec2 texCoords;
};

准备顶点数组时,如下所示:

// Assume this 'shader.attribute(..)' is working and returns the attribute's position
unsigned int shadInputs[] = {
    (unsigned int)shader.attribute("VS_Vertex"),
    (unsigned int)shader.attribute("VS_Normal"),
    (unsigned int)shader.attribute("VS_TexCoords"),
};

glGenBuffers(1, &glBuffer);
glBindBuffer(GL_ARRAY_BUFFER, glBuffer);
glBufferData(GL_ARRAY_BUFFER, vertice.size() * sizeof(buffer_data_t), &vertice[0], GL_STATIC_DRAW);
glGenVertexArrays(1, &glArray);
glBindVertexArray(glArray);
{
    glBindBuffer(GL_ARRAY_BUFFER, glBuffer);
    glVertexAttribPointer(shadInputs[0], 3, GL_FLOAT, GL_FALSE, sizeof(buffer_data_t), (void*)(sizeof(glm::vec3) * 0));
    glVertexAttribPointer(shadInputs[1], 3, GL_FLOAT, GL_FALSE, sizeof(buffer_data_t), (void*)(sizeof(glm::vec3) * 1));
    glVertexAttribPointer(shadInputs[2], 2, GL_FLOAT, GL_FALSE, sizeof(buffer_data_t), (void*)(sizeof(glm::vec3) * 2));
    glEnableVertexAttribArray(shadInputs[0]);
    glEnableVertexAttribArray(shadInputs[1]);
    glEnableVertexAttribArray(shadInputs[2]);
}
glBindVertexArray(0);

顶点着色器输入的定义如下:

in vec3 VS_Vertex;
in vec3 VS_Normal;
in vec2 VS_TexCoords;

此外,为了便于示例,假设我的片段着色器中有一个纹理采样器,可以在该采样器上使用这些输入TexCoords:

uniform sampler2D ColourMap;

介绍我的问题

到目前为止一切顺利,使用上面的代码,我可以成功地渲染纹理图元。现在,我想根据渲染的面选择不同的颜色贴图。为此,我想引入一个index作为顶点属性的一部分。更改如下:
C++数据结构:

struct buffer_data_t
{
    glm::vec3 vertex;
    glm::vec3 normal;
    glm::vec2 texCoords;
    unsigned int textureId; // <---
};

准备顶点数组:

unsigned int shadInputs[] = {
    (unsigned int)shader.attribute("VS_Vertex"),
    (unsigned int)shader.attribute("VS_Normal"),
    (unsigned int)shader.attribute("VS_TexCoords"),
    (unsigned int)shader.attribute("VS_TextureId"),
};

// ...

glBindBuffer(GL_ARRAY_BUFFER, glBuffer);
glVertexAttribPointer(shadInputs[0], 3, GL_FLOAT, GL_FALSE, sizeof(buffer_data_t), (void*)(sizeof(glm::vec3) * 0));
glVertexAttribPointer(shadInputs[1], 3, GL_FLOAT, GL_FALSE, sizeof(buffer_data_t), (void*)(sizeof(glm::vec3) * 1));
glVertexAttribPointer(shadInputs[2], 2, GL_FLOAT, GL_FALSE, sizeof(buffer_data_t), (void*)(sizeof(glm::vec3) * 2));
glVertexAttribPointer(shadInputs[3], 1, GL_UNSIGNED_INT, GL_FALSE, sizeof(buffer_data_t), (void*)(sizeof(glm::vec3) * 2 + sizeof(glm::vec2))); // <---
glEnableVertexAttribArray(shadInputs[0]);
glEnableVertexAttribArray(shadInputs[1]);
glEnableVertexAttribArray(shadInputs[2]);
glEnableVertexAttribArray(shadInputs[3]);

然后,顶点着色器定义新的输入,以及“平面”输出

in vec3 VS_Vertex;
in vec3 VS_Normal;
in vec2 VS_TexCoords;
in unsigned int VS_TextureId;

...

out flat unsigned int FS_TextureId;

片段着色器调整为使输入平面化,并且(再次为了示例)颜色贴图现在是一个数组,我们可以从中选择:

...
uniform sampler2D ColourMaps[2];
in flat unsigned int FS_TextureId;
...
texture2D(ColourMaps[FS_TextureId], ... );

这些更改不起作用特别是因为顶点着色器输入属性'VS_TextureId'。我能够证明这一点(并找到一个解决方案),不使用无符号int类型,而是诉诸于vec2(或vec3,两种方式都适用)。即:

VS:

in vec2 VS_TextureId;
out flat int FS_TextureId;
FS_TextureId = int(VS_TextureId.x);

财政司司长:

in flat int FS_TextureId;
texture2D(ColourMaps[FS_TextureId], ... );

"我的假设"
我猜这是线路故障,尽管我不知道原因:

glVertexAttribPointer(shadInputs[3], 1, GL_UNSIGNED_INT, GL_FALSE, sizeof(buffer_data_t), (void*)(sizeof(glm::vec3) * 2 + sizeof(glm::vec2)));

注意:我检查了'shader.attribute(“VS_TextureId”)'的结果,结果是正确的,这意味着顶点着色器中的属性定义良好并可找到。
你能看出问题出在哪里吗?

gwo2fgha

gwo2fgha1#

如果你想用整型数据类型指定属性数组,那么你必须使用glVertexAttribIPointer(注意函数名中间的 * I *),而不是glVertexAttribPointer
请参见OpenGL 4.6 API核心配置文件规范; 10.2.当前顶点属性值;第348页

VertexAttribI*命令指定有符号或无符号定点值,这些值分别存储为有符号或无符号整数。此类值称为纯整数。

...
所有其他**VertexAttrib*命令指定的值直接转换为内部浮点表示**。
这意味着顶点属性的规格必须是:

//glVertexAttribPointer(shadInputs[3], 1, GL_UNSIGNED_INT, GL_FALSE, 
//    sizeof(buffer_data_t), (void*)(sizeof(glm::vec3) * 2 + sizeof(glm::vec2))); 
glVertexAttribIPointer(shadInputs[3], 1, GL_UNSIGNED_INT,
    sizeof(buffer_data_t), (void*)(sizeof(glm::vec3) * 2 + sizeof(glm::vec2)));

一般来说,你要实现的并不是这样的。采样器数组的索引必须是“动态一致的”。这意味着所有片段的索引必须是“相同的”(例如,一个常量或一个一致的变量)。
请参阅GLSL 4.60 Specification - 4.1.7. Opaque Types (page 33)
纹理组合采样器类型是不透明类型,声明和行为与上述不透明类型相同。当聚集到着色器中的数组中时,只能使用动态统一整数表达式对它们进行索引,否则结果未定义。
我建议使用一个TEXTURE_2D_ARRAY纹理,而不是一个TEXTURE_2D纹理数组。
在这种情况下可以使用三维浮点纹理坐标。

相关问题