提示
虽然是基于我的代码写的,但是部分还是能用的
SimpleGL.hpp
这是最重要的头文件,所有代码都包括了它
#ifndef __SIMPLEGL_MAIN_HPP__
#define __SIMPLEGL_MAIN_HPP__
#if defined(USE_GLEW)
#include <GL/glew.h>
#else
#include <glad/glad.c>
#endif
namespace SimpleGL
{
bool initGL()
{
#if defined(__glad_h_)
if(!gladLoadGL()) return false;
#elif defined(__glew_h__)
if(glewInit() != GLEW_OK) return false;
#endif
return true;
}
}
#include "Program.hpp"
#include "Camera.hpp"
#include "Error.hpp"
#include "Sprite.hpp"
#include "Texture.hpp"
#include "Model.hpp"
#include "GLFWUtils.hpp"
#endif
介绍一下这句代码
如果定义了“USE_GLEW”,就会导入GLEW,否则就导入GLAD
用glad.c是因为直接用glad.h就显示未定义资源(就很奇怪)
#if defined(USE_GLEW)
#include <GL/glew.h>
#else
#include <glad/glad.c>
#endif
Camera
Camera类被我重写了
#ifndef __SIMPLEGL_CAMERA_HPP__
#define __SIMPLEGL_CAMERA_HPP__
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <ctime>
namespace SimpleGL
{
class LookAt
{
public:
const float PITCH_MAX = 89.9f;
enum PitchDirection
{
POSITIVE_Y,
ZERO,
NEGATIVE_Y
};
enum YawDirection
{
POSITIVE_X,
POSITIVE_Z,
NEGATIVE_X,
NEGATIVE_Z
};
enum MovementDirection
{
FORWARD,
BACKWARD,
LEFT,
RIGHT,
UP,
DOWN
};
enum MovementSpeed
{
VERY_SLOW,
SLOW,
NORMAL,
FAST,
VERY_FAST,
CUSTOM
};
private:
glm::vec3 m_position;
glm::vec3 m_front;
glm::vec3 m_up;
glm::vec3 m_right;
float m_yaw;
float m_pitch;
glm::mat4 m_view_matrix;
MovementSpeed m_movement_speed;
float m_speed;
float m_sensitivity;
public:
LookAt(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 front = glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f))
{
m_position = position;
m_front = front;
m_up = up;
calcAngle();
update();
m_movement_speed = MovementSpeed::NORMAL;
m_speed = 1.0f;
m_view_matrix = glm::mat4(1.0f);
m_sensitivity = 0.05f;
}
LookAt(glm::vec3 position, float yaw, float pitch, glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f))
{
m_position = position;
m_yaw = yaw;
m_pitch = pitch;
m_up = up;
update();
m_movement_speed = MovementSpeed::NORMAL;
m_speed = 1.0f;
m_view_matrix = glm::mat4(1.0f);
m_sensitivity = 0.05f;
}
public:
LookAt& operator=(const LookAt& lookAt)
{
m_position = lookAt.m_position;
m_front = lookAt.m_front;
m_up = lookAt.m_up;
m_right = lookAt.m_right;
m_yaw = lookAt.m_yaw;
m_pitch = lookAt.m_pitch;
m_view_matrix = lookAt.m_view_matrix;
m_movement_speed = lookAt.m_movement_speed;
m_speed = lookAt.m_speed;
m_sensitivity = lookAt.m_sensitivity;
return *this;
}
public:
LookAt& calcAngle()
{
m_front = glm::normalize(m_front);
m_yaw = glm::degrees(glm::atan(m_front.z, m_front.x));
m_pitch = glm::degrees(glm::asin(m_front.y));
return *this;
}
LookAt& update()
{
if (m_pitch > PITCH_MAX)
m_pitch = PITCH_MAX;
if (m_pitch < -PITCH_MAX)
m_pitch = -PITCH_MAX;
float h = glm::cos(glm::radians(m_pitch));
float x = glm::cos(glm::radians(m_yaw)) * h;
float y = glm::sin(glm::radians(m_pitch));
float z = glm::sin(glm::radians(m_yaw)) * h;
m_front = glm::normalize(glm::vec3(x, y, z));
m_right = glm::normalize(glm::cross(m_front, m_up));
m_view_matrix = glm::lookAt(m_position, m_position + m_front, m_up);
return *this;
}
public:
LookAt& setYawDirection(YawDirection direction)
{
if (direction == YawDirection::POSITIVE_X)
m_yaw = 0.0f;
else if (direction == YawDirection::POSITIVE_Z)
m_yaw = 90.0f;
else if (direction == YawDirection::NEGATIVE_X)
m_yaw = 180.0f;
else if (direction == YawDirection::NEGATIVE_Z)
m_yaw = 270.0f;
update();
return *this;
}
LookAt& setYaw(float yaw)
{
m_yaw = yaw;
update();
return *this;
}
LookAt& yaw(float degree)
{
m_yaw += degree;
update();
return *this;
}
float getYaw()
{
return m_yaw;
}
LookAt& setPitchDirection(PitchDirection direction)
{
if (direction == PitchDirection::POSITIVE_Y)
m_pitch = PITCH_MAX;
else if (direction == PitchDirection::ZERO)
m_pitch = 0.0f;
else if (direction == PitchDirection::NEGATIVE_Y)
m_pitch = -PITCH_MAX;
update();
return *this;
}
LookAt& setPitch(float pitch)
{
m_pitch = pitch;
update();
return *this;
}
LookAt& pitch(float degree)
{
m_pitch += degree;
update();
return *this;
}
float getPitch()
{
return m_pitch;
}
LookAt& setPosition(glm::vec3 position)
{
m_position = position;
update();
return *this;
}
LookAt& move(glm::vec3 distance, float deltaTime = 1.0f)
{
m_position += distance * deltaTime;
update();
return *this;
}
glm::vec3 getPosition()
{
return m_position;
}
LookAt& setFront(glm::vec3 front)
{
m_front = front;
calcAngle();
update();
return *this;
}
glm::vec3 getFront()
{
return m_front;
}
LookAt& setUp(glm::vec3 up)
{
m_up = up;
update();
return *this;
}
glm::vec3 getUp()
{
return m_up;
}
LookAt& setMovementSpeed(MovementSpeed movement_speed, float speed = 1.0f)
{
m_movement_speed = movement_speed;
if (m_movement_speed == MovementSpeed::VERY_SLOW)
m_speed = 0.2f;
else if (m_movement_speed == MovementSpeed::SLOW)
m_speed = 0.5f;
else if (m_movement_speed == MovementSpeed::NORMAL)
m_speed = 1.0f;
else if (m_movement_speed == MovementSpeed::FAST)
m_speed = 2.0f;
else if (m_movement_speed == MovementSpeed::VERY_FAST)
m_speed = 5.0f;
else if (m_movement_speed == MovementSpeed::CUSTOM)
m_speed = speed;
return *this;
}
float getMovementSpeed()
{
return m_speed;
}
LookAt& move(MovementDirection direction, float deltaTime = 1.0f)
{
if (direction == MovementDirection::FORWARD)
m_position += m_front * m_speed * deltaTime;
else if (direction == MovementDirection::BACKWARD)
m_position += (-m_front) * m_speed * deltaTime;
else if (direction == MovementDirection::LEFT)
m_position += (-m_right) * m_speed * deltaTime;
else if (direction == MovementDirection::RIGHT)
m_position += m_right * m_speed * deltaTime;
else if (direction == MovementDirection::UP)
m_position += m_up * m_speed * deltaTime;
else if (direction == MovementDirection::DOWN)
m_position += (-m_up) * m_speed * deltaTime;
update();
return *this;
}
inline float clocksToSeconds(clock_t clocks)
{
return float(clocks) / float(CLOCKS_PER_SEC);
}
LookAt& rotate(float deltaX, float deltaY)
{
m_yaw += deltaX * m_sensitivity;
m_pitch += deltaY * m_sensitivity;
update();
return *this;
}
LookAt& setRotateSpeed(float sensitivity)
{
m_sensitivity = sensitivity;
return *this;
}
float getSensitivity()
{
return m_sensitivity;
}
LookAt& setViewMatrix(glm::mat4 matrix)
{
m_view_matrix = matrix;
return *this;
}
glm::mat4 getViewMatrix()
{
return m_view_matrix;
}
};
class Projection
{
public:
const float FOVY_MIN = 0.1f;
const float FOVY_MAX = 179.9f;
enum ProjectionType
{
ORTHO,
FRUSTUM,
PERSPECTIVE
};
private:
ProjectionType m_projection_type;
float m_fovy;
float m_aspect;
float m_left;
float m_right;
float m_bottom;
float m_top;
float m_near;
float m_far;
glm::mat4 m_projection_matrix;
public:
Projection(float near_plane = 0.1f, float far_plane = 100.0f)
{
m_near = near_plane;
m_far = far_plane;
m_projection_type = Projection::PERSPECTIVE;
m_projection_matrix = glm::mat4(1.0f);
}
Projection(float fovy, float aspect, float near_plane = 0.1f, float far_plane = 100.0f)
{
m_fovy = fovy;
m_aspect = aspect;
m_near = near_plane;
m_far = far_plane;
m_projection_type = Projection::PERSPECTIVE;
m_projection_matrix = glm::mat4(1.0f);
}
Projection(float l, float r, float b, float t, float n = 0.1f, float f = 100.0f)
{
m_left = l;
m_right = r;
m_bottom = b;
m_top = t;
m_near = n;
m_far = f;
m_projection_type = Projection::PERSPECTIVE;
m_projection_matrix = glm::mat4(1.0f);
}
public:
Projection& operator=(const Projection& projection)
{
m_projection_type = projection.m_projection_type;
m_fovy = projection.m_fovy;
m_aspect = projection.m_aspect;
m_left = projection.m_left;
m_right = projection.m_right;
m_bottom = projection.m_bottom;
m_top = projection.m_top;
m_near = projection.m_near;
m_far = projection.m_far;
m_projection_matrix = projection.m_projection_matrix;
return *this;
}
public:
Projection& setProjectionType(ProjectionType type)
{
m_projection_type = type;
return *this;
}
ProjectionType getProjectionType()
{
return m_projection_type;
}
Projection& setFovy(float fovy)
{
m_fovy = fovy;
update();
return *this;
}
Projection& zoom(float degree)
{
m_fovy += degree;
update();
return *this;
}
float getFovy()
{
return m_fovy;
}
Projection& setAspect(float aspect)
{
m_aspect = aspect;
update();
return *this;
}
float getAspect()
{
return m_aspect;
}
Projection& set(float l, float r, float b, float t, float n = 0.1f, float f = 100.0f)
{
m_left = l;
m_right = r;
m_bottom = b;
m_top = t;
m_near = n;
m_far = f;
update();
return *this;
}
Projection& set(float fovy, float aspect, float near_plane = 0.1f, float far_plane = 100.0f)
{
m_fovy = fovy;
m_aspect = aspect;
m_near = near_plane;
m_far = far_plane;
update();
return *this;
}
Projection& update()
{
if (m_fovy < FOVY_MIN)
m_fovy = FOVY_MIN;
else if (m_fovy > FOVY_MAX)
m_fovy = FOVY_MAX;
if (m_projection_type == ProjectionType::ORTHO)
m_projection_matrix = glm::ortho(m_left, m_right, m_bottom, m_top, m_near, m_far);
else if (m_projection_type == ProjectionType::FRUSTUM)
m_projection_matrix = glm::frustum(m_left, m_right, m_bottom, m_top, m_near, m_far);
else if (m_projection_type == ProjectionType::PERSPECTIVE)
m_projection_matrix = glm::perspective(m_fovy, m_aspect, m_near, m_far);
return *this;
}
Projection& setProjectionMatrix(glm::mat4 matrix)
{
m_projection_matrix = matrix;
return *this;
}
glm::mat4 getProjectionMatrix()
{
return m_projection_matrix;
}
};
class Camera : public LookAt, public Projection
{
public:
Camera() : LookAt(), Projection() {}
Camera(glm::vec3 position, glm::vec3 front, glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f)) : LookAt(position, front, up), Projection() {}
Camera(glm::vec3 position, float yaw, float pitch, glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f)) : LookAt(position, yaw, pitch, up), Projection() {}
};
}
#endif
GLFWUtils
最后才是今天的主角
#ifndef __SIMPLEGL_GLFWUTILS_HPP__
#define __SIMPLEGL_GLFWUTILS_HPP__
#include "SimpleGL.hpp"
#include <GLFW/glfw3.h>
#include <string>
namespace SimpleGL
{
class GLFWUtils
{
public:
static void processInput(GLFWwindow* window, Camera& camera, float deltaTime)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
camera.move(SimpleGL::Camera::MovementDirection::FORWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.move(SimpleGL::Camera::MovementDirection::BACKWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.move(SimpleGL::Camera::MovementDirection::LEFT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.move(SimpleGL::Camera::MovementDirection::RIGHT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS)
camera.move(SimpleGL::Camera::MovementDirection::UP, deltaTime);
if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS)
camera.move(SimpleGL::Camera::MovementDirection::DOWN, deltaTime);
if (glfwGetKey(window, GLFW_KEY_F1) == GLFW_PRESS)
{
float speed = camera.getMovementSpeed();
speed -= 0.01f;
speed = std::max(speed, 0.1f);
camera.setMovementSpeed(SimpleGL::Camera::MovementSpeed::CUSTOM, speed);
}
else if (glfwGetKey(window, GLFW_KEY_F2) == GLFW_PRESS)
{
float speed = camera.getMovementSpeed();
speed += 0.01f;
speed = std::min(speed, 5.0f);
camera.setMovementSpeed(SimpleGL::Camera::MovementSpeed::CUSTOM, speed);
}
}
static void processCursor(Camera& camera, glm::vec2& lastPos, glm::vec2 currentPos, bool& isFirst)
{
if (isFirst)
{
lastPos = currentPos;
isFirst = false;
}
glm::vec2 delta = currentPos - lastPos;
lastPos = currentPos;
camera.rotate(-delta.x, delta.y);
}
static void processResize(Camera& camera, int width, int height)
{
camera.setAspect(float(width) / float(height));
glViewport(0, 0, width, height);
}
static void processScroll(Camera& camera, float offset)
{
camera.zoom(offset);
}
template<typename T>
static T* getUserData(GLFWwindow* window)
{
return (T*)glfwGetWindowUserPointer(window);
}
static GLFWwindow* initWindow_FullScreen(std::string title, int major = 3, int minor = 3)
{
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, major);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, minor);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
const GLFWvidmode* videomode = glfwGetVideoMode(monitor);
GLFWwindow* window = glfwCreateWindow(videomode->width, videomode->height, title.data(), monitor, NULL);
glfwMakeContextCurrent(window);
return window;
}
static void disableCursor(GLFWwindow* window)
{
if (window != nullptr)
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
}
static void calcDeltaTime(float& lastTime, float& deltaTime)
{
float currentTime = glfwGetTime();
deltaTime = currentTime - lastTime;
lastTime = currentTime;
}
template<typename T>
static T* newUserData(GLFWwindow* window)
{
T* data = new T;
glfwSetWindowUserPointer(window, data);
return data;
}
};
}
#endif
简单的示例
最最最后是一个简单的示例
//#define USE_GLFW
#include "SimpleGL/SimpleGL.hpp"
#include <GLFW/glfw3.h>
#include <iostream>
class RenderableSprite : public SimpleGL::Sprite
{
public:
GLuint VAO;
GLuint count;
GLenum mode;
public:
RenderableSprite()
{
VAO = 0;
count = 0;
mode = GL_TRIANGLES;
}
~RenderableSprite()
{
glDeleteVertexArrays(1, &VAO);
}
public:
RenderableSprite& render(SimpleGL::Program& program)
{
program.setUniform("u_model", getModelMatrix());
glBindVertexArray(VAO);
glDrawArrays(mode, 0, count);
glBindVertexArray(0);
return *this;
}
};
struct Data
{
SimpleGL::Camera camera;
SimpleGL::Program program;
GLuint FBO;
GLuint texture;
RenderableSprite axis;
RenderableSprite model;
bool isFirst;
glm::vec2 lastPos;
float lastTime;
float deltaTime;
};
void processInput(GLFWwindow* window);
void cursor_pos(GLFWwindow* window, double x, double y);
void framebuffer_size(GLFWwindow* window, int width, int height);
void scroll(GLFWwindow* window,double x,double y);
int main()
{
glfwInit();
GLFWwindow* window = SimpleGL::GLFWUtils::initWindow_FullScreen("OpenGL 3.3");
glfwSetCursorPosCallback(window, cursor_pos);
glfwSetFramebufferSizeCallback(window, framebuffer_size);
glfwSetScrollCallback(window,scroll);
SimpleGL::GLFWUtils::disableCursor(window);
if (!SimpleGL::initGL())
{
std::cout << "Failed to init GL." << std::endl;
return -1;
}
glEnable(GL_DEPTH_TEST);
Data* data = SimpleGL::GLFWUtils::newUserData<Data>(window);
data->isFirst = true;
data->lastTime = glfwGetTime();
data->camera.setPosition(glm::vec3(1, 1, 1));
data->camera.setFront(glm::vec3(-1, -1, -1));
data->camera.set(60, 1);
bool success = data->program.loadProgramFromFile("shader/vertex.vert", "shader/lighting.frag");
if (!success)
{
std::cout << "Failed to load program." << std::endl;
std::cout << data->program.getError() << std::endl;
return -1;
}
GLfloat axis_ver[] =
{
-100.0f, 0.0f, 0.0f,
100.0f, 0.0f, 0.0f,
0.0f, -100.0f, 0.0f,
0.0f, 100.0f, 0.0f,
0.0f, 0.0f, -100.0f,
0.0f, 0.0f, 100.0f
};
GLfloat axis_col[] =
{
0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f
};
GLuint axis_vao;
GLuint axis_vbo[2];
glGenVertexArrays(1, &axis_vao);
glGenBuffers(2, axis_vbo);
glBindVertexArray(axis_vao);
glBindBuffer(GL_ARRAY_BUFFER, axis_vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(axis_ver), axis_ver, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr);
glBindBuffer(GL_ARRAY_BUFFER, axis_vbo[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(axis_col), axis_col, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(2, axis_vbo);
RenderableSprite axis;
axis.VAO = axis_vao;
axis.count = sizeof(axis_ver) / sizeof(float) / 3;
axis.mode = GL_LINES;
data->axis = axis;
while (!glfwWindowShouldClose(window))
{
SimpleGL::GLFWUtils::calcDeltaTime(data->lastTime,data->deltaTime);
processInput(window);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
data->program.useProgram();
data->program.setUniform("u_projection", data->camera.getProjectionMatrix());
data->program.setUniform("u_view", data->camera.getViewMatrix());
data->program.setUniform("u_cameraposition", data->camera.getPosition());
data->program.setUniform("u_enableUniformColor", false);
data->program.setUniform("u_enableTexture", false);
data->program.setUniform("u_enableLighting", false);
data->axis.render(data->program);
glfwSwapBuffers(window);
glfwPollEvents();
}
delete data;
glfwTerminate();
return 0;
}
void processInput(GLFWwindow* window)
{
Data* data = SimpleGL::GLFWUtils::getUserData<Data>(window);
SimpleGL::GLFWUtils::processInput(window,data->camera,data->deltaTime);
}
void cursor_pos(GLFWwindow* window, double x, double y)
{
Data* data = SimpleGL::GLFWUtils::getUserData<Data>(window);
glm::vec2 currentPos = glm::vec2(x, y);
SimpleGL::GLFWUtils::processCursor(data->camera,data->lastPos,currentPos,data->isFirst);
}
void framebuffer_size(GLFWwindow* window, int width, int height)
{
Data* data = SimpleGL::GLFWUtils::getUserData<Data>(window);
SimpleGL::GLFWUtils::processResize(data->camera,width,height);
}
void scroll(GLFWwindow* window,double x,double y)
{
Data* data = SimpleGL::GLFWUtils::getUserData<Data>(window);
SimpleGL::GLFWUtils::processScroll(data->camera,y);
}
运行结果
结果就算了,就一坐标轴