2015-09-04 150 views
1

即時通訊學習OpenGL,我用C++編寫了以下代碼,使用this guidethis video。 還我使用GLFW上下文的創建和GLEW爲GL功能 大多數Shader類是從鏈接的視頻了複製,爲什麼使用glDrawElements()會導致分段錯誤?

的問題是,使用glDrawElements()主循環裏面渲染讓我一個分割故障:

Segmentation fault 


------------------ 
(program exited with code: 139) 
Press return to continue 

while glDrawArrays()我可以繪製沒有問題。

有誰知道這可能是由什麼引起的? 我認爲這個錯誤可能取決於Shader類的實現,因爲我在其他程序中使用了glDrawArrays(),它沒有使用這個類,並且關心主函數中的着色器。

program.cpp

//INCLUDE AND DECLARATIONS 
#include <iostream> 
#include <fstream> 
// GLEW 
#define GLEW_STATIC 
#include <GL/glew.h> 
// GLFW 
#include <GLFW/glfw3.h> 
#include "Shader.h" 

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); 
unsigned long getFileLength(std::ifstream& file); 
int loadshader(char* filename, GLchar** ShaderSource, unsigned long* len); 

const GLuint WIDTH = 800, HEIGHT = 600; 


//VERTEX DATA 
float data[] = { 
// X  Y  R  G  B 
    -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, // Top-left 
    0.5f, 0.5f, 0.0f, 1.0f, 0.0f, // Top-right 
    0.5f, -0.5f, 0.0f, 0.0f, 1.0f, // Bottom-right 
    -0.5f, -0.5f, 1.0f, 1.0f, 1.0f // Bottom-left 
}; 

GLuint elements[] = { 
     0, 1, 2, 
     2, 3, 0 
    }; 

//main 
int main() 
{ //INIT GLFW AND WINDOW 
    glfwInit(); 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); 
    GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr); 
    glfwMakeContextCurrent(window); 
    glfwSetKeyCallback(window, key_callback); 
    glewExperimental = GL_TRUE; 
    glewInit(); 
    glViewport(0, 0, WIDTH, HEIGHT); 



    //ALLOCATE BUFFERS 
     //VERTEX ARRAY BUFFER 
    GLuint vbo; 
    glGenBuffers(1, &vbo); 
    glBindBuffer(GL_ARRAY_BUFFER, vbo); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); 
     //ELEMENT ARRAY BUFFER 
    GLuint ebo; 
    glGenBuffers(1, &ebo); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW); 
     //CREATE SHADER 
    Shader shader("./shaders/basicShader"); 


    // main loop 
    while (!glfwWindowShouldClose(window)) 
    { 
     shader.Bind(); 
     glfwPollEvents();      //window events 
     glClearColor(1.0f, 0.0f, 0.5f, 0.5f); //background 
     glClear(GL_COLOR_BUFFER_BIT); 
     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); 

     glfwSwapBuffers(window);    //update window 
    } 

    glDeleteBuffers(1, &vbo); 
    glDeleteBuffers(1, &ebo); 
    glfwTerminate(); 
    return 0; 
} 


void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) 
{ 
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) 
     glfwSetWindowShouldClose(window, GL_TRUE); 
} 

Shader.h

#include <iostream> 
#include <fstream> 
#include <GL/glew.h> 
#include <GLFW/glfw3.h> 


class Shader 
{ 
     public: 
      Shader(const std::string& filepath); 
      ~Shader(); 
      void Bind(); 
     private: 
      static const GLuint NUM_SHADERS = 2; 
      GLuint program; 
      GLuint shaders[NUM_SHADERS]; 

      std::string LoadShader(const std::string& fileName); 
      void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const std::string& errorMessage); 
      GLuint CreateShader(const std::string& text, unsigned int type); 

}; 

Shader.cpp

#include "Shader.h" 

Shader::Shader(const std::string& filepath) 
{ 
    program = glCreateProgram(); 
    shaders[0] = CreateShader(LoadShader(filepath + ".vs"), GL_VERTEX_SHADER); 
    shaders[1] = CreateShader(LoadShader(filepath + ".fs"), GL_FRAGMENT_SHADER); 

    for(unsigned int i = 0; i < NUM_SHADERS; i++) 
    { 
     glAttachShader(program, shaders[i]); 
    } 
    glBindAttribLocation(program, 0, "position"); 
    glBindFragDataLocation(program, 0, "outColor"); 

    glLinkProgram(program); 
    CheckShaderError(program, GL_LINK_STATUS, true, "Error linking shader program"); 

    glValidateProgram(program); 
    CheckShaderError(program, GL_LINK_STATUS, true, "Invalid shader program"); 




    GLuint vao; 
    glGenVertexArrays(1, &vao);  
    glBindVertexArray(vao);  

    GLint posAttrib = glGetAttribLocation(program, "position"); 
    glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), 0); 
    glEnableVertexAttribArray(posAttrib); 

    GLint AttribColor = glGetAttribLocation(program, "color"); 
    glVertexAttribPointer(AttribColor, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void*)(2*sizeof(float))); 
    glEnableVertexAttribArray(AttribColor); 


} 

Shader::~Shader() 
{ 
    for(unsigned int i = 0; i < NUM_SHADERS; i++) 
    { 
     glDetachShader(program, shaders[i]); 
     glDeleteShader(shaders[i]); 
    } 
    glDeleteProgram(program); 
} 

void Shader::Bind() 
{ 
     glUseProgram(program); 
} 


//loads shaders from files 
std::string Shader::LoadShader(const std::string& fileName) 
{ 
    std::ifstream file; 
    file.open((fileName).c_str()); 

    std::string output; 
    std::string line; 

    if(file.is_open()) 
    { 
     while(file.good()) 
     { 
      getline(file, line); 
      output.append(line + "\n"); 
     } 
    } 
    else 
    { 
     std::cerr << "Unable to load shader: " << fileName << std::endl; 
    } 

    return output; 
} 
//Checks for eventual errors in shaders 
void Shader::CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const std::string& errorMessage) 
{ 
    GLint success = 0; 
    GLchar error[1024] = { 0 }; 

    if(isProgram) 
     glGetProgramiv(shader, flag, &success); 
    else 
     glGetShaderiv(shader, flag, &success); 

    if(success == GL_FALSE) 
    { 
     if(isProgram) 
      glGetProgramInfoLog(shader, sizeof(error), NULL, error); 
     else 
      glGetShaderInfoLog(shader, sizeof(error), NULL, error); 

     std::cerr << errorMessage << ": '" << error << "'" << std::endl; 
    } 
} 

GLuint Shader::CreateShader(const std::string& text, unsigned int type) 
{ 
    GLuint shader = glCreateShader(type); 
     if(shader == 0) 
      std::cerr << "error allocating shader" << std:: endl; 

    const GLchar* p[1]; 
    p[0] = text.c_str(); 
    GLint lengths[1]; 
    lengths[0] = text.length(); 

    glShaderSource(shader, 1, p, lengths); 
    glCompileShader(shader); 
    CheckShaderError(shader, GL_COMPILE_STATUS, false, "Error compiling shader!"); 

    return shader; 
} 
+0

最後一個參數''glDrawElements()''是一個指向標數組。你給0,這可能是問題嗎? – BitTickler

回答

5

問題是機智h您的索引緩衝區綁定。索引緩衝區(GL_ELEMENT_ARRAY_BUFFER)綁定是VAO狀態的一部分。跳過無關的電話,您有以下整個序列:

... 
glGenBuffers(1, &ebo); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW); 
... 
GLuint vao; 
glGenVertexArrays(1, &vao);  
glBindVertexArray(vao);  
... 
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); 

由於GL_ELEMENT_ARRAY_BUFFER綁定的VAO狀態的一部分,當前索引緩衝區綁定替換爲索引緩存在VAO態結合,當你撥打:

glBindVertexArray(vao);  

因爲你永遠不綁定索引緩存而VAO是綁定的,這意味着該指數的緩衝區VAO態結合是0。結果,你沒有這個電話後綁定索引緩存。

接下來會發生的是,您使用最後一個參數0進行glDrawElements()調用。沒有綁定索引緩衝區,最後一個參數被解釋爲指向CPU內存的指針。因此,OpenGL嘗試讀取地址爲0的索引數據,導致崩潰。

要解決這個問題,你只需綁定VAO綁定索引緩衝區。您可以通過更改呼叫順序來完成此操作,並在設置索引緩衝區之前創建/綁定VAO。或者,當您設置頂點屬性狀態時,您可以再次將其綁定。例如,在Shader構造的盡頭時,glVertexAttribPointer()和相關電話後,你這個調用添加:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 
+0

感謝您的詳盡答覆。 –

相關問題