2014-09-20 6 views
1

Мой вызов glDrawElements вызывает ошибку сегментации. Если я откажусь от индексов и использую glDrawArrays, все в буфере вершин будет нарисовано. Поэтому я полагаю, что ошибка в том, что я заполняю GL_ELEMENT_ARRAY_BUFFER, но я не вижу проблемы.OpenGL SegFault в glDrawElements

У меня есть класс сфер, который создает вершины и индексы для сферы. Я тогда как раз следующий код для настройки ВБО, ВАО и т.д.:

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

Моему Vertex шейдер:

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

И мой Frag шейдер:

#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 ting строку текста в файл и перебирать каждый треугольник в моих индексах 1 на 1. Если я запустил его несколько раз, я обнаружил, что segfault происходит в разных точках массива индексов. Вершина, которую ищет индекс, находится в пределах границ моего массива вершин.

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

Наиболее вероятным объяснением является то, что у вас есть недействительные индексы в массиве индексов. Вы проверили все значения индекса и подтвердили, что ни один из них не является> = числом вершин? –

+0

Привет @RetoKoradi, спасибо за ваш ответ. Да, после генерации сферы я выводил все вершины и индексы в .txt-файлы и просматривал их. – NeomerArcana

+0

Я все еще добавляю некоторые проверки для этого в коде. Множество индексов проверить, и вам просто нужно пропустить один из них. – urraka

ответ

2

Проблема заключалась в использовании GL_DOUBLE для вершин. Переход к GL_FLOAT, похоже, сделал трюк.

При использовании двойного использования вам необходимо использовать glVertexAttribLPointer.

Для использования glVertexAttribLPointer осмысленно может потребовать от вас заново написать строку в шейдере (в dvec4 in_Position)

1

Ваше использование VAO выглядит правильно. Тем не менее, я могу предположить, что вы явно добавить glBindBuffer на индексном буфере перед выполнением glDrawElements вызова, т.е.

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, отключенных в своем движке Source. До тех пор, пока это не изменится, рекомендуется просто привязать сами объекты буфера и профили OpenGL, которые обязывают VAO создавать и связывать это один раз для каждого контекста, а затем просто игнорировать его в дальнейших операциях.

+0

Привет @datenwolf , Спасибо за ваш ответ. Я уже пробовал это, так как думал, что, возможно, я неправильно интерпретировал документы openGL и как работает VAO. Это не помогло. Я понятия не имел о работе VAO; Я буду помнить об этом. – NeomerArcana

+2

Пересылка 'GL_ELEMENT_ARRAY_BUFFER' является частью состояния VAO, поэтому привязка является избыточной и будет только ухудшать производительность. @datenwolf, у вас есть ссылка на недавние данные по этому заявлению VAO из Steam? Я не могу придумать, почему использование VAO должно быть не менее быстрым, чем настройка состояния вручную. Вся идея VAO заключается в том, чтобы сделать настройку состояния более эффективной. И он работает таким образом, если они должным образом реализованы. –

+0

@RetoKoradi: «Портирование источника в Linux, извлеченные уроки» http://adrienb.fr/blog/wp-content/uploads/2013/04/PortingSourceToLinux.pdf - Слайд 57. Я полностью осознаю, что восстановление элемента буфер массива должен быть избыточным, но иногда вам приходится проверять эти вещи, чтобы исключить возможность ошибочной ошибки драйвера. – datenwolf

Смежные вопросы