я изучаю OpenGL, и я написал следующий код на C ++, используя это руководство а также это видео.
Также я использую GLFW для создания контекста и GLEW для функций GL
Большая часть класса Shader скопирована из связанного видео,
Проблема в том, что использование glDrawElements () для рендеринга внутри основного цикла приводит к ошибке сегментации:
Segmentation fault------------------
(program exited with code: 139)
Press return to continue
в то время как с 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;
}
Проблема связана с привязкой вашего индекса к буферу. Индексный буфер (GL_ELEMENT_ARRAY_BUFFER
) обязательная часть ВАО государства. Пропуская несвязанные вызовы, вы получаете следующую общую последовательность:
...
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. В результате у вас нет привязанного индексного буфера после этого вызова.
Что происходит дальше, так это то, что вы делаете glDrawElements()
позвонить с последним аргументом 0
, Без привязки к индексному буферу последний аргумент интерпретируется как указатель на память ЦП. Таким образом, OpenGL пытается прочитать данные индекса по адресу 0, что вызывает сбой.
Чтобы это исправить, вам просто нужно привязать индексный буфер, пока VAO привязан. Вы можете сделать это, изменив порядок ваших вызовов, и создать / связать VAO, прежде чем настраивать буфер индекса. Или вы можете связать его снова при настройке состояния атрибута вершины. Например, в самом конце Shader
конструктор, после glVertexAttribPointer()
и связанные вызовы, вы добавляете этот вызов:
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);