2014-09-20 80 views
1

我对glDrawElements的调用正在产生分段错误。如果我删除索引并使用glDrawArrays绘制了我顶点缓冲区中的所有内容。所以我的假设是,错误是在我填充GL_ELEMENT_ARRAY_BUFFER的方式,但我没有看到问题。glDrawElements中的OpenGL SegFault

我有一个球体类产生球体的顶点和索引。然后我只是下面的代码来设置vbo,vao等:

GLuint vbo; 
    glGenBuffers(1, &vbo); 
    glBindBuffer(GL_ARRAY_BUFFER, vbo); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(struct VertexData) * sphere.GetVertices()->size(), sphere.GetVertices()->data(), GL_STATIC_DRAW); 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 

    GLuint vao; 
    glGenVertexArrays(1,&vao); 
    glBindVertexArray(vao); 
    glBindBuffer(GL_ARRAY_BUFFER, vbo); 
    glEnableVertexAttribArray(0); 
    glVertexAttribPointer(0, 4, GL_DOUBLE, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, position)); 
    glEnableVertexAttribArray(1); 
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, color)); 
    glEnableVertexAttribArray(2); 
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, normal)); 
    glEnableVertexAttribArray(3); 
    glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, tcoords)); 

    GLuint ibo; 
    glGenBuffers(1, &ibo); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * sphere.GetIndices()->size(), sphere.GetIndices()->data(), GL_STATIC_DRAW); 
    glBindVertexArray(0); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 

..我看不出有什么不对。

,我的画,于是做了这样的:

glClearColor(0.0, 0.0, 0.0, 1.0); 
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

float t = watch.GetElapsedTimePeriod().count(); 
float rotation = 0.5/1000.0*t; 
rotationMatrix = glm::rotate(rotationMatrix,rotation,glm::vec3(0,1,0)); 
glm::mat4 modelMatrix = perspectiveMatrix * viewMatrix * rotationMatrix * identitymatrix; 

glUseProgram(shaderprogram); 
glUniformMatrix4fv(glGetUniformLocation(shaderprogram, "mvpmatrix"), 1, GL_FALSE, glm::value_ptr(modelMatrix)); 

glBindVertexArray(vao); 
std::shared_ptr<std::vector<GLushort>> p = sphere.GetIndices(); 
size_t tt = p->size(); 
glDrawElements(GL_TRIANGLES,tt,GL_UNSIGNED_SHORT,0); 
//glDrawArrays(GL_POINTS,0,(*sphere.GetVertices()).size()); 
glBindVertexArray(0); 

glUseProgram(0); 

SDL_GL_SwapWindow(sdlglHandler); 

你可以看到我注释掉glDrawArrays调用成功,如果我用它(也不要设置在上面的代码索引缓冲区)。 (它是GL_POINTS,这样我就可以看到每个顶点都被绘制了。)

我已经注意到如果我在我的球体中产生较少的顶点,程序不会崩溃。所以起初我认为这是使用GLushort作为我的指数的类型,但是没有那么多的顶点被生产出来成为一个问题。我通过使用GLuint进行了测试,但那没有做任何事情。

接下来,我已经注意到,如果我使用小于我的索引向量的大小(从球体返回),我可以让它工作;但它必须是大小的1/6(​​当然,只有大约1/6的球体三角形被绘制出来了。

我已经查看了我的代码的其余部分以及如果我看到写过去的数组或其他任何东西,很简单,只是在openGL代码中,我正在做任何与数组和指针有关的事情

因为我能够删除索引数组并看到它工作,我相信。它是与此,但我不能工作了

哦,最后,VertexData结构是这样的:

struct VertexData 
{ 
    GLdouble position[4]; 
    GLfloat color[3]; 
    GLfloat normal[3]; 
    GLfloat tcoords[2]; 
}; 

海量编辑

因为我已经删除了所有我的C++封装和生产的这段代码,给了我同样的错误。我在一个完全丧失看到试图访问私有内存,没有什么看起来像它的溢出对我说:

#include <exception> 
#include <iostream> 
#include <fstream> 
#include <sstream> 
#include <list> 
#include <string> 
#include <algorithm> 
#include <functional> 

#include <utilities.hpp> 

#include <GL/glew.h> 
#include <SDL2/sdl.h> 
#define GLM_FORCE_RADIANS 
#include <glm/gtc/matrix_transform.hpp> 
#include <glm/gtc/type_ptr.hpp> 
#include <glm/gtx/transform.hpp> 

struct VertexData 
{ 
    GLdouble position[4]; 
    GLfloat color[3]; 
    GLfloat normal[3]; 
    GLfloat tcoords[2]; 
}; 

int main(int argc, char* argv[]) 
{ 
    try 
    { 
     SDL_Window* window; 
     SDL_GLContext context; 
     if(SDL_Init(SDL_INIT_VIDEO) < 0) 
      throw std::runtime_error("unable to initialise video"); 

     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); 
     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 4); 

     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 
     SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); 
     SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); 
     SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); 

     window = SDL_CreateWindow("SpaceEngine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 
     800, 800, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN); 
     if(!window) 
      throw std::runtime_error("unable to create window"); 

     context = SDL_GL_CreateContext(window); 

     SDL_GL_SetSwapInterval(1); 

     GLenum glewErr = glewInit(); 
     if(glewErr != GLEW_OK) 
     { 
      SDL_GL_DeleteContext(context); 
      SDL_DestroyWindow(window); 
      SDL_Quit(); 
      throw std::runtime_error(reinterpret_cast<const char*>(glewGetErrorString(glewErr))); 
     } 

     glEnable(GL_DEPTH_TEST); 
     glDepthFunc(GL_LESS); 

     std::vector<VertexData> vertices; 
     std::vector<GLushort> indices; 
     int rings = 200; 
     int sectors = 200; 
     float radius = 1.0; 

     if(rings < 2) 
      rings = 2; 
     if(sectors < 2) 
      sectors = 2; 
     while(rings * sectors >= std::numeric_limits<GLushort>::max()) 
     { 
      rings /= 2; 
      sectors /= 2; 
     } 

     const GLuint polyCountXPitch = rings+1; 

     GLuint level = 0; 

     for(GLuint p1 = 0; p1 < sectors-1; ++p1) 
     { 
      for(GLuint p2 = 0; p2 < rings-1; ++p2) 
      { 
       GLuint curr = level + p2; 
       indices.push_back(curr + polyCountXPitch); 
       indices.push_back(curr); 
       indices.push_back(curr + 1); 
       indices.push_back(curr + polyCountXPitch); 
       indices.push_back(curr + 1); 
       indices.push_back(curr + 1 + polyCountXPitch); 
      } 

      indices.push_back(level + rings - 1 + polyCountXPitch); 
      indices.push_back(level + rings - 1); 
      indices.push_back(level + rings); 

      indices.push_back(level + rings - 1 + polyCountXPitch); 
      indices.push_back(level + rings); 
      indices.push_back(level + rings + polyCountXPitch); 

      level += polyCountXPitch; 
     } 

     const GLuint polyCountSq = polyCountXPitch * sectors;   //top point 
     const GLuint polyCountSq1 = polyCountSq + 1;     //bottom point 
     const GLuint polyCountSqM1 = (sectors - 1) * polyCountXPitch; //last rows first index 

     for(GLuint p2 = 0; p2 < rings - 1; ++p2) 
     { 
      indices.push_back(polyCountSq); 
      indices.push_back(p2 + 1); 
      indices.push_back(p2); 

      indices.push_back(polyCountSqM1 + p2); 
      indices.push_back(polyCountSqM1 + p2 + 1); 
      indices.push_back(polyCountSq1); 
     } 

     indices.push_back(polyCountSq); 
     indices.push_back(rings); 
     indices.push_back(rings - 1); 

     indices.push_back(polyCountSqM1 + rings - 1); 
     indices.push_back(polyCountSqM1); 
     indices.push_back(polyCountSq1); 

     const GLdouble angleX = 2 * pi()/rings; 
     const GLdouble angleY = pi()/sectors; 

     GLuint i = 0; 
     GLdouble axz; 
     GLdouble ay = 0; 

     vertices.resize(polyCountXPitch * sectors + 2); 
     for(GLuint y = 0; y < sectors; ++y) 
     { 
      ay += angleY; 
      const GLdouble sinay = std::sin(ay); 
      axz = 0; 

      for(GLuint xz = 0; xz < rings; ++xz) 
      { 
       const glm::vec3 pos((radius * std::cos(axz) * sinay),radius * std::cos(ay), radius * std::sin(axz) * sinay); 
       glm::vec3 normal = pos; 
       normal = glm::normalize(normal); 

       GLuint tu = 0.5f; 
       if(y == 0) 
       { 
        if(normal.y != -1.0f && normal.y != 1.0f) 
         tu = std::acos(glm::clamp<GLdouble>(normal.x/sinay, -1.0f, 1.0f)) * 0.5 * (1.0f/pi()); 
        if(normal.z < 0.0f) 
         tu = 1 - tu; 
       } 
       else 
        tu = vertices[i-polyCountXPitch].tcoords[0]; 

       VertexData v; 
       v.color[0] = 1; 
       v.color[1] = 1; 
       v.color[2] = 1; 
       v.position[0] = pos.x; 
       v.position[1] = pos.y; 
       v.position[2] = pos.z; 
       v.position[3] = 1.0f; 
       v.normal[0] = normal.x; 
       v.normal[1] = normal.y; 
       v.normal[2] = normal.z; 
       v.tcoords[0] = tu; 
       v.tcoords[1] = ay * (1.0f/pi()); 
       vertices.at(i) = v; 

       ++i; 
       axz += angleX; 
      } 

      vertices.at(i) = vertices.at(i - rings); 
      vertices.at(i).tcoords[0] = 1.0f; 
      ++i; 
     } 

     VertexData v; 
     v.color[0] = 1; 
     v.color[1] = 1; 
     v.color[2] = 1; 
     v.position[0] = 0; 
     v.position[1] = radius; 
     v.position[2] = 0; 
     v.position[3] = 1.0f; 
     v.normal[0] = 0; 
     v.normal[1] = 1; 
     v.normal[2] = 0; 
     v.tcoords[0] = 0.5f; 
     v.tcoords[1] = 0.0f; 
     vertices.at(i) = v; 
     ++i; 
     v.position[1] = -radius; 
     v.normal[1] = -1.0f; 
     v.tcoords[1] = 1.0f; 
     vertices.at(i) = v; 

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

     GLuint vbo; 
     glGenBuffers(1, &vbo); 
     glBindBuffer(GL_ARRAY_BUFFER, vbo); 
     glBufferData(GL_ARRAY_BUFFER, sizeof(struct VertexData) * vertices.size(), vertices.data(), GL_STATIC_DRAW); 

     glEnableVertexAttribArray(0); 
     glVertexAttribPointer(0, 4, GL_DOUBLE, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, position)); 
     glEnableVertexAttribArray(1); 
     glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, color)); 
     glEnableVertexAttribArray(2); 
     glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, normal)); 
     glEnableVertexAttribArray(3); 
     glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(struct VertexData), (const GLvoid*)offsetof(struct VertexData, tcoords)); 

     GLuint ibo; 
     glGenBuffers(1, &ibo); 
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * indices.size(), indices.data(), GL_STATIC_DRAW); 

     glBindVertexArray(0); 
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 

     GLuint shader1,shader2; 
     std::ifstream file("tutorial2.vert"); 
     if(!file) 
      throw std::runtime_error("The file tutorial2.vert was not opened"); 
     else 
     { 
      std::string fileContents((std::istreambuf_iterator<char>(file)),std::istreambuf_iterator<char>()); 

      shader1 = glCreateShader(GL_VERTEX_SHADER); 
      std::string fail = "glCreateShader failed using " + GL_VERTEX_SHADER; 

      if(!shader1) 
       throw std::runtime_error(fail.c_str()); 

      const GLchar* contents[1]; 
      contents[0] = fileContents.c_str(); 
      glShaderSource(shader1, 1, contents, NULL); 

      glCompileShader(shader1); 
      int compiled; 
      glGetShaderiv(shader1, GL_COMPILE_STATUS, &compiled); 
      if(compiled == 0) 
      { 
       int maxLength; 
       glGetShaderiv(shader1, GL_INFO_LOG_LENGTH, &maxLength); 
       char* vertexInfoLog = new char[maxLength]; 
       glGetShaderInfoLog(shader1, maxLength, &maxLength, vertexInfoLog); 
       throw std::runtime_error("Shader failed to compile:\n>\t" + std::string(vertexInfoLog)); 
      } 
     } 
     std::ifstream file2("tutorial2.frag"); 
     if(!file2) 
      throw std::runtime_error("The file tutorial2.frag was not opened"); 
     else 
     { 
      std::string fileContents((std::istreambuf_iterator<char>(file2)),std::istreambuf_iterator<char>()); 

      shader2 = glCreateShader(GL_FRAGMENT_SHADER); 
      std::string fail = "glCreateShader failed using " + GL_FRAGMENT_SHADER; 
      if(!shader2) 
       throw std::runtime_error(fail.c_str()); 

      const GLchar* contents[1]; 
      contents[0] = fileContents.c_str(); 
      glShaderSource(shader2, 1, contents, NULL); 

      glCompileShader(shader2); 
      int compiled; 
      glGetShaderiv(shader2, GL_COMPILE_STATUS, &compiled); 
      if(compiled == 0) 
      { 
       int maxLength; 
       glGetShaderiv(shader2, GL_INFO_LOG_LENGTH, &maxLength); 
       char* vertexInfoLog = new char[maxLength]; 
       glGetShaderInfoLog(shader2, maxLength, &maxLength, vertexInfoLog); 
       throw std::runtime_error("Shader failed to compile:\n>\t" + std::string(vertexInfoLog)); 
      } 
     } 

     GLuint program = glCreateProgram(); 
     if(!program) 
      throw std::runtime_error("glCreateProgram failed"); 

     glAttachShader(program, shader1); 
     glAttachShader(program, shader2); 

     glBindAttribLocation(program, 0, "in_Position"); 
     glBindAttribLocation(program, 1, "in_Color"); 
     glBindAttribLocation(program, 2, "in_Normal"); 
     glBindAttribLocation(program, 3, "in_UV"); 

     glLinkProgram(program); 
     int IsLinked; 
     glGetProgramiv(program, GL_LINK_STATUS, (int *)&IsLinked); 
     if(IsLinked == 0) 
     { 
      int maxLength; 
      glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); 
      char* shaderProgramInfoLog = new char[maxLength]; 
      glGetProgramInfoLog(program, maxLength, &maxLength, shaderProgramInfoLog); 
      throw std::runtime_error("Program failed to link:\n>\t" + std::string(shaderProgramInfoLog) + ""); 
     } 

     glDetachShader(program, shader1); 
     glDetachShader(program, shader2); 

     bool done = false; 

     while(!done) 
     { 
      SDL_Event event; 
      while(SDL_PollEvent(&event)) 
      { 
       switch(event.type) 
       { 
       case SDL_WINDOWEVENT: 
        switch(event.window.event) 
        { 
        case SDL_WINDOWEVENT_CLOSE: 
         done = true; 
         break; 
        } 
        break; 
       } 
      } 

      glClearColor(0.0, 0.0, 0.0, 1.0); 
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

      glUseProgram(program); 

      glBindVertexArray(vao); 

      glDrawElements(GL_TRIANGLES,indices.size(),GL_UNSIGNED_SHORT,0); 

      glBindVertexArray(0); 

      glUseProgram(0); 

      SDL_GL_SwapWindow(window); 
      } 

     glUseProgram(0); 
     glDisableVertexAttribArray(0); 
     glDisableVertexAttribArray(1); 

     glDeleteProgram(program); 
     glDeleteBuffers(1, &vbo); 
     glDeleteVertexArrays(1, &vao); 

     SDL_GL_DeleteContext(context); 
     SDL_DestroyWindow(window); 
     SDL_Quit(); 

     std::cout << "all good in the hood" << std::endl; 
    } 
    catch(const std::exception& e) 
    { 
     std::cout << "ERROR:\t" << e.what() << std::endl; 
    } 
    catch(...) 
    { 
     std::cout << "ERROR" << std::endl; 
    } 
    exit(EXIT_SUCCESS); 
} 

我的顶点着色器:

#version 150 

precision highp float; 

in vec4 in_Position; 
in vec3 in_Color; 
in vec3 in_Normal; 
in vec2 in_UV; 

uniform mat4 mvpmatrix; 

out vec3 ex_Color; 
void main(void) 
{ 
    gl_Position = in_Position; 

    ex_Color = in_Color; 
} 

我的破片着色器:

#version 150 

precision highp float; 

in vec3 ex_Color; 
out vec4 gl_FragColor; 

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

EDIT2

我甚至试过outpu将一行文本添加到文件中,并通过1遍遍遍历索引中的每个三角形。如果我运行了几次,则会发现segfault发生在indices数组中的不同点上。索引正在查找的顶点位于我的顶点数组的边界内。

for(int i = 0; i < tt; i+=3) 
{ 
    file << "attempting " << i/3 << std::endl; 
    glDrawElements(GL_TRIANGLES,i,GL_UNSIGNED_SHORT,0); 
    SDL_GL_SwapWindow(sdlglHandler); 
} 

所以这告诉我,我试图访问一个索引是边界外从我发送到GL_ELEMENT_ARRAY_BUFFER但同样,我也看不出问题。

+0

最可能的解释是,你必须索引数组中的无效索引。你检查了所有的索引值,并确认它们中没有一个> =顶点的数量? – 2014-09-20 15:09:30

+0

嗨@RetoKoradi,谢谢你的回复。是的,在生成球体后,我将所有的顶点和索引输出到.txt文件并查看它们。 – NeomerArcana 2014-09-20 23:24:30

+0

我仍然在代码中添加一些检查。这是很多指标检查,你只需要错过其中之一。 – urraka 2014-09-21 03:24:22

回答

2

问题在于使用GL_DOUBLE作为顶点。更改为GL_FLOAT似乎已经做到了。

使用double时需要使用glVertexAttribLPointer

要使用glVertexAttribLPointer有意义会要求你重新写你的着色器的线(在dvec4 IN_POSITION)

1

您对VAO的使用看起来是正确的。不过我可以建议你明确地做glDrawElements调用之前对股指缓冲区中添加glBindBuffer,即

std::shared_ptr<std::vector<GLushort>> p = sphere.GetIndices(); 
size_t tt = p->size(); 

glBindVertexArray(vao); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 
glDrawElements(GL_TRIANGLES,tt,GL_UNSIGNED_SHORT,0); 
glBindVertexArray(0); 

注意,即使在今天VAOs不是很优化和改变VAO结合可能意味着性能击中。以Valve为例进行基准测试,截至目前仍然有使用多个VAO在其Source引擎中禁用的代码路径。在这种改变之前,推荐的方法是仅仅绑定缓冲区对象本身,而对于要求VAO创建并绑定一次的OpenGL配置文件,然后在进一步的操作中忽略它。

+0

Hi @datenwolf , 感谢您的回复。我已经尝试过,因为我在想,也许我错误地解释了OpenGL文档以及VAO是如何工作的。它没有帮助。 我不知道VAO的性能;我会记住这一点。 – NeomerArcana 2014-09-20 13:06:27

+2

GL_ELEMENT_ARRAY_BUFFER绑定是VAO状态的一部分,因此绑定它是多余的,只会损害性能。 @datenwolf,你是否有链接到Steam上有关VAO声明的最新数据?我想不出为什么使用VAO不应该像手动设置状态一样快。 VAO的整个想法是让状态设置更高效。如果它们得到正确实施,它就会这样工作。 – 2014-09-20 16:14:09

+0

@RetoKoradi:谈论“将源码移植到Linux,经验教训”http://adrienb.fr/blog/wp-content/uploads/2013/04/PortingSourceToLinux.pdf - Slide 57.我完全意识到重新绑定元素数组缓冲区应该是多余的,但有时你必须尝试这些东西来消除你被驱动程序错误误导的可能性。 – datenwolf 2014-09-20 18:56:47