当前位置: 首页 > 知识库问答 >
问题:

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

宋涵忍
2023-03-14

在顶点数组缓冲区的典型构建中,我试图将一个无符号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;

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

uniform sampler2D ColourMap;

介绍我的问题

到目前为止还不错,有了上面的代码,我可以成功地渲染纹理原语。现在,我想根据渲染的人脸选择不同的颜色贴图。为此,我想引入一个索引作为vertice属性的一部分。变化包括:

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”,这些更改不会特别起作用。通过不使用unsigned int类型,而是使用vec2(或vec3,两种方式都有效),我能够证明这一点(并找到了一种解决方法)。也就是说:

VS:

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

FS:

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)));

注意:我检查了“着色器”的结果。属性(“VS_TextureId”)。它是正确的,这意味着顶点着色器中的属性定义良好,并且可以找到。

你能看出问题出在哪里吗?

共有1个答案

曾涵育
2023-03-14

如果要使用整型数据类型指定属性数组,则必须使用glVertexAttribIPointer(专注于函数名称中间的I),而不是glVertexAttribIPointer。

参见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规范-4.1.7。不透明类型(第33页)

纹理组合采样器类型是不透明类型,其声明和行为与上述不透明类型相同。当聚集到着色器中的数组中时,只能使用动态统一的积分表达式对它们进行索引,否则结果将不确定。[...]

我建议使用单个TEXTURE_2D_ARRAY纹理,而不是TEXTURE_2D纹理数组。请参阅纹理。
在这种情况下,您可以使用3维浮点纹理坐标。

 类似资料:
  • 在一个简单的hello world OpenGL程序中,它只是在窗口上绘制一个静态三角形,当我将三角形的3个顶点设置为红色、绿色和蓝色时,三角形将填充渐变。 但是当我使用这样的着色器时: 顶点着色器: 其中属性和来自顶点缓冲区,通过的调用传递。 片段着色器: 三角形仍然充满了梯度,问题来了: 如果顶点着色器是按顶点计算的,则应为的每个实例指定顶点的颜色。顶点颜色应为红色、绿色或蓝色,如顶点缓冲区中

  • 我正在QT-QML-3D中用C开发一个应用程序。我需要将数十个浮点值(或浮点数向量)传递给片段着色器。这些值是灯光的位置和颜色,所以我需要更多的值,范围从0.0到1.0。但是,不支持将浮点或整数数组传递给QML中的着色器。我的想法是将浮动保存到纹理,将纹理传递到着色器,并从中获取值。 我试过这样的方法: 并将此QImage作为sampler2D传递给片段着色器。但是有没有像memcpy这样的方法可

  • WebGL的着色器代码分为顶点着色器代码和片元着色器代码两部分,顶点着色器代码会在GPU的顶点着色器单元执行,片元着色器代码会在GPU的片元着色器单元执行,在WebGL渲染管线流程中,或者说GPU的渲染流程中,顶点着色器代码先执行处理顶点,得到一系列片元,然后再执行片元着色器代码处理片元。 main()函数 顶点着色器和片元着色器代码都有一个唯一的主函数main(),attribute、varyi

  • 顶点着色器用来操作ShaderEffect提供的顶点。正常情况下,ShaderEffect有4个顶点(左上top-left,右上top-right,左下bottom-left,右下bottom-right)。每个顶点使用vec4类型记录。为了实现顶点着色器的可视化,我们将编写一个吸收的效果。这个效果通常被用来让一个矩形窗口消失为一个点。 配置场景(Setting up the scene) 首先我

  • 他们没有提到的是如何首先将两个纹理传递给着色器。 以前我 所以现在我 如何将大小不同的纹理数组传递给GLSL? 将多个纹理从OpenGL传递到GLSL着色器 GLSL中的多个纹理-只有一个有效 (这是家庭作业,所以请用最少的代码片段回答(如果有的话)。谢谢!) 如果做不到这一点,有人有茶具吗?

  • 我正在使用gradle tooling api,我遇到了下面的场景。有一个应用某个插件P的项目,它只在传递shouldApplyP属性时才创建任务T。 因此,如果您将运行,您将看不到任务T,但是如果您将运行,您将看到任务T。 在gradle tooling api中,一旦创建了,我就可以执行 但我看不到这个具体的任务。是否有方法将此属性传递给项目连接,以便在方法中显示该属性?