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

C++ 将无符号int输入属性传递给顶点着色器,c++,opengl,glsl,shader,vertex-buffer,C++,Opengl,Glsl,Shader,Vertex Buffer,在一个典型的顶点数组缓冲区构建中,我试图将一个无符号int属性与其他经典属性(顶点、法线、纹理坐标…)一起传递。但是,该属性的值以某种方式错误告终:我不确定该值是否错误,或者该属性只是没有设置 从一个简单的例子开始,假设我已经定义了以下C++输入结构: struct buffer_data_t { glm::vec3 vertex; glm::vec3 normal; glm::vec2 texCoords; }; struct buffer_data_t {

在一个典型的顶点数组缓冲区构建中,我试图将一个无符号int属性与其他经典属性(顶点、法线、纹理坐标…)一起传递。但是,该属性的值以某种方式错误告终:我不确定该值是否错误,或者该属性只是没有设置

从一个简单的例子开始,假设我已经定义了以下C++输入结构:

struct buffer_data_t
{
    glm::vec3 vertex;
    glm::vec3 normal;
    glm::vec2 texCoords;
};
struct buffer_data_t
{
    glm::vec3 vertex;
    glm::vec3 normal;
    glm::vec2 texCoords;
    unsigned int textureId; // <---
};
准备顶点数组的过程如下所示:

// 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;
介绍我的问题

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

C++数据结构:

struct buffer_data_t
{
    glm::vec3 vertex;
    glm::vec3 normal;
    glm::vec2 texCoords;
};
struct buffer_data_t
{
    glm::vec3 vertex;
    glm::vec3 normal;
    glm::vec2 texCoords;
    unsigned int textureId; // <---
};
调整片段着色器以使输入平坦(为了示例起见),颜色贴图现在是一个数组,我们可以从中选择:

...
uniform sampler2D ColourMaps[2];
in flat unsigned int FS_TextureId;
...
texture2D(ColourMaps[FS_TextureId], ... );
由于顶点着色器输入属性“VS_TextureId”,这些更改不起作用。通过不使用unsigned int类型,而是使用vec2(或vec3,两种方式都可以),我能够证明这一点(并找到一种解决方法)。即:

VS:

财政司司长:

我的假设

我猜这是线路的故障,尽管我不知道如何/为什么:

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”)”的结果,结果是正确的,这意味着顶点着色器中的属性定义良好并已找到


你能看到问题是什么吗?

< P>如果你想用一个完整的数据类型来指定属性数组,那么你必须使用(在函数名称的中间关注代码< > <代码> >,而不是<代码> GrVistaTrBiTrimult.P/> 看

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

所有其他
VertexAttrib*
命令指定直接转换为内部浮点表示形式的值

这意味着顶点属性的规格必须为:

//glvertexattributepointer(shadInputs[3],1,GL\u UNSIGNED\u INT,GL\u 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));

总的来说,你试着用韭菜做的事情不是这样的。一组采样器的索引必须是“动态统一的”。这意味着所有片段的索引必须“相同”(例如常数或统一变量)

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

我建议使用单个
TEXTURE\u 2D\u数组
纹理,而不是
TEXTURE\u 2D
纹理数组。请参阅。

在这种情况下,可以使用三维浮点纹理坐标

仅供参考:不透明类型数组(如采样器)的索引必须是动态统一的值。而且
FS_TextureId
不是一个(除非渲染命令中的每个三角形都获得相同的值)!谢谢你,我就知道那一定是些小而愚蠢的东西!在将您的答案标记为已接受之前,我将尝试您的解决方案(尽管我相信它会解决问题)。再次感谢你@很抱歉,我没有把问题读到最后,我只是读到了顶点规范。阅读对你的问题的评论(关于@Nicolabolas)。你想要达到的目标不是这样的。我建议使用
TEXTURE\u 2D\u ARRAY
实际上我被@Nicolabolas的评论弄糊涂了-我只是按照你的建议尝试使用IPointer,现在一切都正常了(就像我以前的解决方法一样)-这意味着我确实能够在同一渲染过程中基于该属性选择不同的纹理(当然,一个给定的面,也就是顶点三元组有相同的纹理索引)@Smoove我明白了。你使用哪种硬件和OpenGL版本?@Smoove硬件供应商经常超越规范,分别提供扩展,这些扩展不是标准的一部分(目前)在这一点上,规范非常明确,它说如果
FS_TextureId
是一个输入变量,那么
colormaps[FS_TextureId]
是未定义的。但请注意,它并没有说它不允许工作。
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)));