简体   繁体   English

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

[英]OpenGL - Shader loads but can only display 2D triangles

I have completely run out of ideas. 我已经完全没有想法了。 I am trying to get my shaders to work in OpenGL, and have taken my code back to the super basics in an attempt to do so. 我正在尝试使着色器在OpenGL中工作,并已将我的代码恢复为超级基础知识,以尝试这样做。

When I run my code using glDrawArrays I get a blue triangle, which tells me my shaders are working. 当我使用glDrawArrays运行代码时,我得到一个蓝色三角形,告诉我我的着色器正在工作。 I can also set the colour within the frag shader to prove that it fixes a colour. 我还可以在碎片着色器中设置颜色,以证明它可以固定颜色。 As you can see I used the variable 'numOfVerts' which I have tested, any value below 3 and as expected nothing draws, however any value above 3 draws the same basic 2D triangle and not a cube. 如您所见,我使用了我测试过的变量'numOfVerts',任何小于3的值都按预期绘制,但是,大于3的任何值都绘制相同的基本2D三角形,而不是立方体。 The code for thisis as follows: 此代码如下:

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
}

The other draw method I have in an attempt to draw the full cube uses glDrawElements, however all this does is show me a blank white screen: 我尝试绘制整个多维数据集的另一种绘制方法使用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
}

This is my vert shader: 这是我的垂直着色器:

#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;
}

This is my frag shader: 这是我的碎片着色器:

#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);
}

The following code is what I have stripped my program to in an attempt to get this to work and shows my 'drawTest' method with all related vertex and index arrays along with related setup code. 下面的代码是我剥离程序所要尝试的,以使其正常运行,并显示了带有所有相关顶点和索引数组以及相关设置代码的“ drawTest”方法。 The drawTest method is called ONCE in my init function: 在我的init函数中,drawTest方法称为ONCE:

/**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
}

Does anybody know why I can't seem to render more than a single 2D triangle? 有人知道为什么我似乎无法渲染多个2D三角形吗? Also I have no compile/runtime errors with any of the above code. 另外,以上任何代码都没有编译/运行时错误。

This was solved by following Reto Koradi's comment advice, which is to ensure that the same type is used when defining the indices, when loading them into the buffer and when drawing. 这是通过遵循Reto Koradi的注释建议来解决的,该建议是确保在定义索引,将索引加载到缓冲区以及绘图时使用相同的类型。
So the correct working code is as follows: 因此正确的工作代码如下:

To create the list of indices declare them as GLuint: 要创建索引列表,请将它们声明为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
};    

Ensure GLuint is used when loading into the buffer: 装入缓冲区时,请确保使用GLuint:

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

Ensure GL_UNSIGNED_INT is used when drawing: 确保在绘制时使用GL_UNSIGNED_INT:

glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM