带纹理的三角形作为纯色加载

时间:2019-06-14 04:47:21

标签: c opengl textures

我正在尝试渲染带纹理的三角形。我正在使用机顶盒图像加载png。对于我尝试过的许多不同图像,三角形显示为单色。颜色似乎是图像中显示的全部颜色的平均值。

我研究了许多类似问题的解决方案,并确保(或我认为)我没有陷入常见的“陷阱”:被称为glEnable(GL_TEXTURE_2D)。我对glVertexAttribPoitners()的呼叫设置正确。我试图告诉OpenGl我不想对glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)使用mipmapping,并且已经通过glEnableVertexAttribArray()启用了相关的顶点数组。我的着色器编译没有错误。

#include <practice/practice.h>
#include <test_dep/stb_image.h>


void
initRenderer_practice()
{
    const char* vertex_shader = GLSL(450 core,

                                     layout (location = 0) in vec2 vCoords;
                                     layout (location = 1) in vec2 tCoords;

                                     out vec2 ftCoords;

                                     void main()
                                     {
                                         gl_Position = vec4(vCoords.x, vCoords.y, 0.0, 1.0);
                                         ftCoords = tCoords;
                                     }

        );

    const char* fragment_shader = GLSL(450 core,

                                       uniform sampler2D texture_data;
                                       in vec2 ftCoords;
                                       out vec4 fragColor;

                                       void main()
                                       {
                                           fragColor = texture(texture_data, ftCoords.st);
                                       }
        );


    GLfloat vCoordsLocal[] =
        {
            //
            // POSITION COORDS
            //
            // bottom left
            -0.5, -0.5,

            // bottom right
            0.5, -0.5,

            // top center
            0.0, 0.5,

            //
            // TEXTURE COORDS
            //
            // left bottom
            0.0, 0.0,

            // right bottom
            1.0, 0.0,

            // center top
            0.5, 1.0,
        };

    if (!practice_target)
    {
        practice_target = (uGLRenderTarget*)malloc(sizeof(uGLRenderTarget));
        practice_target->shader_program = 0;
        practice_target->vertex_array_object = (GLuint) -1;
        practice_target->vertex_buffer_object = (GLuint) -1;
    }

    practice_target->shader_program = uGLCreateShaderProgram_vf(&vertex_shader,
                                                                &fragment_shader);
    assert(practice_target->shader_program);
    glUseProgram(practice_target->shader_program);
    glError;

    glGenVertexArrays(1, &practice_target->vertex_array_object);
    glBindVertexArray(practice_target->vertex_array_object);
    glError;

    glGenBuffers(1, &practice_target->vertex_buffer_object);
    glBindBuffer(GL_ARRAY_BUFFER, practice_target->vertex_buffer_object);
    glBufferData(GL_ARRAY_BUFFER,
                 sizeof(vCoordsLocal),
                 vCoordsLocal,
                 GL_STATIC_DRAW);
    glError;

    glGenTextures(1, &practice_target->texture_id);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, practice_target->texture_id);
    practice_target->shdr_texture_2d_location = glGetUniformLocation(practice_target->shader_program, "texture_data");
    glUniform1i(practice_target->shdr_texture_2d_location, 0);
    assert(practice_target->shdr_texture_2d_location != -1);
    glError;

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glError;


    stbi_set_flip_vertically_on_load(true);
    u8* texture_data = NULL;
    GLint width, height, channels = 0;
    texture_data = stbi_load("./assets/index.png", &width, &height, &channels, 0);
    if (texture_data)
    {
        /*
        void glTexImage2D(GLenum target,
                          GLint level,
                          GLint internalFormat,
                          GLsizei width,
                          GLsizei height,
                          GLint border,
                          GLenum format,
                          GLenum type,
                          const GLvoid * data);
        */
        glTexImage2D(GL_TEXTURE_2D,
                     0,
                     GL_RGB,
                     width,
                     height,
                     0,
                     GL_RGB,
                     GL_UNSIGNED_BYTE,
                     texture_data);
        glGenerateMipmap(GL_TEXTURE_2D);
        glError;

        printf("\n\n numchannels: %d\n\n", channels);
    }
    else
    {
        puts("[ debug ] Load texture failed\n");
        assert(0);
    }

    stbi_image_free(texture_data);

    /*
      void glVertexAttribPointer(GLuint index,
      GLint size,
      GLenum type,
      GLboolean normalized,
      GLsizei stride,
      const GLvoid * pointer);
    */

    // Vertex coordinate attribute
    glVertexAttribPointer(0,
                          2,
                          GL_FLOAT,
                          GL_FALSE,
                          0,
                          (void*) 0);
    glEnableVertexAttribArray(0);

    // Texture coordinate attribute
    glVertexAttribPointer(1,
                          2,
                          GL_FLOAT,
                          GL_FALSE,
                          0,
                          (void*) 6);
    glEnableVertexAttribArray(1);
    glError;

    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glUseProgram(0);
    glError;
}

void
render_practice()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(practice_target->shader_program);

    glEnable(GL_TEXTURE_2D);
    glBindVertexArray(practice_target->vertex_array_object);
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, practice_target->texture_id);
    glDrawArrays(GL_TRIANGLES, 0, 3);

    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glUseProgram(0);
    glError;
}

预期结果是将纹理映射到三角形上,而不是单色上。

1 个答案:

答案 0 :(得分:2)

纹理坐标的顶点属性规范未对齐。
属性的内存布局为

x0 y0, x1, y1, x2, y2,   u0 v0, u1, v1, u2, v2

因此,第一个纹理坐标是缓冲区中的第6个元素。

但是,glVertexAttribPointer的最后一个参数是缓冲区对象数据存储区中的 byte 偏移量。
这意味着偏移量必须为6*sizeof(GLfloat)而不是6

glVertexAttribPointer(1,
                      2,
                      GL_FLOAT,
                      GL_FALSE,
                      0,
                      (void*)(6*sizeof(GLfloat)); // <-----

我建议将顶点属性的排列更改为可扩展的布局:

x0 y0 u0 v0    x1 y1 u1 v1    x2 y2 u2 v2   ...

并使用相应的顶点属性规范:

GLsizei stride     = (GLsizei)(4*sizeof(GLfloat)); // 4 because of (x, y, u ,v)
void*   vertOffset = (void*)(0);                   // 0 because the vertex coords are 1st
void*   texOffset  = (void*)(2*sizeof(GLfloat));   // 2 because u, v are after x, y

// Vertex coordinate attribute
glVertexAttribPointer(0,
                      2,
                      GL_FLOAT,
                      GL_FALSE,
                      stride,
                      vertOffset);
glEnableVertexAttribArray(0);

// Texture coordinate attribute
glVertexAttribPointer(1,
                      2,
                      GL_FLOAT,
                      GL_FALSE,
                      stride,
                      texOffset;
glEnableVertexAttribArray(1);