跳转至

项目0 -- DDGI全局光照

1.优点

  • 适应动态变化
  • 基于硬件光线追踪
  • 全局的漫反射

2. 缺点

  • 硬件光追,设备限制
  • 低频,无细节

3.如何抑制漏光?

  • 深度缓冲纹理判断遮挡
  • 全方位光线追踪
  • 时空滤波(抑制瞬时漏光,降低权重)
  • 探针布局优化,根据场景复杂度增加探针(尤其是密度较大,模型较细的地方,但是麻烦)

4. 优化

  • 固定光线:只存距离
    • 分类
    • 重定位
  • 收敛性判断
  • 探针剔除
  • 分层实现
  • 光照收敛判断

细节

1.采样

  • 世界坐标、法线、光线方向
  • 计算阴影的偏移bias
  • 判断着色点位置(边缘平滑)
  • 先找最近的探针,计算出alpha
  • 拿八个探针
    • 判断活跃(分类、重定位)
    • 三线性插值
    • 方向权重(和法线作比较),法线方的权重较大
    • 切比雪夫测试(比距离小必不遮挡了)
  • 加权平均

2.光线追踪

  • Raybuufer纹理
  • 非活跃判断
  • 从探针开始光线追踪
    • 出局情况:
      • miss
      • 背面
      • 固定光线()
  • 拿到交点信息,递归进行阴影计算
    • 遍历平行光和点光源
  • 存到raybuffer中

3.纹理计算

  • 八面体纹理映射,边界处理
  • 斐波那契卷积raybuffers,注意排除固定光线
  • 后处理
    • 滞后值,时域处理
      • rgb检测光照差异,差异大减权重
    • 变异性(暂时没用)
    • tonemapping
  • 更新距离
    • 一样的方式,多存一个平方
    • 后处理
      • 时域插值,避免阴影大幅度跳动,伪影
  • classification:
    • 固定光线(但是距离最大只有1.5f)
      • 判断背面卡墙阈值
      • 拿到最近三个平面,探测有效几何
  • relocation重定位
    • 根据distance,拿固定光线
    • 设置最近背面、最近正面、最远正面距离
    • 三种情况,不同处理方式

项目1--引擎

做这个游戏引擎的目的就是想更加深入的了解游戏开发的底层原理,实现一通百通。

这个引擎是一个模块化的C++游戏引擎,主要分为引用库、引擎层和编辑器层三大部分。


​首先,引擎的架构设计体现了分层与解耦的思想。​​ 引擎层采用“核心-渲染-场景”的三层结构:

  1. ​核心层​​通过LayerStack层级管理系统实现了层级动态调度。例如,我们将场景渲染层和编辑器UI层分别注册为普通层与覆盖层,确保编辑器界面始终渲染在顶层。事件处理则采用反向迭代机制,当点击编辑器按钮时,事件会优先被覆盖层拦截,避免穿透到游戏场景。

    - 每个Layer基类会提供了生命周期的方法模版(如加入、删除、imgui的Update,渲染的Update,还可以指定时间步,以及事件处理),具体的实现交给子类用继承的方式去实现。

  2. ​渲染层​​抽象出RenderAPI接口,目前基于OpenGL实现。我们在GLContext类中封装了GLFW窗口创建与Glad函数加载,并通过Shader类实现SPIR-V着色器的跨平台编译——即将shader转换为SPIR-V的二级制数据,再用SPIRV-Cross转译成OpenGL的GLSL 430版本,既保持现代着色器语法,又兼容旧版渲染API。渲染API和平台目前也是通过策略模式进行切换,每个API提供了一些通用的渲染Command指令交由子类具体实现。不过这里目前倒还是个饼,因为目前引擎还没有去做其他平台和Vulkan,DX的支持。

  3. ​场景层​​实现ECS架构管理组件,实体组件的序列化类似于Unity,通过yaml-cpp完成。比如当保存场景时,Transform组件会序列化为Position: [1.0, 2.0, 3.0]的YAML节点,反序列化时也是通过读取yaml重新组装场景结构(序列化时,具体的细节只会记录脏数据)。

    1. 个人认为一般平时手写的渲染器基本上只注重效果展现,而游戏引擎的目的就是提供可交互的功能方便玩家制作游戏,因此也实现了通过按键交互。只要点击场景中的物体或者编辑器物体目录下的物体,就可以通过的gizmosGUI去调整物体的大小方位旋转了。同时资源检视器的GUI面板也会显示它对应的组件如Transform,SpriteRednerer等。
    2. 在资源检视器的UI面板下也可以调整对应的组件数据,实现修改场景中物体的逻辑。

也许会被问到的问题: - 通用的Components: - Transform:只存储平移、旋转、缩放的三个Vec向量。提供了一个四维矩阵的获取方法,则是先平移再旋转(旋转则是直接用四元数),最后缩放。 - SpriteRenderer则基本上只存储RGBA颜色,方形+纹理和大小。 - 如何实现点击屏幕进行场景交互的? - 首先是输入响应:GLFW捕获鼠标事件 → Window数据封装为MouseButtonEvent → LayerStack反向遍历处理。 - 检测到事件后,我们通过IMGUI拿到鼠标在窗口的位置,然后就去读取帧缓冲。所有物体的着色器都会单独一个帧缓冲的Red通道都会去记录每个像素点上的实体ID。通过鼠标位置,读取帧缓冲对应的位置上的值,就可以拿到对应的实体ID。 - 将此实体ID设置为当前select的上下文,就可以拿到对应的组件进行操作了。(具体检索逻辑倒是不太清楚,毕竟用的是封装的entt)。 - Input交互:每帧轮询,检测是否按下,多按键采用或运算检测。