[英]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.