Мой вызов 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
, но опять же, я не могу видеть проблему.
Наиболее вероятным объяснением является то, что у вас есть недействительные индексы в массиве индексов. Вы проверили все значения индекса и подтвердили, что ни один из них не является> = числом вершин? –
Привет @RetoKoradi, спасибо за ваш ответ. Да, после генерации сферы я выводил все вершины и индексы в .txt-файлы и просматривал их. – NeomerArcana
Я все еще добавляю некоторые проверки для этого в коде. Множество индексов проверить, и вам просто нужно пропустить один из них. – urraka