簡體   English   中英

將無符號整數輸入屬性傳遞給頂點着色器

[英]Passing unsigned int input attribute to vertex shader

在典型的頂點數組緩沖區構建中,我試圖將一個 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;

介紹我的問題

到目前為止一切順利,使用上面的代碼我可以成功渲染紋理基元。 現在我想 select 不同的顏色貼圖取決於被渲染的臉。 為此,我想引入一個索引作為頂點屬性的一部分。 變化是:

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;

調整片段着色器使輸入變平(同樣為了示例)顏色 map 現在是一個我們可以從中選擇的數組:

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

由於頂點着色器輸入屬性“VS_TextureId”,這些更改不會特別有效。 我能夠通過不使用 unsigned int 類型而是求助於 vec2(或 vec3,無論哪種方式都有效)來證明這一點(並找到解決方法)。 那是:

對比:

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

注意:我檢查了 'shader.attribute("VS_TextureId")' 的結果,它是正確的,這意味着頂點着色器中的屬性已明確定義並找到。

你能看出問題所在嗎?

如果要指定具有整數數據類型的屬性數組,則必須使用glVertexAttribIPointer (關注 function 名稱中間的I ),而不是glVertexAttribPointer

參見OpenGL 4.6 API Core Profile Specification; 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 頁)

紋理組合采樣器類型是不透明類型,其聲明和行為如上文針對不透明類型所述。 當在shader中聚合成arrays時,只能用動態統一的整數表達式來索引,否則結果是未定義的。 [...]

我建議使用單個TEXTURE_2D_ARRAY紋理,而不是TEXTURE_2D紋理數組。 請參見紋理
在這種情況下,您可以使用 3 維浮點紋理坐標。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM