Napisałem dla OpenGL'a klasy Display, Shader i Buffer, które mają pozwolić na obiektową obsługę aplikacji.
Udało mi się z tymi 3 klasami napisać prosty program wyświetlający trójkąt.
Jednakże z zapewne jakiegoś prostego błędu, vertex shader w ogóle nie działa na geometrię trójkąta.
Jest to coś dziwnego, ponieważ fragment shader jest w stanie pokolorować trójkąt na czerwono zgodnie z zapisem.
Prosiłbym o pomoc, bo jestem początkującym w OpenGL'u i nie mogę znaleźć żadnego błędu... Przydały by mi się też wskazówki dotyczące poprawek w moich klasach.
main.cpp
#include <iostream>
#include "Shader.h"
#include "Buffer.h"
#include "Display.h"
int main()
{
Display display;
display.setAttributes("GAME", 1280, 720, false, 0, GLFW_DONT_CARE);
if(!display.create())return -1;
glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
float vertex_buffer_data[9] = {0.0f, 0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f};
Buffer VBO(GL_ARRAY_BUFFER);
VBO.data(vertex_buffer_data, sizeof(vertex_buffer_data), GL_STATIC_DRAW);
Shader shader("shader.vsh", "shader.fsh");
shader.addAttribute(0, "vertex");
//shader.addUniform(1,"imAnInt");
while(!display.isShouldClose()) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader.bind();
VBO.bind(0, 3, GL_FLOAT, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
VBO.unbind();
shader.unbind();
display.update();
}
display.destroy();
return 0;
}
Shader.h
#ifndef SHADER_H
#define SHADER_H
#define GLEW_STATIC
#include <GL/glew.h>
#include <glm/vec3.hpp>
#include <glm/mat4x4.hpp>
#include <iostream>
#include <fstream>
#include <map>
class Shader {
private:
GLuint programID;
GLuint vertexShaderID;
GLuint fragmentShaderID;
GLuint loadShaderFromFile(std::string filepath, GLuint type) {
std::ifstream file(filepath);
std::string code((std::istreambuf_iterator<char>(file)), (std::istreambuf_iterator<char>()));
GLuint shaderID = glCreateShader(type);
char const* source = code.c_str();
glShaderSource(shaderID, 1, &source, nullptr);
glCompileShader(shaderID);
GLint status = GL_FALSE;
glGetShaderiv(shaderID, GL_COMPILE_STATUS, &status);
if(status == GL_FALSE){
GLint logSize;
glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &logSize);
GLchar description[logSize];
glGetShaderInfoLog(shaderID, logSize, nullptr, &description[0]);
std::cout<<"\n"<<description;
std::cout<<"\nCould not compile shader!";
}
glDetachShader(programID, vertexShaderID);
glDetachShader(programID, fragmentShaderID);
glDeleteShader(vertexShaderID);
glDeleteShader(fragmentShaderID);
return shaderID;
}
public:
Shader(std::string vertexShaderFilePath,std::string fragmentShaderFilePath) {
std::cout<<"\nCompiling vertex shader...";
vertexShaderID = loadShaderFromFile(vertexShaderFilePath, GL_VERTEX_SHADER);
std::cout<<"\nCompiling fragment shader...";
fragmentShaderID = loadShaderFromFile(fragmentShaderFilePath, GL_FRAGMENT_SHADER);
programID = glCreateProgram();
glAttachShader(programID, vertexShaderID);
glAttachShader(programID, fragmentShaderID);
glLinkProgram(programID);
GLint status = GL_FALSE;
glGetProgramiv(programID, GL_LINK_STATUS, &status);
if(status == GL_FALSE){
GLint logSize;
glGetShaderiv(programID, GL_INFO_LOG_LENGTH, &logSize);
GLchar description[logSize];
glGetProgramInfoLog(programID, logSize, nullptr, &description[0]);
std::cout<<"\n"<<description;
std::cout<<"\nCould not link shader program!";
}
glValidateProgram(programID);
}
void addAttribute(GLint index, std::string name) {
glBindAttribLocation(programID, index, name.c_str());
}
void addUniform(int value, std::string name) {
glUniform1i(glGetUniformLocation(programID, name.c_str()), value);
}
void addUniform(float value, std::string name) {
glUniform1f(glGetUniformLocation(programID, name.c_str()), value);
}
void addUniform(glm::vec3 value, std::string name) {
glUniform3f(glGetUniformLocation(programID, name.c_str()), value.x, value.y, value.z);
}
void addUniform(glm::mat4 value, std::string name) {
glUniformMatrix4fv(glGetUniformLocation(programID, name.c_str()), 1, GL_FALSE, &value[0][0]);
}
void bind() {
glUseProgram(programID);
}
void unbind() {
glUseProgram(0);
}
~Shader(){
glDeleteProgram(programID);
}
};
#endif
Buffer.h
#ifndef BUFFER_H
#define BUFFER_H
#define GLEW_STATIC
#include <GL/glew.h>
#include <iostream>
class Buffer {
private:
GLuint bufferID;
GLuint index;
GLenum target;
bool active;
public:
Buffer(GLenum target) {
this->target = target;
this->active = false;
glGenBuffers(1, &bufferID);
}
void data(const void *data, int dataSize, GLenum mode) {
glBindBuffer(target, bufferID);
glBufferData(target, dataSize, data, mode);
glBindBuffer(target, 0);
}
void bind(GLuint index, GLint unitSize, GLenum dataType, GLsizei stride, int pointer) {
active = true;
index = index;
glEnableVertexAttribArray(index);
glBindBuffer(target, bufferID);
glVertexAttribPointer(index, unitSize, dataType, GL_FALSE, stride, (void*)pointer);
}
void unbind() {
active = false;
glBindBuffer(target, 0);
glDisableVertexAttribArray(index);
}
GLuint getID() {
return bufferID;
}
~Buffer() {
if(active)
unbind();
glDeleteBuffers(1, &bufferID);
}
};
#endif
Display.h
#ifndef DISPLAY_H
#define DISPLAY_H
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <string>
static void error_callback(int error, const char* description) {
fprintf(stderr, "GLFW Error: %s\n", description);
}
class Display {
private:
GLFWwindow* window;
bool shouldClose;
std::string title;
int width, height;
bool fullscreen;
int msaa_samples;
int fps_cap;
public:
Display() {
shouldClose = true;
setAttributes();
}
void setAttributes(std::string title="OpenGL", int width=640, int height=640, bool fullscreen=false, int msaa_samples=0, int fps_cap=60) {
this->title = title;
this->width = width;
this->height = height;
this->fullscreen = fullscreen;
this->msaa_samples = msaa_samples;
this->fps_cap = fps_cap;
}
bool create() {
glfwSetErrorCallback(error_callback);
if(!glfwInit())
return false;
glfwWindowHint(GLFW_REFRESH_RATE, fps_cap);
glfwWindowHint(GLFW_SAMPLES, msaa_samples);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(width, height, title.c_str(), fullscreen?glfwGetPrimaryMonitor():nullptr, nullptr);
if(!window) {
glfwTerminate();
return false;
}
glfwMakeContextCurrent(window);
glewExperimental = true;
if(glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW!\n");
glfwTerminate();
return false;
}
glViewport(0, 0, width, height);
shouldClose = false;
return true;
}
void update() {
shouldClose = glfwWindowShouldClose(window);
glfwSwapBuffers(window);
glfwPollEvents();
}
void destroy() {
glfwDestroyWindow(window);
glfwTerminate();
}
bool reload() {
glfwDestroyWindow(window);
return create();
}
bool isShouldClose() {
return shouldClose;
}
};
#endif
SHADERY
#version 330 core
in vec3 vertex;
void main()
{
gl_Position = vec4(vertex+vec3(0.1),1.0);
}
//////////////////////////////////////////////////////////
#version 330 core
out vec4 OUT_COLOR;
void main()
{
OUT_COLOR = vec4(1.0,0.0,0.0,1.0);
}
W kodzie mogą jeszcze być niepotrzebne #include.