2017-09-13 126 views
4

我有一个非常简单的程序,它将红色虚拟贴图映射到四边形。未能将简单的无符号字节rgb贴图映射到四边形:

这里是C++纹理定义:

struct DummyRGB8Texture2d 
{ 
    uint8_t data[3*4]; 
    int width; 
    int height; 

}; 

DummyRGB8Texture2d myTexture 
{ 
    { 
     255,0,0, 
     255,0,0, 
     255,0,0, 
     255,0,0 
    }, 
    2u, 
    2u 
}; 

这是我如何设置纹理:

void SetupTexture() 
{ 
    // allocate a texture on the default texture unit (GL_TEXTURE0): 

    GL_CHECK(glCreateTextures(GL_TEXTURE_2D, 1, &m_texture)); 

    // allocate texture: 
    GL_CHECK(glTextureStorage2D(m_texture, 1, GL_RGB8, myTexture.width, myTexture.height)); 

    GL_CHECK(glTextureParameteri(m_texture, GL_TEXTURE_WRAP_S, GL_REPEAT)); 
    GL_CHECK(glTextureParameteri(m_texture, GL_TEXTURE_WRAP_T, GL_REPEAT)); 
    GL_CHECK(glTextureParameteri(m_texture, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); 
    GL_CHECK(glTextureParameteri(m_texture, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); 

    // tell the shader that the sampler2d uniform uses the default texture unit (GL_TEXTURE0) 
    GL_CHECK(glProgramUniform1i(m_program->Id(), /* location in shader */ 3, /* texture unit index */ 0)); 

    // bind the created texture to the specified target. this is necessary even in dsa 
    GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_texture)); 

    GL_CHECK(glGenerateMipmap(GL_TEXTURE_2D)); 
} 

这是我画的质感成四:

void Draw() 
{ 
    m_target->ClearTargetBuffers(); 
    m_program->MakeCurrent(); 

    // load the texture to the GPU: 
    GL_CHECK(glTextureSubImage2D(m_texture, 0, 0, 0, myTexture.width, myTexture.height, 
      GL_RGB, GL_UNSIGNED_BYTE, myTexture.data)); 

    GL_CHECK(glBindVertexArray(m_vao));  

    GL_CHECK(glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(VideoQuadElementArray.size()), GL_UNSIGNED_INT, 0)); 
     m_target->SwapTargetBuffers(); 
} 

结果:

enter image description here

我不明白为什么这个纹理不会出现红色。另外,如果我将纹理内部格式更改为RGB,并且纹理数据数组在每一行中都有另一个元素,我会得到一个很好的红色纹理。


在情况下,其相关的,这里是我的顶点属性和我的(很简单)着色器:

struct VideoQuadVertex 
{ 
    glm::vec3 vertex; 
    glm::vec2 uv; 
}; 

std::array<VideoQuadVertex, 4> VideoQuadInterleavedArray 
{ 
    /* vec3 */ VideoQuadVertex{ glm::vec3{ -0.25f, -0.25f, 0.5f }, /* vec2 */ glm::vec2{ 0.0f, 0.0f } }, 
    /* vec3 */ VideoQuadVertex{ glm::vec3{ 0.25f, -0.25f, 0.5f }, /* vec2 */ glm::vec2{ 1.0f, 0.0f } }, 
    /* vec3 */ VideoQuadVertex{ glm::vec3{ 0.25f, 0.25f, 0.5f }, /* vec2 */ glm::vec2{ 1.0f, 1.0f } }, 
    /* vec3 */ VideoQuadVertex{ glm::vec3{ -0.25f, 0.25f, 0.5f }, /* vec2 */ glm::vec2{ 0.0f, 1.0f } } 


}; 

顶点设置:

void SetupVertexData() 
{ 


// create a VAO to hold all node rendering states, no need for binding: 
    GL_CHECK(glCreateVertexArrays(1, &m_vao)); 

// create vertex buffer objects for data and indices and initialize them: 
GL_CHECK(glCreateBuffers(static_cast<GLsizei>(m_vbo.size()), m_vbo.data())); 

// allocate memory for interleaved vertex attributes and transfer them to the GPU: 
GL_CHECK(glNamedBufferData(m_vbo[EVbo::Data], VideoQuadInterleavedArray.size() * sizeof(VideoQuadVertex), VideoQuadInterle 

GL_CHECK(glVertexArrayAttribBinding(m_vao, 0, 0)); 
GL_CHECK(glVertexArrayVertexBuffer(m_vao, 0, m_vbo[EVbo::Data], 0, sizeof(VideoQuadVertex))); 


// setup the indices array: 
GL_CHECK(glNamedBufferData(m_vbo[EVbo::Element], VideoQuadElementArray.size() * sizeof(GLuint), VideoQuadElementArray.data 
GL_CHECK(glVertexArrayElementBuffer(m_vao, m_vbo[EVbo::Element])); 

// enable the relevant attributes for this VAO and 
// specify their format and binding point: 

// vertices: 
GL_CHECK(glEnableVertexArrayAttrib(m_vao, 0 /* location in shader*/)); 
GL_CHECK(glVertexArrayAttribFormat(
    m_vao, 
    0,     // attribute location 
    3,     // number of components in each data member 
    GL_FLOAT,   // type of each component 
    GL_FALSE,   // should normalize 
    offsetof(VideoQuadVertex, vertex) // offset from the begining of the buffer 
)); 

// uvs: 
GL_CHECK(glEnableVertexArrayAttrib(m_vao, 1 /* location in shader*/)); 
GL_CHECK(glVertexAttribFormat(
    1,         // attribute location 
    2,         // number of components in each data member 
    GL_FLOAT,       // type of each component 
    GL_FALSE,       // should normalize 
    offsetof(VideoQuadVertex, uv) // offset from the begining of the buffer 
)); 

GL_CHECK(glVertexArrayAttribBinding(m_vao, 1, 0)); 

} 

顶点着色器:

layout(location = 0) in vec3 position; 
layout(location = 1) in vec2 texture_coordinate; 


out FragmentData 
{ 
    vec2 uv; 
} toFragment; 


void main(void) 
{ 
    toFragment.uv = texture_coordinate; 
    gl_Position = vec4 (position, 1.0f); 
} 

片段着色器:

in FragmentData 
{ 
    vec2 uv; 
} data; 

out vec4 color; 

layout (location = 3) uniform sampler2D tex_object; 

void main() 
{ 
    color = texture(tex_object, data.uv); 
} 
+2

我猜你离开了'GL_UNPACK_ALIGNMENT'在4默认值,这会使得GL期待一些填充字节在您的客户端阵列的每一行的末尾。有关详细信息,请参见[常见错误:OpenGL wiki中的纹理上传和像素读取](https://www.khronos.org/opengl/wiki/Common_Mistakes#Texture_upload_and_pixel_reads)。 – derhass

+0

'glPixelStorei(GL_UNPACK_ALIGNMENT,1);''glTextureSubImage2D'之前'' – Rabbid76

回答

4

GL_UNPACK_ALIGNMENT指定存储器中每个像素行开始的对齐要求。默认情况下,GL_UNPACK_ALIGNMENT设置为4. 这意味着纹理的每行应具有4 * N字节的长度。

你指定一个2×2的纹理与数据:255,0,0,255,0,0,255,0,0,255,0,0

随着GL_UNPACK_ALIGNMENT集到4这被解释作为

  column 1   column 2    alignment 
row 1: 255, 0, 0,  255, 0,  0,  255, 0, 
row 2: 0, 255, 0,  0, undef, undef 

所以纹理被读作

  column 1 olumn 2 
row 1: red,  red, 
row 2: green,  RGB(0, ?, ?) 


你必须glTextureSubImage2D之前设置glPixelStorei(GL_UNPACK_ALIGNMENT, 1);,用于读取TI ght包装的纹理。


如果你不想改变GL_UNPACK_ALIGNMENT(取向保持设定为4)时,您必须将数据适应这样的:

struct DummyRGB8Texture2d 
{ 
    uint8_t data[8*2]; 
    int width; 
    int height; 
}; 

DummyRGB8Texture2d myTexture 
{ 
    { 
     255, 0, 0, 255, 0, 0, // row 1 
     0, 0,     // 2 bytes alignment 
     255, 0, 0, 255, 0, 0, // row 2 
     0, 0     // 2 bytes alignment 
    }, 
    2u, 
    2u 
}; 


另见: