OpenGL 索引缓冲以形成正方形

OpenGL Index Buffering To Make A Square

我是 OpenGL 的新手,一直在关注 Jeffrey Chastine 的 YouTube 教程。作为个人练习,我想使用索引缓冲区制作一个简单的正方形。遗憾的是,在我的尝试中,我只看到绘制了一个三角形(当我期望有两个时)。我不确定我错过了什么。这是我的代码,我试着在评论中解释我的 logic/reasoning。不对的地方欢迎指正:

#include <GL/glew.h>
#include <GL/freeglut.h>
#include <iostream>

#define BUFFER_OFFSET(i) ((char *)NULL + (i))
GLuint shaderProgramID;
GLuint vao = 0;
GLuint vbo;
GLuint positionID, colorID;
GLuint indexBufferID;


#pragma region SHADER_FUNCTIONS

static char* readFile(const char* fileName)
{
    //Open the file
    FILE* fp = fopen(fileName, "r");

    //Move the file pointer to the end of the file and determining the length
    fseek(fp, 0, SEEK_END);
    long file_length = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    char* contents = new char[file_length + 1];

    //zero out memory
    for(int i = 0; i < file_length+1; i++)
    {
        contents[i] = 0;
    }

    //Here's the actual read
    fread(contents, 1, file_length, fp);
    contents[file_length + 1] = '[=10=]';
    fclose(fp);
    return contents;
}

bool compiledStatus(GLint shaderID){
    GLint compiled = 0;
    glGetShaderiv(shaderID, GL_COMPILE_STATUS, &compiled);
    if (compiled) {
        return true;
    }
    else {
        GLint logLength;
        glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &logLength);
        char* msgBuffer = new char[logLength];
        glGetShaderInfoLog(shaderID, logLength, NULL, msgBuffer);
        printf ("%s\n", msgBuffer);
        delete (msgBuffer);
        return false;
    }
}

//Takes in source code as string
GLuint makeVertexShader(const char* shaderSource)
{
    //Call GL to make a vertex shader and get the ID
    GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);

    //Bind the provided source code to the shader ID
    glShaderSource(vertexShaderID, 1, (const GLchar**)&shaderSource, NULL);

    //Compile the vertex Shader
    glCompileShader(vertexShaderID);

    bool compiledCorrect = compiledStatus(vertexShaderID);
    if(compiledCorrect)
    {
        return vertexShaderID;
    }
    return -1;

    return vertexShaderID;
}

GLuint makeFragmentShader(const char* shaderSource)
{
    //Call GL to make a fragment shader and get the ID
    GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
    //Bind the provided source code to the shader ID
    glShaderSource(fragmentShaderID, 1, (const GLchar**)&shaderSource, NULL);
    //Compile the fragment Shader
    glCompileShader(fragmentShaderID);

    bool compiledCorrect = compiledStatus(fragmentShaderID);
    if(compiledCorrect)
    {
        return fragmentShaderID;
    }
    return -1;

    return fragmentShaderID;
}

#pragma endregion SHADER_FUNCTIONS 

void changeViewport(int w, int h)
{
    glViewport(0, 0, w, h);
}

//This is the function we are using each time the window needs to be redrawn
void render()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDrawElements(GL_TRIANGLES, 4, GL_UNSIGNED_INT, NULL);
    glutSwapBuffers();
}

GLuint makeShaderProgram(GLuint vertextShaderID, GLuint fragmentShaderID)
{
    GLuint shaderID = glCreateProgram();
    //Attach the vertex shader to the shader program
    glAttachShader(shaderID, vertextShaderID);

    //Attatch the fragment shader to the shader program
    glAttachShader(shaderID, fragmentShaderID);

    //Link all the shaders together
    glLinkProgram(shaderID);
    return shaderID;
}

int main (int argc, char** argv)
{
    //Standards
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA);
    glutInitWindowSize(800, 600);
    glutCreateWindow("Test");
    glutReshapeFunc(changeViewport);
    glutDisplayFunc(render);
    glewInit();

    //Verticies
    GLfloat vertices_0[] = {-0.5f, -0.5f, 0.0f, //0 -> Bottom Left
                            -0.5f,  0.5f, 0.0f, //1 -> Top Left
                             0.5f, -0.5f, 0.0f, //2 -> Bottom Right
                             0.05f, 0.5f, 0.0f};//3 -> Top Right
    //Colors
    GLfloat colors_0[] = {1.0f, 0.0, 0.0f, 1.0f,//0
                          0.0f, 1.0f, 0.0f, 1.0f,//1
                          0.0f, 0.0f, 1.0f, 1.0f,//2
                          1.0f, 0.0f, 1.0f, 1.0f};//3

    //Indicies -> Triangle 1 -> 0 1 2, Traingle 2 -> 1 3 2
    GLuint indicies_0[] = {0, 1, 2, 1, 3, 2};


    //Read the vertex shader
    char* vertexShaderSourceCode = readFile("vertexShader.vsh");

    //Read the fragment shader
    char* fragmentShaderSourceCode = readFile("fragmentShader.fsh");

    //Make Vertex Shader
    GLuint vertexShaderID = makeVertexShader(vertexShaderSourceCode);

    //Make Fragment Shader
    GLuint fragmentShaderID = makeFragmentShader(fragmentShaderSourceCode);

    //Make Shader Program
    shaderProgramID = makeShaderProgram(vertexShaderID, fragmentShaderID);


    printf("Vertex Shader ID is %d\n", vertexShaderID);
    printf("Fragment Shader ID is %d\n", fragmentShaderID);
    printf("Shader Program ID is %d\n", shaderProgramID);
    printf("s_vPosition's ID is %d\n", positionID);

    //Create vertex array object
    glGenVertexArrays(1, &vao);

    //Bind Vertex array object
    glBindVertexArray(vao);

    //Create vertex buffer object
    glGenBuffers(1, &vbo);

    //Bind vertex buffer object
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    //Create Buffer ->7 Values for 4 vertices
    glBufferData(GL_ARRAY_BUFFER, 7*4*sizeof(GLfloat), NULL, GL_STATIC_DRAW);

    //Starting at the beggining of the buffer, place the position data (3 values for 4 verticies)
    glBufferSubData(GL_ARRAY_BUFFER, 0, 3*4*sizeof(GLfloat), vertices_0);

    //Starting after the placement of position data, place the color data (4 values for 4 verticies)
    glBufferSubData(GL_ARRAY_BUFFER, 3*4*sizeof(GLfloat), 4*4*sizeof(GLfloat), colors_0);

    //Generate the index buffer
    glGenBuffers(1, &indexBufferID);

    //Bind the buffer
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);

    //Place index buffer data for the 6 indicies
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6*sizeof(GLuint), indicies_0, GL_STATIC_DRAW); 

    //Get the position attribute from the shader
    positionID = glGetAttribLocation(shaderProgramID, "s_vPosition");

    //Get the color attribute from the shader
    colorID = glGetAttribLocation(shaderProgramID, "s_vColor");

    //Tell the variables where they can find its info in the buffer
    glVertexAttribPointer(positionID, 3, GL_FLOAT, GL_FALSE, 0, 0);

    glVertexAttribPointer(colorID, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(vertices_0)));

    //Tell the program to use the shader program
    glUseProgram(shaderProgramID);
    //Turn on the position variable in the shader
    glEnableVertexAttribArray(positionID);
    //Turn on the color variable in the shader
    glEnableVertexAttribArray(colorID);

    glutMainLoop();
    return 0;
}

如评论中所述,您的顶点定义有误(0.05f 应为 0.5f)。

但是,您只看到一个三角形而不是 2 个的原因是这条线:

glDrawElements(GL_TRIANGLES, 4, GL_UNSIGNED_INT, NULL);

第二个参数在OpenGL documentation中描述为

count - Specifies the number of elements to be rendered.

这是索引计数(每个元素都由索引数组中的条目引用),因此应该是索引数组中的条目数,而不是唯一索引数。所以把 4 改成 6。

请注意,如果您使用 GL_TRIANGLE_STRIPGL_TRIANGLE_FAN 而不是 GL_TRIANGLES,您将只需要 4 个索引 {0, 1, 2, 3} 并且您可以传递 4正在做,因为第一个三角形之后的每个三角形与前一个三角形共享其索引的 2 个,总索引计数为(三角形计数 + 2)。但是,当使用 GL_TRIANGLES 时,每个三角形分别指定了 3 个索引(三角形数 * 3)。