当前位置: 首页 > news >正文

【OpenGL】简单的渲染架构设计与封装

目录

一、总体设计

二、Object类的设计

三、Material类设计

四、Mesh类的设计

五、Light类的设计

六、Renderer类的设计

七、具体使用


前言:刚学OpenGL,主要想要记录下学到的东西,也当作一个笔记,部分理解可能有偏差,也是不全面的,如果有发现问题的话也很高兴大家可以指正,我会尽快修改的,在后续学习过程中,也会进行相应的补充与修改。(除了运行结果的截图,课件截图一般均来源于bilibili赵新政老师[后面有水印的])

补充说明:这只是一个mini架构,并不能兼容各种各样的功能,只是便于学习阶段的理解与使用。因而在设计时只是简单封装,甚至变量类型都是设置成了public(可以自行写成private然后添加set和get函数)。提供的只是封装部分的代码,并非完整代码,完整代码在绑定资源当中。

(OpenGL老师:赵新政的个人空间-赵新政个人主页-哔哩哔哩视频)

最终的话是使用封装好的功能去实现下图所示的效果,在原来一个球体的基础上,再去实现一个旋转的球体。(我们设计架构的主要目的,便是为了简化这一创建过程)

一、总体设计

在学习进程的推进下,随着功能的不断扩充,原本的代码结构显得相当凌乱。因而,为了使代码结构更清晰,使用更为方便,就需要去进行一次重构。

对于每一个网格体Mesh(用于表示一个单独模型),他们都是从物体Objcct概念下派生出来的(可以进行移动,旋转和缩放),对于Mesh而言,他需要包含Geometry(几何数据)和Material(材质类型)。

在实现好了Mesh的封装后,便需要将他们一一放到渲染列表当中,使用Renderer(渲染器)进行渲染,而对于渲染器Renderer而言,他需要知道当前材质应当使用什么样的光照Light,以及相机Camera的相关数据。

所以,接下来就需要考虑如何去设计Object、Material、Mesh、Light以及Renderer

二、Object类的设计

Object代表一个物体,而对于一个物体而言,他们都应该可以完成缩放、旋转和平移,并在世界坐标系下进行移动。

在这里将会遵循unity标准进行实现:

①模型变换的顺序为:缩放,旋转,平移

②物体旋转的顺序为:pitch(俯仰),yaw(偏航),row(翻转)

为了完成上述目标,就需要一个记录物体当前位置的变量m_position,在每个轴上旋转的角度angle,以及缩放比例m_scale。

对外应当暴露设置物体位置的函数、设置旋转角度的函数(这里为增量旋转)、设置缩放比例的函数、并提供获取模型变换矩阵的函数。

object.h:

#pragma once#include"core.h"class Object 
{
public:Object();~Object();void set_position(glm::vec3 position);//增量旋转void rorate_x(float angle);void rorate_y(float angle);void rorate_z(float angle);void set_scale(glm::vec3 scale);glm::mat4 get_model_matrix();protected:glm::vec3 m_position{ 0.0f };//unity旋转标准:pitch、yaw、rollfloat m_angle_x{ 0.0f };float m_angle_y{ 0.0f };float m_angle_z{ 0.0f };glm::vec3 m_scale{ 1.0f };};

object.cpp:
 

#include"object.h"Object::Object()
{}
Object::~Object()
{}void Object::set_position(glm::vec3 position)
{m_position = position;
}//增量旋转
void Object::rorate_x(float angle)
{m_angle_x += angle;
}
void Object::rorate_y(float angle)
{m_angle_y += angle;
}
void Object::rorate_z(float angle)
{m_angle_z += angle;
}
void Object::set_scale(glm::vec3 scale)
{m_scale = scale;
}glm::mat4 Object::get_model_matrix()
{//unity标准:缩放 旋转 平移glm::mat4 transform{ 1.0f };transform=glm::scale(transform, m_scale);//unity旋转标准:pitch yaw rolltransform = glm::rotate(transform, glm::radians(m_angle_x), glm::vec3(1.0f, 0.0f, 0.0f));transform = glm::rotate(transform, glm::radians(m_angle_y), glm::vec3(0.0f, 1.0f, 0.0f));transform = glm::rotate(transform, glm::radians(m_angle_z), glm::vec3(0.0f, 0.0f, 1.0f));//在世界坐标系下平移transform = glm::translate(glm::mat4(1.0f), m_position) * transform;return transform;
}

三、Material类设计

材质(Material):描述了物体表面如何与光发生反应

(①漫反射②高光反射③环境光效果)

目前所学习的光照模型方式:Phong-LightingModel(冯氏光照模型)

(由越南计算机科学家冯宝荣(Bui Tuong Phong)提出)

而基于冯氏光照模型我们又应该提供哪些参数呢?

·材质参数

物体的漫反射颜色(Diffuse Color)其实可以代表本身的固有色

·物体本身固有色可以用两种方式表示:

  1. 物体顶点颜色+插值
  2. 使用像素uv采样贴图(当前常用的)

最终都可以得到漫反射颜色(Diffuse Color)

·物体的高光反射性质   ==>  光斑大小调整(Shiniess)

·物体的环境反射颜色 ==>大多数情况设置为物体贴图颜色

·父类设计为Material,包含一个类型参数

material.h

#pragma once
#include"../core.h"//使用C++枚举类型
enum class MaterialType
{PhongMaterial,
};class Material
{
public:Material();~Material();public:MaterialType m_type;
};

material.cpp

#include"material.h"Material::Material()
{}
Material::~Material()
{}

phong_material.h

#pragma once
#include"material.h"
#include"../texture.h"class PhongMaterial :public Material
{
public:PhongMaterial();~PhongMaterial();public:Texture* m_diffuse{ nullptr };float m_shininess{ 1.0f };};

phong_material.cpp

#include"phong_material.h"PhongMaterial::PhongMaterial()
{m_type = MaterialType::PhongMaterial;
}
PhongMaterial::~PhongMaterial()
{}

四、Mesh类的设计

Mesh包含两个关键信息:
①几何外观Geometry

②材质信息Material

那么在设计当中,就需要为他提供Material和Geometry的指针,并在构造函数中传入

mesh.h

#pragma once
#include"object.h"
#include"geometry.h"
#include"material/material.h"class Mesh :public Object
{
public:Mesh(Geometry* geometry, Material* material);~Mesh();public:Geometry* m_geometry{ nullptr };Material* m_material{ nullptr };
};

mesh.cpp

#include"mesh.h"Mesh::Mesh(Geometry* geometry, Material* material)
{m_geometry = geometry;m_material = material;
}
Mesh::~Mesh()
{}

五、Light类的设计

这里的光照包含平行光与环境光,对于所有的光而言,其颜色跟高光反色的强度使共有的。

而平行光则需要额外携带方向信息,环境光只作为权值的叠加避免“死黑”的出现。(该过程只需要改变其本身携带的color信息)

light.h

#pragma once
#include"../core.h"class Light
{
public:Light();~Light();public:glm::vec3 m_color{ 1.0f };float m_specular_intensity{ 1.0f };};

directional_light.h

#pragma once
#include"light.h"class DirectionalLight :public Light 
{
public:DirectionalLight();~DirectionalLight();public:glm::vec3 m_direction{ -1.0f };};

ambient_light.h

#pragma once
#include"light.h"class AmbientLight : public Light {
public:AmbientLight();~AmbientLight();};

六、Renderer类的设计

渲染器需要执行渲染的功能。

它会遍历列表中的每一个Mesh,根据传入的相机来确定位置,并受到光照影响。

在每一帧的渲染当中,会根据材质类型去使用不同的着色器shader。

之后的话就是考虑如何进行渲染,也就是需要去完善render函数

那么根据绘制流程,所需要做的便是:

  1. 设置当前帧绘制的时候,OpenGL的必要状态机参数(开启深度检测)
  2. 清理画布glClear
  3. 遍历mesh列表,对每个mesh进行绘制

而在进行对mesh 的绘制当中,则需要去进行:

  1. 确定shader,更新shader中的uniform变量(MVP变换、光源参数、相机信息等)
  2. 将纹理绑定对应的纹理单元
  3. 绑定vao
  4. 执行绘制命令
  5. 解绑

在绑定纹理单元的时候,就会遇到一个问题,那就是mesh当中存储着material信息,而material的父类并没有设计自身的纹理数据,实际的纹理数据存在于phong_material子类当中。

因此,就需要先通过material中存储的type数据,根据其材质类型(这里使用的是冯氏光照模型),通过数据类型强转获取数据。

renderer.h

#pragma once
#include"../core.h"
#include"../mesh.h"
#include"../../Application/camera/camera.h"
#include"../light/directional_light.h"
#include"../light/ambient.h"
#include"../shader.h"
#include<vector>class Renderer
{
public:Renderer();~Renderer();//渲染功能函数,每次调用都会渲染一帧void render(std::vector<Mesh*>&mesh_list,Camera* camera,DirectionalLight* light,/*这里没有考虑多个光的照射*/AmbientLight* ambient);private:Shader* pick_shader(MaterialType type);private://生成多种不同的shader对象//根据材质类型的不同,挑选使用哪一个shader对象Shader* m_phong_shader{ nullptr };};

renderer.cpp

#include"renderer.h"
#include"../material/phong_material.h"
#include<iostream>Renderer::Renderer()
{m_phong_shader = new Shader("assets/shaders/phong.vert", "assets/shaders/phong.frag");
}
Renderer::~Renderer()
{}//渲染功能函数,每次调用都会渲染一帧
void Renderer::render(std::vector<Mesh*>& mesh_list,Camera* camera,DirectionalLight* light,/*这里没有考虑多个光的照射*/AmbientLight* ambient
)
{//1.设置当前帧绘制的时候,opengl的必要状态机参数glEnable(GL_DEPTH_TEST);glDepthFunc(GL_LESS);//2.清理画布glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//3.遍历mesh列表,对每个mesh进行绘制for (auto mesh : mesh_list){auto geometry = mesh->m_geometry;auto material = mesh->m_material;//1.决定使用哪一个shaderShader* shader = pick_shader(material->m_type);//2.更新shader的uniform变量//2.1.绑定programshader->on_begin();switch (material->m_type){case MaterialType::PhongMaterial: {PhongMaterial* phong_material = (PhongMaterial*)material;//diffuse贴图shader->set_uniform_1i("sampler", 0);//将纹理与纹理单元进行挂钩phong_material->m_diffuse->bind();//mvp变换shader->set_uniform_4matrix("model_matrix", mesh->get_model_matrix());shader->set_uniform_4matrix("view_matrix", camera->get_view_matrix());shader->set_uniform_4matrix("projection_matrix", camera->get_projection_matrix());//光源参数更新shader->set_uniform_3vec("light_direction", light->m_direction);shader->set_uniform_3vec("light_color", light->m_color);shader->set_uniform_3vec("ambient_color", ambient->m_color);shader->set_uniform_1f("specular_intensity", light->m_specular_intensity);shader->set_uniform_1f("shininess", phong_material->m_shininess);//相机信息更新shader->set_uniform_3vec("camera_position", camera->m_position);//计算normal_matrixauto normal_matrix = glm::transpose(glm::inverse(glm::mat3(mesh->get_model_matrix())));shader->set_uniform_3matrix("normal_matrix", normal_matrix);break;}default:continue;//直接执行循环的下一个}//3.绑定vaoglBindVertexArray(mesh->m_geometry->get_vao());//4.执行绘制命令glDrawElements(GL_TRIANGLES, geometry->get_indices_count(), GL_UNSIGNED_INT, (void*)0);//5.解绑glBindVertexArray(0);shader->on_end();}}Shader* Renderer::pick_shader(MaterialType type)
{Shader* result = nullptr;switch (type){case MaterialType::PhongMaterial:result = m_phong_shader;break;default:std::cout << "Unknow material type to pick shader" << std::endl;break;}return result;
}

七、具体使用

此处封装其实就是简化了大量vbo,ebo,vao等的创建绑定等行为,当需要添加一个mesh 的时候,只需要根据创建好其material和geometry(这个过程也已经通过封装进行了简化),然后设置好相应的属性值即可。

最后需要进行转动,也就只需要在每一帧的渲染过程中对其增量旋转函数进行调用即可。

main.cpp

#include<iostream>
#include<string>
#include<assert.h>#include"glframework/core.h"
#include"glframework/shader.h"#include"wrapper/checkError.h"
#include"Application/Application.h"#define STB_IMAGE_IMPLEMENTATION
#include"Application/stb_image.h"
#include"glframework/texture.h"#include"Application/camera/perspective_camera.h"
#include"Application/camera/orthographic_camera.h"
#include"Application/camera/trackball_camera_control.h"
#include"Application/camera/game_camera_control.h"#include"glframework/geometry.h"
#include"glframework/material/phong_material.h"
#include"glframework/mesh.h"
#include"glframework/renderer/renderer.h"Renderer* renderer;
std::vector<Mesh*> mesh_list{};
DirectionalLight* directed_light = nullptr;
AmbientLight* ambient_light = nullptr;
Mesh* mesh = nullptr;
Mesh* mesh2 = nullptr;Geometry* geometry = nullptr;
PhongMaterial* material = nullptr;
PhongMaterial* material2 = nullptr;Camera* camera = nullptr;
CameraControl* camera_control = nullptr;void on_resize(int width, int height)
{GL_CALL(glViewport(0, 0, width, height));
}
void on_key(int key, int action, int mods)
{camera_control->on_key(key, action, mods);
}
void on_mouse(int button, int action, int mods)
{double x, y;app->get_cursor_pos(&x, &y);camera_control->on_mouse(button, action, x, y);
}
void on_cursor(double xpos, double ypos)
{camera_control->on_cursor(xpos, ypos);
}
void on_scroll(double offset)
{camera_control->on_scroll(offset);
}void prepare_perspective_camera()
{camera = new PerspectiveCamera(60.0f, (float)app->get_width() / (float)app->get_height(), 0.1f, 1000.0f);camera_control = new TrackballCameraControl();camera_control->set_camera(camera);
}void prepare()
{renderer = new Renderer();//1.创建geometrygeometry = Geometry::create_sphere(1.5f);//2.创建一个material并且配置参数material = new PhongMaterial();material->m_diffuse = new Texture("assets/textures/StrawValley.png", 0);material->m_shininess = 32.0f;material2=new PhongMaterial();material2->m_diffuse = new Texture("assets/textures/world.jpg", 0);material2->m_shininess = 64.0f;//3.生成meshmesh = new Mesh(geometry, material);mesh_list.push_back(mesh);mesh2=new Mesh(geometry, material2);mesh->set_position(glm::vec3(-4.0f, 0.0f, 0.0f));mesh_list.push_back(mesh2);directed_light=new DirectionalLight();directed_light->m_color = glm::vec3(1.0f);directed_light->m_specular_intensity = 32.0f;ambient_light = new AmbientLight();ambient_light->m_color = glm::vec3(0.2f);
}int main()
{if (!app->on_init(800, 600)){return -1;}app->set_resize_call_back(on_resize);app->set_key_board_call_back(on_key);app->set_mouse_call_back(on_mouse);app->set_cursor_call_back(on_cursor);app->set_scroll_call_back(on_scroll);GL_CALL(glViewport(0, 0, 800, 600));GL_CALL(glClearColor(0.2f, 0.3f, 0.3f, 1.0f));prepare_perspective_camera();prepare();while (app->on_update()) {mesh_list[1]->rorate_x(0.01f);mesh_list[1]->rorate_y(0.03f);camera_control->on_update();renderer->render(mesh_list, camera, directed_light, ambient_light);};app->on_destroy();return 0;
}

http://www.dtcms.com/a/416062.html

相关文章:

  • 制作企业网站的秘诀腾讯云服务器新人优惠
  • 【系统架构设计(38)】数据库规范化理论
  • 合肥专业手机网站制作价格anaconda可以做网站吗
  • 商业网站可以选择.org域名吗江苏专业网站建设费用
  • 服装工厂软件有哪些,如何合理控制服装软件费用?
  • 学会建网站如何做网络营销外包网站开发合同
  • 3C电子企业柔性制造转型:如何通过MES管理系统实现快速换线与弹性生产?
  • BOM与DOM
  • 广东外贸网站推广公司wordpress去除下一页
  • 网站运营与网络推广方案二手房网站开发
  • 莞城区做网站山西网站建设服务
  • 做外贸有哪些好的网站有哪些湘潭做网站 用户多磐石网络
  • 数据结构与算法7:树和二叉树
  • 婚纱网站模板下载建电影网站程序
  • 医疗设备响应式网站临沂网站推广排名
  • Lazarus结合Lazserial多线程方式的串口采集实操心得
  • nano工具
  • 专门做西装网站wordpress alipay
  • 网络公司企业网站源码aso优化违法吗
  • 中国建设法律法规网官方网站手机可以搭建网站吗
  • 怎么用网站做文案wordpress网站有支付功能吗
  • 手工做皮具国外的网站工信部网站报备
  • 上海高端品牌网站建设专家郑州东区做网站电话
  • 手表网站起名网站常用插件
  • 网站建设推广接单语wordpress 3.5 漏洞
  • 保定模板做网站手机在线做ppt的网站有哪些问题
  • win8扁平化网站牙科医院网站源码
  • 徐州建设局网新网站永康电子商务网站建设公司
  • 加盟网站建设公司电子商务网站帮助中心该怎么更好地设计
  • OpenDDS运行配置可编程化