OpenGL纹理无法呈现

时间:2017-12-06 02:50:48

标签: c++ opengl glfw

我目前正在尝试学习OpenGL。我已成功地将彩虹三角形渲染到屏幕上,并且我已成功地将它们移动到屏幕上。 但是,我似乎无法正确地将纹理渲染为两个三角形。

每当我运行这个程序时,我都会看到一个没有任何渲染的黑屏。我已经检查了,图像文件肯定在正确的目录中(否则不会运行!)

define STB_IMAGE_IMPLEMENTATION

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <stb/stb_image.h>

int main()
{
    //Initialize glfw
    if (!glfwInit())
    {
        fprintf(stderr, "ERROR: Could not start GLFW3.\n");
        return 1;
    }

    //Create the rendering context
    GLFWwindow* window = glfwCreateWindow(480, 600, "Hello Rendering",
                                          nullptr, nullptr);

    if(!window)
    {
        fprintf(stderr, "ERROR: Could not create a rendering context with "
            "GLFW3.\n");
        return 1;
    }

    glfwMakeContextCurrent(window);

    //Start GLEW
    glewExperimental=GL_TRUE;
    GLenum err=glewInit();
    if(err!=GLEW_OK)
    {
        //Problem: glewInit failed, something is seriously wrong.
        std::cout<<"glewInit failed, aborting."<<std::endl;
    }



    ////////////////////////
    //Loading PNG
    ////////////////////////
    int x = 0;
    int y = 0;
    int n = 0;
    int force_channels = 4;
    unsigned char* image_data = stbi_load("spooky.png", &x, &y, &n,
                                          force_channels);
    if(!image_data)
    {
        fprintf(stderr, "ERROR: Could not load spooky.png\n.");
        return 1;
    }

    //NPOT Check
    if((x & (x - 1)) != 0 || (y & (y - 1)) != 0)
    {
        fprintf(stderr, "ERROR: Image is not a power of 2.\n");
        fprintf(stderr, "h: %d w: %d", y, x);
        return 1;
    }

    //Flip the image
    int width_in_bytes = x * 4;
    unsigned char* top = nullptr;
    unsigned char* bottom = nullptr;
    unsigned char temp = 0;
    int half_height = y / 2;

    for(int row = 0; row < half_height; row++)
    {
        top = image_data + row * width_in_bytes;
        bottom = image_data + (y - row - 1) * width_in_bytes;
        for(int col = 0; col < width_in_bytes; col++)
        {
            temp = *top;
            *top = *bottom;
            *bottom = temp;
            top++;
            bottom++;
        }
    }


    GLuint tex = 0;
    glGenTextures(1, &tex);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA,
                 GL_UNSIGNED_BYTE, image_data);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);


    //////////////////////////////////
    //Vertex shader
    //////////////////////////////////
    const char* vertShader =
        "#version 330 core"
        "layout(location = 0) in vec3 vertexPosition_modelspace;"
        "layout(location = 1) in vec2 vt;"
        "out vec2 texture_coordinates;"
        "void main() {"
        "   texture_coordinates = vt;"
        "   gl_Position.xyz = vertexPosition_modelspace;"
        "   gl_Position.w = 1.0;"
        "}";

    ///////////////////////////////////
    //Frag shader
    ///////////////////////////////////
    const char* fragShader =
        "#version 330 core"
        "uniform sampler2D basic_texture;"
        "out vec4 frag_color;"
        "void main() {"
        "   vec4 texel = texture(basic_texture, texture_coordinates);"
        "   frag_color = texel;"
        "}";


    ////////////////////////////////////
    //Create shader program
    ///////////////////////////////////
    GLuint vsp = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vsp, 1, &vertShader,  nullptr);
    glCompileShader(vsp);

    GLuint fsp = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fsp, 1, &fragShader, nullptr);
    glCompileShader(fsp);

    GLuint shader_program = glCreateProgram();
    glAttachShader(shader_program, fsp);
    glAttachShader(shader_program, vsp);
    glLinkProgram(shader_program);

    glUseProgram(shader_program);



    ////////////////////////////////////
    //Texture coordinates
    ////////////////////////////////////
    GLfloat texcoords[] = {
        0.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,
        1.0f, 0.0f,
        1.0f, 1.0f,
        0.0f, 1.0f
    };

    GLuint vt_vbo;
    glGenBuffers(1, &vt_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof( texcoords), texcoords,
                 GL_STATIC_DRAW);

    GLuint vao;;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
    int dimensions = 2;
    glVertexAttribPointer(1, dimensions, GL_FLOAT, GL_FALSE, 0, nullptr);
    glEnableVertexAttribArray(1);

    while(!glfwWindowShouldClose(window))
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        //Use the shader
        glUseProgram(shader_program);
        //Draw the two triangles (6 points)
        glDrawArrays(GL_TRIANGLES, 0, 6);
        glfwPollEvents();
        glfwSwapBuffers(window);
        if(GLFW_PRESS == glfwGetKey(window, GLFW_KEY_ESCAPE))
        {
            glfwSetWindowShouldClose(window, 1);
        }
    }

    std::cout << "Hello, World!" << std::endl;
    return 0;
}

1 个答案:

答案 0 :(得分:1)

首先,您应该在编译和链接着色器时检索错误消息:

GLint status = GL_TRUE;
char error_msg[1024];
GLsizei read;

GLuint vsp = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vsp, 1, &vertShader,  nullptr);
glCompileShader(vsp);
glGetShaderiv( vsp, GL_COMPILE_STATUS, &status );
if ( status != GL_TRUE )
{
    glGetShaderInfoLog( vsp, 1024, &read, error_msg );
    std::cout << "compile error:" << std::endl << error_msg << std::endl;
}

GLuint fsp = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fsp, 1, &fragShader, nullptr);
glCompileShader(fsp);
glGetShaderiv( fsp, GL_COMPILE_STATUS, &status );
if ( status != GL_TRUE )
{
    glGetShaderInfoLog( fsp, 1024, &read, error_msg );
    std::cout << "compile error:" << std::endl << error_msg << std::endl;
}

GLuint shader_program = glCreateProgram();
glAttachShader(shader_program, fsp);
glAttachShader(shader_program, vsp);
glLinkProgram(shader_program);
glGetProgramiv( shader_program, GL_LINK_STATUS, &status );
if ( status != GL_TRUE )
{
    glGetProgramInfoLog( shader_program, 1024, &read, error_msg );
    std::cout << "compile error:" << std::endl << error_msg << std::endl;
}

您将收到的第一条错误消息是这样的:

  

0(1):错误C0205:无效的配置文件“corelayout”
  0(1):错误C0206:版本行中的令牌“”无效

这是因为您没有在着色器代码的第一行("\n")之后写下结束"#version 330 core"的行。

当您修复此问题时,您会收到下一条错误消息:

  

0(2):错误C1008:未定义变量“texture_coordinates”

您必须将in变量texture_coordinates的声明添加到片段着色器。

in vec2 texture_coordinates;

最终代码如下:

const char* vertShader =
    "#version 330 core\n"
    "layout(location = 0) in vec3 vertexPosition_modelspace;"
    "layout(location = 1) in vec2 vt;"
    "out vec2 texture_coordinates;"
    "void main() {"
    "   texture_coordinates = vt;"
    "   gl_Position.xyz = vertexPosition_modelspace;"
    "   gl_Position.w = 1.0;"
    "}";

const char* fragShader =
    "#version 330 core\n"
    "uniform sampler2D basic_texture;"
    "out vec4 frag_color;"
    "in vec2 texture_coordinates;"
    "void main() {"
    "   vec4 texel = texture(basic_texture, texture_coordinates);"
    "   frag_color = texel;"
    "}";


当然,您必须为顶点属性vertexPosition_modelspace提供顶点数据:

GLfloat texcoords[] = {
    0.0f, 1.0f,
    0.0f, 0.0f,
    1.0f, 0.0f,
    1.0f, 0.0f,
    1.0f, 1.0f,
    0.0f, 1.0f
};

GLfloat vertex[] = {
    -1.0f,  1.0f, 0.0f,
    -1.0f, -1.0f, 0.0f,
     1.0f, -1.0f, 0.0f,
     1.0f, -1.0f, 0.0f,
     1.0f,  1.0f, 0.0f,
    -1.0f,  1.0f, 0.0f
};

GLuint vert_vbo;
glGenBuffers(1, &vert_vbo);
glBindBuffer(GL_ARRAY_BUFFER, vert_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof( vertex ), vertex, GL_STATIC_DRAW);

GLuint vt_vbo;
glGenBuffers(1, &vt_vbo);
glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof( texcoords ), texcoords, GL_STATIC_DRAW);

GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vert_vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(1);


最后,您应该将纹理单元的索引(纹理绑定到的)设置为纹理采样器统一变量basic_texture

int texture_unit_index = 0;
GLuint tex = 0;
glGenTextures(1, &tex);
glActiveTexture(GL_TEXTURE0 + texture_unit_index );
glBindTexture(GL_TEXTURE_2D, tex);

.....

// to do after    glLinkProgram(shader_program);
int tex_sampler_loc = glGetUniformLocation( shader_program, "basic_texture" );

.....

// to do after    glUseProgram(shader_program);
glUniform1i( tex_sampler_loc, texture_unit_index );