最近做毕设,将代码重新整理一遍,将原来的OpenGL框架抽象了一遍,重构了一下,在此总结一下。同时,仿照assimp重写了一个obj文件的loader。
obj文件loader编写
obj
文件格式解析见之前的博客,pcd,obj,mtl文件格式解析。obj
主要包含obj
文件和材质文件mtl
。其中模型的结构是按照组来划分的,每个组有自己的材质,而且绝大部分模型不同组不共享顶点【猜测~】。因此将模型处理成组,每个组拥有自己的顶点【包括顶点,纹理,法线】,材质信息【漫反射,高光,贴图等】。主要包含两个类,一个是model
,这是一个模型一个类,一个是mesh
,为每个组一个类。
以下介绍数据结构:
// 材质,暂时没有写贴图
struct Matrial
{
glm::vec3 Ka;
glm::vec3 Kd;
glm::vec3 Ks;
int illum;
std::string mat_name;
};
// 顶点
struct Vertex
{
glm::vec3 pos;
glm::vec3 nor;
glm::vec2 tex;
};
// mesh类
class Mesh
{
public:
std::string meshName;
std::string matrialName;
// 该组的顶点信息
std::vector<glm::vec3> points;
std::vector<glm::vec3> normal;
std::vector<glm::vec2> textCoords;
// 存储网格信息,将顶点重新组织,每个顶点含有位置,纹理,法线
std::vector<Vertex> vertices;
Matrial mat;
void clear();
void setUp();// 传输数据到GPU
void draw(Shader *);// 绘制
private:
GLuint VAO;
GLuint VBO;
};
// model类
class Model
{
public:
Model(){};
~Model(){};
std::string path;
std::string matrial_path;
bool loadModel(std::string path);// 读取模型
void setUp();
void draw(Shader *);
private:
// 包含所有的组
std::vector<Mesh> meshes;
// 记录所有的材质
std::map<std::string, Matrial> matrials;
};
具体的实现参见最后的资源链接。
重构OpenGL工程
OpenGL是原生支持的,但构建完整的OpenGL工程需要有辅助的函数库,主要包括窗口的工具类glfw
,获取OpenGL函数地址的库glew
或者glad
。原生的写OpenGL会代码比较丑陋,很难抽象出来。参考learning OpenGL
上的代码整理成如下的格式。
callBack
类
注册回调函数的基类glfwinit.h
传入基类指针,并且初始化OpenGL环境camera.h
相机类shader.h
着色器类Entrance
类
继承自callback
基类,负责渲染的主过程控制,指针传入到glfwinit.h
部分代码如下:
// callback.h
class ICallbacks
{
public :
GLfloat deltaTime = 0.0f;
virtual void RenderSceneCB() {};// 绘制场景接口
// 回调函数接口
virtual void MouseCB(MOUSE Button, KEY_STATE State, int x, int y){};
virtual void PassiveMouseCB(GLfloat x, GLfloat y) {};
virtual void KeyboardCB(GLFWwindow* window, int Key, int KeyState){};
};
// glfwinit.h
void InitGlfw(ICallbacks * s,int width, int height, std::string title);// 初始化OpenGL环境
// 注册回调函数
void keyfunc(GLFWwindow* window, int k, int scancode, int action, int mode);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
// 绘制场景
void RunShader();
// Entrance.h
class Entrance :public ICallbacks
{
private:
GLfloat lastX = 400, lastY = 300;
GLfloat lastFrame = 0.0f;
bool firstMouse = true;
public:
Camera camera;
std::vector<int> key;
OBJ::Model * o_model;
Shader * shader;
Entrance(int width, int height, std::string title);
void Run();// 绘制函数
// 继承自callback基类的接口
virtual void RenderSceneCB() override;
virtual void KeyboardCB(GLFWwindow* window, int k, int action = GLFW_RELEASE) override;
virtual void PassiveMouseCB(GLfloat xpos, GLfloat ypos) override;
void Do_Movement();// 处理移动
};
效果如图:只适用了最简单的着色器,没有使用贴图。
完整代码github地址
如有错误,欢迎指正~