OpenGL - 着色器加载但只能显示 2D 三角形

OpenGL - Shader loads but can only display 2D triangles

我完全运行没主意了。我正在尝试让我的着色器在 OpenGL 中工作,并已将我的代码带回超级基础以尝试这样做。

当我 运行 我的代码使用 glDrawArrays 时,我得到一个蓝色三角形,这告诉我我的着色器正在工作。我还可以在片段着色器中设置颜色以证明它可以修复颜色。 如您所见,我使用了我测试过的变量 'numOfVerts',任何低于 3 的值都不会像预期的那样绘制任何东西,但是任何高于 3 的值都会绘制相同的基本 2D 三角形而不是立方体。 其代码如下:

int DrawGLScene(GLvoid)                     
{

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer

    glUseProgram(myShader.handle());  // use the shader
    GLuint matLocation = glGetUniformLocation(myShader.handle(), "ProjectionMatrix");
    glUniformMatrix4fv(matLocation, 1, GL_FALSE, &ProjectionMatrix[0][0]);
    //Draw code
    glBindVertexArray(m_vaoID);     // select VAO
    glDrawArrays(GL_TRIANGLES, 0, numOfVerts); //draw some geometry 
    glBindBuffer(GL_ARRAY_BUFFER, 0);  //unbind the buffer

    glBindVertexArray(0);
    glUseProgram(0); //turn off the current shader
    return TRUE;                                        // Keep Going
}

我尝试绘制完整立方体的另一种绘制方法使用 glDrawElements,但是所有这一切都向我展示了一个空白的白屏:

int DrawGLScene(GLvoid)                             
{

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer

    glUseProgram(myShader.handle());  // use the shader
    GLuint matLocation = glGetUniformLocation(myShader.handle(), "ProjectionMatrix");
    glUniformMatrix4fv(matLocation, 1, GL_FALSE, &ProjectionMatrix[0][0]);

    //draw objects
    glBindVertexArray(m_vaoID);     // select VAO       
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
    // Done
    glBindVertexArray(0); //unbind the vertex array object

    return TRUE;                                        // Keep Going
}

这是我的垂直着色器:

#version 150
uniform mat4 ProjectionMatrix;

in  vec3 in_Position;  // Position coming in
in  vec3 in_Color;     // colour coming in
out vec3 ex_Color;     // colour leaving the vertex, this will be sent to the fragment shader

void main(void)
{
    gl_Position = ProjectionMatrix * vec4(in_Position, 1.0);

    ex_Color = in_Color;
}

这是我的片段着色器:

#version 150
in  vec3 ex_Color;  //colour arriving from the vertex
out vec4 out_Color; //colour for the pixel

void main(void)
{
    out_Color = vec4(ex_Color,1.0);
}

以下代码是我为了使它正常工作而剥离我的程序的代码,并显示了我的 'drawTest' 方法以及所有相关的顶点和索引数组以及相关的设置代码。 drawTest 方法在我的初始化函数中被调用一次:

/**includes**/
#define GLEW_STATIC
#include <GL/glew.h>
#include <GL/wglew.h>
#include "boost\lexical_cast.hpp"
#include <boost/asio.hpp>
#include <boost/asio/serial_port.hpp>
#include "Image_Loading/nvImage.h"
#include <map>
#include "MenuController.h"
#include <windows.h>        // Header File For Windows
#include <gl\gl.h>          // Header File For The OpenGL32 Library
#include <gl\glu.h>         // Header File For The GLu32 Library
#include "../glm/glm.hpp"
#include "../glm/gtc/matrix_transform.hpp"
#include "../glm/gtc/type_ptr.hpp"
#include "../glm/gtc/matrix_inverse.hpp"
#include <vector>
#include <algorithm>    // std::reverse
#include <iostream>
#include "console.h"
#include "DistanceCalculator.h"
#include "Shader.h"

/* Variables*/
glm::mat4 ProjectionMatrix; // matrix for the orthographic projection
unsigned int m_vaoID;           // vertex array object
unsigned int m_vboID[2];        // two VBOs - used for colours and vertex data
unsigned int ibo;
const int numOfVerts = 3;
const int numOfTris = 1;
float verts[9];
float cols[9];
Shader myShader;  ///shader object 


//index array to draw basic cube
GLubyte indicesTest5[] = { 
    0,1,2,2,3,0,      // back
    5,6,7,7,4,5,     // front
    1,2,7,7,6,1,      // left
    0,3,4,4,5,0,      // right
    0,1,6,6,5,0,     // top
    2,3,4,4,7,2   // bottom
};


/*Method to draw a simple cube using shaders*/
void drawTest(){

    int dim = 20;
    //8 vertices to define a basic cube
    GLfloat verticesTest2[] = {
        /*0*/dim, dim, -dim,
        /*1*/-dim, dim, -dim,
        /*2*/-dim, -dim, -dim,
        /*3*/dim, -dim, -dim,
        /*4*/dim, -dim, dim,
        /*5*/dim, dim, dim,
        /*6*/-dim, dim, dim,
        /*7*/-dim, -dim, dim
    };

    //Create a vec3 array that will store the x,y,z of the 8 vertices more understandably
    std::vector<glm::vec3 > cubeVerts;
    for (int i = 0; i < 24; i += 3){ //verticesTest2 size of
        glm::vec3 vert = glm::vec3(verticesTest2[i], verticesTest2[i+1], verticesTest2[i+2]);
        cubeVerts.push_back(vert);
    }

    /*****THIS PART JUST BUILDS A VERT NORMALS LIST****/
    //define a vector to store the x,y,z of each vertex normal (so 8 in total)
    std::vector<glm::vec3 > vertNormals;    
    //loop for the amount of vertices that we have
    for (int i = 0; i < cubeVerts.size(); i++){
        //define tracking variables
        int currentVertexIndex = i;
        int faceCount = 0;
        glm::vec3 faceNormalSum = glm::vec3(0, 0, 0);

        //loop for all 36 indices within the index array
        for (int j = 0; j < 36; j++){
            //if the current vertex has been located in the index array
            if (indicesTest5[j] == currentVertexIndex){
                //calculate a modulo of the position to determine the vertex position in the index array (1st, 2nd or 3rd vertex of the triangle)
                int positionMod = j % 3;                
                glm::vec3 v1, v2, v3;

                //if the first vertex in a triangle, or the first array element
                if (positionMod == 0 || j == 0){ 
                    v1 = cubeVerts.at(indicesTest5[j]);
                    v2 = cubeVerts.at(indicesTest5[j+1]);
                    v3 = cubeVerts.at(indicesTest5[j+2]);
                }

                //if second vertex in a triangle, or the second array element
                else if (positionMod == 1 || j ==1){ 
                    v1 = cubeVerts.at(indicesTest5[j-1]);
                    v2 = cubeVerts.at(indicesTest5[j]);
                    v3 = cubeVerts.at(indicesTest5[j+1]);
                }

                //if third vertex in a triangle, or the third array element
                else if (positionMod == 2 || j == 2){ 
                    v1 = cubeVerts.at(indicesTest5[j-2]);
                    v2 = cubeVerts.at(indicesTest5[j-1]);
                    v3 = cubeVerts.at(indicesTest5[j]);
                }

                //increment the amount of faces surrounding the current vertex
                faceCount++;

                /*calculate face normal*/               
                //calculate 2 vectors of the current triangle
                glm::vec3 V = v2 - v1;
                glm::vec3 W = v3 - v1;
                //calculate the cross product of these vectors to get the face normal
                glm::vec3 faceNormal = glm::cross(V,W);
                //normalize the obtained face normal
                faceNormal = glm::normalize(faceNormal);
                //add this to the current sum of the facenormals values
                faceNormalSum += faceNormal;
            }           
        }
        //Once all indices checked for the current vertex, divide each x,y,z value in the faceNormalSum by the amount of
        //surrounding faces detected to give a mean value and therefore the normal for that vertex
        vertNormals.push_back(glm::vec3(faceNormalSum.x / faceCount, faceNormalSum.y / faceCount, faceNormalSum.z / faceCount));
    }
    /*****END OF VERT NORMALS CREATION*****/    

    //Create a vector to store all the vertex normal values as floats (much like the vertices list)
    vector<float> vertNormalVector;
    vertNormalVector.clear();
    for (int i = 0; i < vertNormals.size(); i++){
        vertNormalVector.push_back(vertNormals.at(i).x);
        vertNormalVector.push_back(vertNormals.at(i).y);
        vertNormalVector.push_back(vertNormals.at(i).z);
    }

    //create a pointer for the vertexNormal vector
    float* vertexNormal = &vertNormalVector[0];

    vector<Vertex> vertices;    
    for (int x = 0; x < 8; x++){
        Vertex vertStruct = Vertex();
        vertStruct.position = cubeVerts.at(x);
        vertStruct.normal = vertNormals.at(x);
        vertices.push_back(vertStruct);
    }

    //By this point I simply have a vertices array, a vertex normal array and an array of indices.
    //So I can set all the buffers shown below  

    // VAO allocation
    glGenVertexArrays(1, &m_vaoID);
    // First VAO setup
    glBindVertexArray(m_vaoID);
    glGenBuffers(2, m_vboID);
    glBindBuffer(GL_ARRAY_BUFFER, m_vboID[0]);

    //initialises data storage of vertex buffer object
    glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(GLfloat), verticesTest2, GL_STATIC_DRAW);
    GLint vertexLocation = glGetAttribLocation(myShader.handle(), "in_Position");
    glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(vertexLocation);

    //storage of normals (will simply act as colours for this example)
    glBindBuffer(GL_ARRAY_BUFFER, m_vboID[1]);
    glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(GLfloat), vertexNormal, GL_STATIC_DRAW);
    GLint colorLocation = glGetAttribLocation(myShader.handle(), "in_Color");
    glVertexAttribPointer(colorLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(colorLocation);

    //index buffer for indices defined above
    glGenBuffers(1, &ibo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 36 * sizeof(unsigned int), indicesTest5, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glEnableVertexAttribArray(0);
    glBindVertexArray(0);
}

/*Resize method to update projection matrix*/
GLvoid ReSizeGLScene(GLsizei width, GLsizei height)     // Resize And Initialize The GL Window
{
    if (height == 0)                                        // Prevent A Divide By Zero By
    {
        height = 1;                                     // Making Height Equal One
    }       
    glViewport(0, 0, width, height);                        // Reset The Current Viewport

    // Calculate The Aspect Ratio Of The Window
    gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);*/
    aspectRatio = (GLfloat)width / (GLfloat)height;
    screenHeight = (GLfloat)height;
    screenWidth = (GLfloat)width;

    ProjectionMatrix = glm::perspective(60.0f, (GLfloat)screenWidth / (GLfloat)screenHeight, 1.0f, 200.0f);
}


/*Init to load shader and call drawTest defined above*/
int InitGL(GLvoid)                                      // All Setup For OpenGL Goes Here
{
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);               // Black Background

    if (!myShader.load("BasicView", "../glslfiles/basic.vert", "../glslfiles/basic.frag"))
    {
        cout << "failed to load shader" << endl;
    }
    drawTest();
    return TRUE;                                        // Initialization Went OK
}


/*This code is where I set up my glew*/
/*AT THE END OF MY 'CreateGLWindow' METHOD*/
    HGLRC tempContext = wglCreateContext(hDC);
    wglMakeCurrent(hDC, tempContext);
    glewExperimental = TRUE;
    if (glewInit() != GLEW_OK) {
        std::cout << "glewInit failed, aborting." << std::endl;
    }
    int attribs[] =
    {
        WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
        WGL_CONTEXT_MINOR_VERSION_ARB, 2,
        WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
        0
    };
    if (wglewIsSupported("WGL_ARB_create_context") == 1)
    {
        hRC = wglCreateContextAttribsARB(hDC, 0, attribs);
        wglMakeCurrent(NULL, NULL);
        wglDeleteContext(tempContext);
        wglMakeCurrent(hDC, hRC);
    }
    else
    {   //It's not possible to make a GL 3.x context. Use the old style context (GL 2.1 and before)
        hRC = tempContext;
        cout << " not possible to make context " << endl;
    }

    ShowWindow(hWnd, SW_SHOW);                      // Show The Window
    SetForegroundWindow(hWnd);                      // Slightly Higher Priority
    SetFocus(hWnd);                                 // Sets Keyboard Focus To The Window
    ReSizeGLScene(width, height);                   // Set Up Our Perspective GL Screen

    if (!InitGL())                                  // Initialize Our Newly Created GL Window
    {
        KillGLWindow();                             // Reset The Display
        MessageBox(NULL, "Initialization Failed.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
        return FALSE;                               // Return FALSE
    }

    return TRUE;                                    // Success
}

有人知道为什么我似乎不能渲染超过一个 2D 三角形吗? 我也没有 compile/runtime 以上代码的错误。

这已通过遵循 Reto Koradi 的评论建议解决,即确保在定义索引、将索引加载到缓冲区和绘制时使用相同的类型。
所以正确的工作代码如下:

要创建索引列表,将它们声明为 GLuint:

GLuint indicesTest5[] = { 
0,1,2,2,3,0,     // back
5,6,7,7,4,5,     // front
1,2,7,7,6,1,     // left
0,3,4,4,5,0,     // right
0,1,6,6,5,0,     // top
2,3,4,4,7,2      // bottom
};    

确保在加载到缓冲区时使用 GLuint:

glBufferData(GL_ELEMENT_ARRAY_BUFFER, 36 * sizeof(GLuint), indicesTest5, GL_STATIC_DRAW);

确保绘图时使用GL_UNSIGNED_INT:

glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);