c++ - 在 OpenGL 中显示立方体的问题

标签 c++ opengl glsl

我目前正在尝试关注 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;
}

目前我的立方体看起来像这样:

Awesome Cube

着色器编译正常,没有错误消息。

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

更新

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

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 的值,这样我就可以在我的显示函数中使用它。现在看起来像这样:

enter image description here

有人有任何进一步的建议吗?

最佳答案

一方面,假设属性的位置是不好的。您武断地假设“vertex”是属性 0,而“color”是属性 1。这是一个危险的假设。您想要调用 glGetAttribLocation 来获取它们的真实位置,或者在链接之前调用 glBindAttribLocation 以将变量分配给一个位置。

你的困惑结果看起来几乎就像你在提供顶点作为颜色,反之亦然。

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

关于c++ - 在 OpenGL 中显示立方体的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11354129/

相关文章:

c++ - 将 vector 与 qsort() 一起使用

python - 当我没有为 openGLWidget 创建额外的类时,为什么 glRotate 只工作一次?

opengl - glCompileShader 是可选的吗?

iOS GLSL 球谐着色器。如何使用 iOS GPU 进行 Raycast

c++ - OpenGL 中的视差映射故障

c++ - 如何同时旋转和平移我的 Sprite ? cocos2dx 3.2

c++ - 为什么 gcc 4.7.0 在这段代码上给我一个段错误,而在线 ideone(gcc 4.5.1) 却没有?

c++ - std::vector 的问题

Cocoa 应用程序在 OpenGL 调用时崩溃

javascript - 在 WebGL2 中使用 mat4 属性