纹理图像无法正确显示 - OpenGL

时间:2015-04-05 21:33:08

标签: c++ opengl

我正在尝试使用OpenGL 3.30使用Shader程序学习显示纹理。我能够加载图像,但我无法在每个立方体的脸上正确显示它。

下面的代码定义了顶点的属性,它是与每个立方体顶点关联的顶点和纹理坐标。然后创建2个VBO,一个保存立方体顶点,另一个保存纹理信息。

我认为我对最终结果非常接近:我获得了立方体,成功加载了图像,能够获取图像信息。那么我在这里做错了什么呢?

我正在使用stblib加载图片。

这是我的代码:

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h> /* must include for the offsetof macro */
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <stdlib.h>
#include "utils.h"

#include "stb_image.h"

struct Vertex {
    GLdouble position[3];
    GLdouble texture[2];
    };
/* These pointers will receive the contents of our shader source code files */
GLchar *vertexsource, *fragmentsource;
/* These are handles used to reference the shaders */
GLuint vertexshader, fragmentshader;
/* This is a handle to the shader program */
GLuint shaderprogram;
GLuint vbo[1]; /* Create handles for our Vertex Array Object and One Vertex Buffer Object */

//GLuint text_2d_1;

const struct Vertex plane[24] = {
                // Front Face
        {{1.0f,  1.0f, 1.0f}, {0.0, 0.0}},
        {{-1.0f,  1.0f, 1.0f}, {1.0, 0.0}},
        {{-1.0f, -1.0f, 1.0f}, {1.0, 1.0}},
        {{ 1.0f, -1.0f, 1.0f},  {0.0, 1.0}},
        // Back Face
        {{-1.0f, -1.0f, -1.0f}, {1.0, 0.0}},
        {{-1.0f,  1.0f, -1.0f}, {1.0, 1.0}},
        {{ 1.0f,  1.0f, -1.0f}, {0.0, 1.0}},
        {{ 1.0f, -1.0f, -1.0f}, {0.0, 0.0}},
        // Top Face
        {{-1.0f,  1.0f, -1.0f}, {0.0, 1.0}},
        {{-1.0f,  1.0f,  1.0f}, {0.0, 0.0}},
        {{ 1.0f,  1.0f,  1.0f}, {1.0, 0.0}},
        {{ 1.0f,  1.0f, -1.0f}, {1.0, 1.0}},
        // Bottom Face
        {{-1.0f, -1.0f, -1.0f}, {1.0, 1.0}},
        {{ 1.0f, -1.0f, -1.0f}, {0.0, 1.0}},
        {{ 1.0f, -1.0f,  1.0f}, {0.0, 0.0}},
        {{-1.0f, -1.0f,  1.0f}, {1.0, 0.0}},
        // Right face
        {{1.0f, -1.0f, -1.0f}, {1.0, 0.0}},
        {{1.0f,  1.0f, -1.0f}, {1.0, 1.0}},
        {{1.0f,  1.0f,  1.0f}, {0.0, 1.0}},
        {{1.0f, -1.0f,  1.0f}, {0.0, 0.0}},
        // Left Face
        {{-1.0f, -1.0f, -1.0f}, {0.0, 0.0}},
        {{-1.0f, -1.0f,  1.0f}, {1.0, 0.0}},
        {{-1.0f,  1.0f,  1.0f}, {1.0, 1.0}},
        {{-1.0f,  1.0f, -1.0f}, {0.0, 1.0}}

};

void SetupGeometry() {
    /* Allocate and assign One Vertex Buffer Object to our handle */
    glGenBuffers(1, vbo);
    /* Bind our VBO as being the active buffer and storing vertex attributes (coordinates + colors) */
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    /* Copy the vertex data from plane to our buffer */
    /* 12 * sizeof(GLfloat) is the size of the tetrahedrom array, since it contains 12 Vertex values */
    glBufferData ( GL_ARRAY_BUFFER, 24 * sizeof ( struct Vertex ), plane, GL_STATIC_DRAW );
    /* Specify that our coordinate data is going into attribute index 0, and contains three doubles per vertex */
    /* Note stride = sizeof ( struct Vertex ) and pointer = ( const GLvoid* ) 0 */
    glVertexAttribPointer ( ( GLuint ) 0, 3, GL_DOUBLE, GL_FALSE,  sizeof ( struct Vertex ), ( const GLvoid* ) offsetof (struct Vertex,position) );
    /* Enable attribute index 0 as being used */
    glEnableVertexAttribArray(0);
    /* Specify that our color data is going into attribute index 1, and contains three floats per vertex */
    /* Note stride = sizeof ( struct Vertex ) and pointer = ( const GLvoid* ) ( 3 * sizeof ( GLdouble ) ) i.e. the size (in bytes)
     occupied by the first attribute (position) */
    glVertexAttribPointer ( ( GLuint ) 1, 3, GL_FLOAT, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof(struct Vertex,texture) ); // bug );
    /* Enable attribute index 1 as being used */
    glEnableVertexAttribArray ( 1 );/* Bind our fourth VBO as being the active buffer and storing vertex attributes (texture) */
    printf("vertex %d\n", offsetof(struct Vertex,position));
    printf("texture %d\n", offsetof(struct Vertex,texture));
}

void SetupShaders(void) {
    /* Read our shaders into the appropriate buffers */
    vertexsource = filetobuf("plane/plane.vert");
    fragmentsource = filetobuf("plane/plane.frag");
    /* Assign our handles a "name" to new shader objects */
    vertexshader = glCreateShader(GL_VERTEX_SHADER);
    fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
    /* Associate the source code buffers with each handle */
    glShaderSource(vertexshader, 1, (const GLchar**)&vertexsource, 0);
    glShaderSource(fragmentshader, 1, (const GLchar**)&fragmentsource, 0);
    /* Compile our shader objects */
    glCompileShader(vertexshader);
    glCompileShader(fragmentshader);
    /* Assign our program handle a "name" */
    shaderprogram = glCreateProgram();
    glAttachShader(shaderprogram, vertexshader);/* Attach our shaders to our program */
    glAttachShader(shaderprogram, fragmentshader);
    glBindAttribLocation(shaderprogram, 0, "in_Position"); /* Bind attribute 0 (coordinates) to in_Position and attribute 1 (colors) to in_Texture */
    glBindAttribLocation(shaderprogram, 1, "in_Texture");
    glLinkProgram(shaderprogram);/* Link our program, and set it as being actively used */
    glUseProgram(shaderprogram);
    }

void Render(int i) {
    GLfloat angle;
    glm::mat4 Projection = glm::perspective(45.0f, 1.0f, 0.1f, 100.0f);
    angle = (GLfloat) (i % 360);
    glm::mat4 View = glm::mat4(1.);
    View = glm::translate(View, glm::vec3(0.f, 0.f, -5.0f));
    View = glm::rotate(View, angle * -1.0f, glm::vec3(1.f, 0.f, 0.f));
    View = glm::rotate(View, angle * 0.5f, glm::vec3(0.f, 1.f, 0.f));
    View = glm::rotate(View, angle * 0.5f, glm::vec3(0.f, 0.f, 1.f));
    glm::mat4 Model = glm::mat4(1.0);
    glm::mat4 MVP = Projection * View * Model;
    glUniformMatrix4fv(glGetUniformLocation(shaderprogram, "mvpmatrix"), 1, GL_FALSE, glm::value_ptr(MVP));
    /* Bind our modelmatrix variable to be a uniform called mvpmatrix in our shaderprogram */
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDrawArrays(GL_QUADS, 0, 24);
    /* Invoke glDrawArrays telling that our data consists of individual triangles */
}

int reverse = 1;

static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
    if ((key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
    if ((key == GLFW_KEY_R) && action == GLFW_PRESS)
        reverse = 1 - reverse; // togrls reverse from 0 to 1 to o to ...
    }


int main( void ) {
    int k = 0;
    GLFWwindow* window;
    if( !glfwInit() ) {
            printf("Failed to start GLFW\n");
            exit( EXIT_FAILURE );
            }
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window) {
            glfwTerminate();
            printf("GLFW Failed to start\n");
            return -1;
            }
    /* Make the window's context current */
    glfwMakeContextCurrent(window); // IMPORTANT: Must be done so glew recognises OpenGL
    glewExperimental = GL_TRUE;
    int err = glewInit();
    if (GLEW_OK != err) {
            /* Problem: glewInit failed, something is seriously wrong. */
            fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
            }
    fprintf(stderr, "Glew done\n");
    glfwSetKeyCallback(window, key_callback);
    fprintf(stderr, "GL INFO %s\n", glGetString(GL_VERSION));
    SetupGeometry();
    SetupShaders();
    int w, h, n, O;
    char *filename = "plane/rock.bmp";
    unsigned char * data = stbi_load(filename, &w, &h, &n, 0); //image data
    if(data == NULL) {
        print("Image not loaded");
        const char *error = stbi_failure_reason();
        printf("Failure reason %s\n", error);
        exit(0);
    }else{
        print("Image loaded successfully");
    }
    printf("Image Stats %d %d %d\n", w, h, n);
//    for(int d = 0; d < w * h * 3; d++)
//        printf("img content: %i\n",data[d]);
    printf (" first 4 bytes are: %i %i %i %i\n", data[ 0], data[ 1], data[ 2], data[ 3] );

    GLuint tex;
    glGenTextures(1, &tex);
    Print("Texture");
    Print(GL_TEXTURE0);
    print((int) tex);
    //glActiveTexture(GL_TEXTURE0);
    /*
     * To get the texture to activate, take the base texture GL_TEXTURE0 and add the value of the generated texture.
     * This needs checking with more than one texture.
     * beware of NIDIA specific.
     */
     //glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
    glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    stbi_image_free(data); // free up image data
    //glDisable(gl_te)

    glEnable(GL_DEPTH_TEST);
    glClearColor(0.0, 0.0, 0.0, 1.0);/* Make our background black */
    while( !glfwWindowShouldClose(window) ) {// Main loop
        Render(k);// OpenGL rendering goes here...
            if(reverse)
                k--;
            else
                k++;

        Sleep(20);
        glfwSwapBuffers(window);// Swap front and back rendering buffers
        glfwPollEvents();
        }
    glfwTerminate();// Close window and terminate GLFW
    exit( EXIT_SUCCESS );// Exit program
    }

顶点着色器:

#version 330
precision highp float;
in vec3 in_Position;
in vec2 in_Texture;

// mvpmatrix is the result of multiplying the model, view, and projection matrices */
uniform mat4 mvpmatrix;

out vec2 UV;
void main(void) {
// Multiply the mvp matrix by the vertex to obtain our final vertex position
    gl_Position = mvpmatrix * vec4(in_Position, 1.0);
    UV = in_Texture;
}

片段着色器:

#version 330
precision highp float;

in  vec2 UV;

out vec3 color;

uniform sampler2D myTexture;

void main(void) {
    color = texture(myTexture, UV).rgb;
}

这是输入图片: rock.bmp

这是程序的输出: output

2 个答案:

答案 0 :(得分:2)

问题在于:

/* Specify that our color data is going into attribute index 1,
   and contains three floats per vertex */
/* Note stride = sizeof ( struct Vertex ) and
   pointer = ( const GLvoid* ) ( 3 * sizeof ( GLdouble ) )
   i.e. the size (in bytes) occupied by the first attribute
   (position) */
glVertexAttribPointer ( ( GLuint ) 1, 3, GL_FLOAT, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof(struct Vertex,texture) );

顶点纹理坐标属性有两个元素,但是你告诉OpenGL连续有3个元素。这显然既不匹配您的顶点数据也不匹配着色器顶点属性类型。将元素大小调整为2,它应该工作。哦,你不必明确地将数字文字强制转换为GLuint

答案 1 :(得分:2)

您使用的数据类型存在一些不一致。结构的声明对位置和纹理坐标使用双精度:

struct Vertex {
    GLdouble position[3];
    GLdouble texture[2];
};

在属性设置期间,您使用的是不同的类型:

glVertexAttribPointer ( ( GLuint ) 0, 3, GL_DOUBLE, GL_FALSE,  sizeof ( struct Vertex ), ( const GLvoid* ) offsetof (struct Vertex,position) );
glVertexAttribPointer ( ( GLuint ) 1, 3, GL_FLOAT, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof(struct Vertex,texture) ); // bug );

纹理坐标在此处用作GL_FLOAT。此外,您在此处指定3个组件,其中struct只有2个。

很少有理由使用双打坐标。无论如何,OpenGL内部将使用32位精度。因此,如果您将属性指定为双精度数,则只会添加转换数,并使用更多内存。

要将float用于所有内容,结构应该声明如下:

struct Vertex {
    GLfloat position[3];
    GLfloat texture[2];
};

属性规范如下所示:

glVertexAttribPointer ( ( GLuint ) 0, 3, GL_FLOAT, GL_FALSE,  sizeof ( struct Vertex ), ( const GLvoid* ) offsetof (struct Vertex,position) );
glVertexAttribPointer ( ( GLuint ) 1, 2, GL_FLOAT, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof(struct Vertex,texture) ); // bug );