在 OpenGL 中显示立方体的问题

Posted

技术标签:

【中文标题】在 OpenGL 中显示立方体的问题【英文标题】:Problems displaying cube in OpenGL 【发布时间】:2012-07-05 23:55:45 【问题描述】:

我目前正在尝试关注this tutorial。但是有一些问题,对于初学者来说,因为我在 Mac 上,GLSL 语言的最大值为 1.5(我决定使用 1.1)并且本教程需要 3.3,本教程也使用不同的窗口系统(我正在使用他们正在使用的 GLUT GLFW 请参阅here 以获取所有站点教程的完整源代码)。我目前已经重新安排了代码,让它在我的电脑上运行:

//OpenGL and GLEW
#include <GL/glew.h>
//Include GLUT
#ifdef __APPLE__
# include <GLUT/glut.h>
#else
# include <GL/glut.h>
#endif
//Some standard libraries
#include <vector>
#include <string>
#include <stdio.h>
#include <fstream>
#include <math.h>
//For transofmations.
#include "glm.hpp"
#include "transform.hpp"
//max macro for my Mac.
#define max( a, b ) ( ((a) > (b)) ? (a) : (b) )

//Vertex data for cube. Direct copy and paste for the coordinates from the website.
static const GLfloat g_vertex_buffer_data[] =  
        -1.0f,-1.0f,-1.0f,
        -1.0f,-1.0f, 1.0f,
        -1.0f, 1.0f, 1.0f,
        1.0f, 1.0f,-1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f, 1.0f,-1.0f,
        1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f,-1.0f,
        1.0f,-1.0f,-1.0f,
        1.0f, 1.0f,-1.0f,
        1.0f,-1.0f,-1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f,-1.0f,
        1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f, 1.0f, 1.0f,
        -1.0f,-1.0f, 1.0f,
        1.0f,-1.0f, 1.0f,
        1.0f, 1.0f, 1.0f,
        1.0f,-1.0f,-1.0f,
        1.0f, 1.0f,-1.0f,
        1.0f,-1.0f,-1.0f,
        1.0f, 1.0f, 1.0f,
        1.0f,-1.0f, 1.0f,
        1.0f, 1.0f, 1.0f,
        1.0f, 1.0f,-1.0f,
        -1.0f, 1.0f,-1.0f,
        1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f,-1.0f,
        -1.0f, 1.0f, 1.0f,
        1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f, 1.0f,
        1.0f,-1.0f, 1.0f
;

//Color data for cube. Direct copy and paste from the site.
static const GLfloat g_color_buffer_data[] = 
    0.583f,  0.771f,  0.014f,
    0.609f,  0.115f,  0.436f,
    0.327f,  0.483f,  0.844f,
    0.822f,  0.569f,  0.201f,
    0.435f,  0.602f,  0.223f,
    0.310f,  0.747f,  0.185f,
    0.597f,  0.770f,  0.761f,
    0.559f,  0.436f,  0.730f,
    0.359f,  0.583f,  0.152f,
    0.483f,  0.596f,  0.789f,
    0.559f,  0.861f,  0.639f,
    0.195f,  0.548f,  0.859f,
    0.014f,  0.184f,  0.576f,
    0.771f,  0.328f,  0.970f,
    0.406f,  0.615f,  0.116f,
    0.676f,  0.977f,  0.133f,
    0.971f,  0.572f,  0.833f,
    0.140f,  0.616f,  0.489f,
    0.997f,  0.513f,  0.064f,
    0.945f,  0.719f,  0.592f,
    0.543f,  0.021f,  0.978f,
    0.279f,  0.317f,  0.505f,
    0.167f,  0.620f,  0.077f,
    0.347f,  0.857f,  0.137f,
    0.055f,  0.953f,  0.042f,
    0.714f,  0.505f,  0.345f,
    0.783f,  0.290f,  0.734f,
    0.722f,  0.645f,  0.174f,
    0.302f,  0.455f,  0.848f,
    0.225f,  0.587f,  0.040f,
    0.517f,  0.713f,  0.338f,
    0.053f,  0.959f,  0.120f,
    0.393f,  0.621f,  0.362f,
    0.673f,  0.211f,  0.457f,
    0.820f,  0.883f,  0.371f,
    0.982f,  0.099f,  0.879f
;

//Used to check if shaders are working. (http://content.gpwiki.org/index.php/OpenGL:Codes:Simple_GLSL_example is where I got this from)
void printLog(GLuint obj)

    int infologLength = 0;
    int maxLength;

    if(glIsShader(obj))
        glGetShaderiv(obj,GL_INFO_LOG_LENGTH,&maxLength);
    else
        glGetProgramiv(obj,GL_INFO_LOG_LENGTH,&maxLength);

    char infoLog[maxLength];

    if (glIsShader(obj))
        glGetShaderInfoLog(obj, maxLength, &infologLength, infoLog);
    else
        glGetProgramInfoLog(obj, maxLength, &infologLength, infoLog);

    if (infologLength > 0)
        printf("%s\n",infoLog);


//Loads the vertex and fragment shader.
GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path)

    // Create the shaders
    GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
    GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

    // Read the Vertex Shader code from the file
    std::string VertexShaderCode;
    std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
    if(VertexShaderStream.is_open())
    
        std::string Line = "";
        while(getline(VertexShaderStream, Line))
            VertexShaderCode += "\n" + Line;
        VertexShaderStream.close();
    

    // Read the Fragment Shader code from the file
    std::string FragmentShaderCode;
    std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
    if(FragmentShaderStream.is_open())
        std::string Line = "";
        while(getline(FragmentShaderStream, Line))
            FragmentShaderCode += "\n" + Line;
        FragmentShaderStream.close();
    

    GLint Result = GL_FALSE;
    int InfoLogLength;

    // Compile Vertex Shader
    printf("Compiling shader : %s\n", vertex_file_path);
    char const * VertexSourcePointer = VertexShaderCode.c_str();
    glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
    glCompileShader(VertexShaderID);
    printLog(VertexShaderID);

    // Compile Fragment Shader
    printf("Compiling shader : %s\n", fragment_file_path);
    char const * FragmentSourcePointer = FragmentShaderCode.c_str();
    glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
    glCompileShader(FragmentShaderID);
    printLog(FragmentShaderID);

    // Link the program
    fprintf(stdout, "Linking program\n");
    GLuint ProgramID = glCreateProgram();
    glAttachShader(ProgramID, VertexShaderID);
    glAttachShader(ProgramID, FragmentShaderID);
    glLinkProgram(ProgramID);

    // Check the program
    glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
    glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    std::vector<char> ProgramErrorMessage( max(InfoLogLength, int(1)) );
    glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
    fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);

    //Clean up.
    glDeleteShader(VertexShaderID);
    glDeleteShader(FragmentShaderID);

    return ProgramID;


void display() 
    //Enable depth.
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    //Clear screen.
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //Create the vertexbuffer.
    GLuint vertexbuffer;
    glGenBuffers(1, &vertexbuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data,  GL_STATIC_DRAW);

    //Create the color buffer.
    GLuint colorbuffer;
    glGenBuffers(1, &colorbuffer);
    glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data), g_color_buffer_data, GL_STATIC_DRAW);

    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    glVertexAttribPointer(
                          0,
                          3,
                          GL_FLOAT,
                          GL_FALSE,
                          0,
                          (void*)0
                          );

    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
    glVertexAttribPointer(
                          1,
                          3,
                          GL_FLOAT,
                          GL_FALSE,
                          0,
                          (void*)0
                          );

    //Draw the cube. 12 triangles, 3 vertices per triangle thus 12*3.
    glDrawArrays(GL_TRIANGLES, 0, 12*3);

    //Clean Up.
    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);

    //Display on screen
    glutSwapBuffers();


int main(int argc, char** argv) 

    //Init stuff.
    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
    glutInitWindowSize(400, 300);
    glutCreateWindow("Triangle");

    GLenum err = glewInit();
    if (GLEW_OK != err)
    
        /* Problem: glewInit failed, something is seriously wrong. */
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
    
    fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));

    //Create the shaders.
    GLuint programID = LoadShaders("/Users/person/Programming/C++/OpenGL Cube/OpenGL Cube/v.vsh", "/Users/person/Programming/C++/OpenGL Cube/OpenGL Cube/f.fsh");

    glUseProgram(programID);

    //Set the camera and stuff.
    glm::mat4 Projection = glm::perspective(45.0f, 4.0f/3.0f, 0.1f, 100.0f);

    glm::mat4 View = glm::lookAt(
                                 glm::vec3(4.0f,3.0f,3.0f),
                                 glm::vec3(0.0f,0.0f,0.0f),
                                 glm::vec3(0.0f,1.0f,0.0f)
                                 );

    glm::mat4 Model = glm::mat4(1.0f);

    glm::mat4 MVP = Projection * View * Model;

    GLuint MatrixID = glGetUniformLocation(programID, "MVP");
    glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);

    //Get stuff to display.
    glutDisplayFunc(display);


    glutMainLoop();
    return 0;

顶点着色器代码:

#version 110

uniform mat4 MVP;
attribute vec2 position;
attribute vec3 vertexColor;

varying vec4 fragmentColor;

void main() 
    gl_Position = MVP * vec4(position, 0.0, 1.0);
    fragmentColor = vec4(vertexColor, 1.0);

片段着色器代码:

#version 110

varying vec4 fragmentColor;

void main() 
    gl_FragColor = fragmentColor;

目前我的立方体是这样的:

着色器编译良好,没有错误消息。

很抱歉,如果这看起来代码太多或什么的,但我真的不知道要删减什么,如果你有什么要我特别指出的,请询问。

更新

感谢蒂姆的建议,但我仍然遇到一些问题(尽管看起来更好)。我在显示函数中更改了以下代码行,因此我不假设哪个属性是哪个:

GLuint loc1;
loc1 = glGetAttribLocation(program, "position");
glEnableVertexAttribArray(loc1);
printf("%d\n", loc1);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
                      loc1,
                      3,
                      GL_FLOAT,
                      GL_FALSE,
                      0,
                      (void*)0
                      );

GLuint loc2 = glGetAttribLocation(program, "vertexColor");
glEnableVertexAttribArray(loc2);
printf("%d\n", loc2);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glVertexAttribPointer(
                      loc2,
                      3,
                      GL_FLOAT,
                      GL_FALSE,
                      0,
                      (void*)0
                      );

除了创建一个全局变量program,它将假定programID 的值,这样我就可以在我的显示函数中使用它。现在看起来像这样:

大家还有什么建议吗?

【问题讨论】:

您是否注意到我的第二个建议,即 2d 与 3d 不匹配?如果是,请更新代码。 @Tim 这种 2d-3d 的不匹配肯定会导致他的立方体变成正方形。 +1 给你,-1 给只阅读一半答案然后寻求进一步帮助的人。 @Tim:好的,我认为这只是一个建议,例如:您应该这样做以获得更好的实践,但这不是必需的(我当时只是想让它工作),这有帮助。谢谢!再次。 【参考方案1】:

一方面,假设属性的位置是不好的。您任意假设“顶点”是属性 0,而“颜色”是属性 1。这是一个危险的假设。您想调用glGetAttribLocation 来获取他们的真实位置,或者在链接之前调用glBindAttribLocation 将变量分配给一个位置。

您的混乱结果看起来几乎就像您提供顶点作为颜色,反之亦然。

此外,您正在着色器中读取 2d 顶点,同时提供 3d 顶点信息。您可能希望保持一致。

【讨论】:

嗯,在更改了位置中的一些变量之后,您似乎对颜色是正确的,是给定的顶点...给我一点,看看我是否可以使用您的建议修复它。谢谢。 如果您愿意查看我更新的问题,感谢您迄今为止的帮助!

以上是关于在 OpenGL 中显示立方体的问题的主要内容,如果未能解决你的问题,请参考以下文章

我的 opengl 代码应该显示多个立方体,但只显示一个正方形

使用 GLM 在 OpenGL 中绘制 2 个立方体

引擎测试:在屏幕上渲染立方体 (OpenGL)

在 android 中使用 opengl 在 glsurfaceview 中显示 3D 模型的问题

OpenGL立方体贴图面顺序和采样问题

OpenGL在显示多个对象时显示白屏