| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 游戏开发 -> <2021SC@SDUSC> 开源游戏引擎 Overload 代码模块分析 之 OvGame(三)—— Core(二)GameRenderer -> 正文阅读 |
|
[游戏开发]<2021SC@SDUSC> 开源游戏引擎 Overload 代码模块分析 之 OvGame(三)—— Core(二)GameRenderer |
2021SC@SDUSC 目录前言本篇是 OvGame 的 Core 的第二篇,将探究其倒二层引用的文件:GameRenderer。该文件会包含 Core 的另一个部分 —— Context,所以如果读者已经有些遗忘、或是尚未了解过,请前往 Core(一)阅读。 另外,若想先大致了解该引擎各个大模块,可前往笔者这篇相关文章查看。 GameRenderer1、GameRenderer.h1.1 头文件
这里引入了 Overload 的 OvCore 模块的部分文件,在此不多讲述,遇到再简单探究;还引入了上一篇探究的 Context 文件。 1.2 主体代码该文件的主体代码包含了一个 GameRenderer 类,负责游戏界面的渲染工作,定义如下:
该类包含了两个私有类,类型分别是上篇文章的 Context.h 文件中定义的 Context 类与包含材质设置以及 Shader 的一个类 Material;另一方面,GameRenderer 的函数功能已有注释,不多赘述,我们来 cpp 文件中进一步探究: 2、GameRenderer.cpp2.1 头文件
该文件一样是引入了多个 Overload 几个模块的文件,涉及到再作分析。 2.2 主体代码主体代码先声明了一些命名空间,并又多包含了两模块 OvMaths 与 OvRendering:
接下来依次探究 GameRenderer 的函数: GameRenderer() 函数该函数是类的构造函数,咱们分两段代码看:
首先,参数初始化表初始化 Context 类的 m_context;然后,m_context 的变量 shaderManager 调用运算符重载函数 “ [ ] ” 获取目标路径的文件(此处为 OpenGL 的 glsl 文件),并传入 Material 类的 m_emptyMaterial 调用 SetShader() 进行设置,绑定为 EngineUBO;最后,m_emptyMaterial 调用 Set() 函数(该函数的两个参数会分别作为 key 和 value 存入哈希表)设置漫反射初值、以及设置漫反射贴图为空。 这样 m_emptyMaterial 就初始化完成了,接着处理 m_context:
m_context 的变量 renderer 使用了一个特殊结构 [ this ] ( ) { }。这是 C++11 引入的 Lambda 表达式,可以简单理解为是一种未命名也无需命名的内联函数,可以使得代码更为简洁。此处嵌套在了 RegisterModelMatrixSender() 与 RegisterUserMatrixSender() 的参数内。 RegisterModelMatrixSender() 函数可以记录模型矩阵,并能通过它传给 GPU,所以传入的参数是一个四维矩阵。该函数的 Lambda 表达式是 m_context 的变量 engineUBO 调用 SetSubData() 函数,其有两个参数依次为 p_data、p_offsetInOut,函数能将位于位置 p_offsetInOut 的 UBO(缓冲对象,OpenGL 的数据结构)设置其值为 p_data。此处,是在位置 0 将 UBO 设置为 Transpose() 转置后的矩阵。 最后是 RegisterUserMatrixSender() 函数,可以记录的是用户矩阵,也能传给 GPU。该函数的 Lambda 表达式也是调用 SetSubData(),不过位置变了。 现在先探究三个较短的函数,因为它们会被另一个函数 RenderScene() 调用中: UpdateEngineUBO() 函数
由于构造函数中已经记录了模型矩阵,待会设置时需要跳过,所以这里 sizeof() 取了一个四维矩阵长度;然后 GetCamera() 获得的是相机的指针;接着,和构造函数中的操作一样,调用 SetSubData() 设置 UBO,其中依次传入的值是转置的视角矩阵、转置的投影矩阵、相机类的组件集合类对象 owner 的实体组件系统类 ECS 调用 GetWorldPosition() 获得相机在世界中的位置,这些值存的 UBO 位置就是模型矩阵之后。简单一提,这里的 std::ref 是 C++11 的引用包装器 reference_wrapper。 UpdateLights() 函数
该函数先是使用 OvAnalytics/Profiling/Profiler.h 中定义的 PROFILER_SPY,这个宏允许创造 profiler spy(笔者不知道中文该如何翻译),使用的就是给出的 name,这里是 SSBO(GLSL 着色器的缓冲对象);然后就简单了,FindLightMatrices() 获得光的矩阵信息,m_context.lightSSBO 调用 SendBlocks() 发送数据块给 OpenGL 的接口,完成 Shader 的绑定等。 UpdateLightsInFrustum() 函数
该函数和 UpdateLights() 原理一样,只是换为 FindLightMatricesInFrustum(),获取的是 Frustum(视截体)内的光矩阵信息。 了解了上面的三个函数,咱们就可以继续探究最后一个 RenderScene() 函数了: RenderScene() 函数代码比较长,咱们分段看:
首先,第一个判断里调用了函数 GetCurrentScene(),从 m_context 的变量对象 sceneManager 场景管理者获得当前的场景后继续;第二个判断将第一个判断获得的场景的指针传入 m_context 的变量对象 renderer 渲染器的函数 FindMainCamera() ,查找激活的主摄像头、返回指针并继续,没有则返回 nulllptr。 第三个判断是第二个判断获得的相机指针 mainCameraComponent 调用 HasFrustumLightCulling(),返回真假值来判断是否已经做过 Frustum Light Culling(视截体内的光的裁剪);返回 True,则调用上述的函数 UpdateLightsInFrustum() ,传入当前场景的指针、当前主相机的视截体的引用,依此来更新 SSBO 为视截体内;否则,调用上述的函数 UpdateLights() ,传入当前场景的指针设置 SSBO。 紧接着进行下列处理:
首先进行几个变量声明:m_context.window->GetSize() 获得窗口大小,记录在 winWidth、winHeight;和 UpdateEngineUBO() 里的操作一样,mainCameraComponent 分别调用 GetWorldPosition() 获得相机在世界中的位置赋值引用 cameraPosition、GetWorldRotation() 获得相机在世界中的旋转情况赋值引用 cameraRotation;mainCameraComponent 又调用 GetCamera() 获得相机指针赋值引用 camera。 接着,camera 调用 CacheMatrices() 缓存信息,包括窗口大小、相机位置与转角;然后调用上述的函数 UpdateEngineUBO 更新 UBO; 最后是 m_context.renderer 的一些操作:先调用 Clear() 函数用设置的颜色清除屏幕,其后三个真值参数的意义依次为是否清空颜色缓冲、深度缓冲、模板缓冲,其中的接口使用的是 OpenGL;然后调用 FetchGLState(),赋值变量 glState 获得 当前 OpenGL 的状态;接着第一次调用 ApplyStateMask(),传入 glState 修改并应用当前 OpenGL 状态,之后调用 RenderScene(),依次传入上述的当前场景指针 *currentScene、相机位置、相机、nullptr(参数意义是视截体)、GameRenderer 类自己的私有对象 m_emptyMaterial 来绘制场景,最后第二次调用 ApplyStateMask() 再次修改状态。 不过,如果第二个判断没通过,即没有找到激活的相机,则进行下列操作:
renderer 渲染器 SetClearColor() 设置一个颜色(这里是黑色),再 Clear(),用设置的颜色清屏,其三个真值参数的意义依次为是否清空颜色缓冲、深度缓冲、模板缓冲。简单一提,细心的读者或许已经发现,这里的 Clear() 和上一段代码里的 Clear() 确实是函数的重载,并且后者调用了前者来完成清屏工作。 总结至此,我们就大致了解了整个游戏场景的渲染器和渲染方法。其中涉及了图形学,但是对于涉足渲染的人来说都是一些简单的基础知识,就不特别讲解了,还请其它领域的读者自行搜索了解。 由于 Core 文件剩下的两部分里,Application 会包含 Game;另外,Game 还用到了同属 OvGame 模块的 Utils 文件以及 Debug 文件。所以接下来的两篇,我们将暂停对 Core 文件的探究;下一篇,先探究 Utils 的 FPSCounter 以及 Debug 的 DriverInfo。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/27 21:04:02- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |