目前已有

分类: Demo概述 | WhiteTail’s Blog (whitetail-o.github.io)

分类: 整理 | WhiteTail’s Blog (whitetail-o.github.io)

分类: Games101 | WhiteTail’s Blog (whitetail-o.github.io)

分类: Games104 | WhiteTail’s Blog (whitetail-o.github.io)(占位,待全部完成后上传)

分类: SRP | WhiteTail’s Blog (whitetail-o.github.io)

分类: Games202 | WhiteTail’s Blog (whitetail-o.github.io)

分类: 百人计划 | WhiteTail’s Blog (whitetail-o.github.io)

分类: 相机概述 | WhiteTail’s Blog (whitetail-o.github.io)

阅读全文 »

此篇为工作期间的初期工作,很多较为稀碎的优化相关的不会在此涉及,本篇只涉及部分较为通用的流程(部门之后应该会发知乎专栏,但还是在此做个备份)。不过之后或许会借此机会谈些细节的东西,比如后处理Pixel Shader和全屏Compute Shader的性能比较(还有许多相关的可以参考Nv在GDC上的论文)、函数拟合代替贴图、半影mask生成的流程(特定的工程解)。

阴影是画面表现光影的重要元素之一,高质量的阴影会对游戏画面产生不小的贡献。对于大世界来说,高质量的阴影往往意味着低走样和较远的绘制距离。Unity的URP管线中自带了最大级联数为4级的级联阴影,然而4级的级联数在阴影绘制距离较大时,近处的阴影会出现难以接受的锯齿,出现较大的走样。解决走样主要有两个方向,提高采样频率和降低信号频率。在本篇文章中,我们选择了一个较为通用的解决方案。对于前者,我们选择提高级联数,拓展4级到8级,对于后者,我们则选择在采样前进行PCF滤波。同时,也在PCF的基础上做了PCSS,以及通过PCF模拟的软阴影搭配Ramp图实现随TOD变化的阴影着色。

下图采样为8SPP(采样参考使命召唤)、搭配联合双边滤波和Temporal filter。

本篇基于Unity 2021.3.5,URP 12.1.7。

image-20240221145708412

1. 编辑器拓展

在开始对管线进行拓展之前,我们需要大致了解下URP管线的处理流程。URP首先会对UniversalRendererData、UniversalRenderPipelineAsset进行序列化。其中,UniversalRendererData会进行一些资源的加载(Shader、Texture等)和RenderFeature的配置。UniversalRenderPipelineAsset则会配置一系列UniversalRendererData,并设置一些UniversalRenderPipeline所需要的数据。UniversalRenderPipeline继承自RenderPipeline,是组织整体管线逻辑的地方,它会使用UniversalRenderPipelineAsset初始化管线。在初始化CameraData的时候,通过UniversalRendererData创建UniversalRenderer,之后在RenderSingleCamera函数中进行UniversalRenderer的设置(主要是设置一系列将被执行的Pass,如MainLightShadowCasterPass),并将对应Pass添加至管线中。最后,在UniversalRenderPipeline的Render函数中调用相关函数进行渲染。

了解完这些后,我们需要修改的内容就很明确了。首先,我们需要在UniversalRenderPipelineAsset下为8级级联添加相关的变量,并在其Editor中添加对应的UI。URP中,级联阴影相关的数据会由ShadowData的结构体进行组织,因此我们需要修改该结构体(处于UniversalRenderPipelineCore,该文件包含一些与管线相关的结构体、ShaderPropertyId、Keyword,以及一系列对管线数据做处理的函数),并在UniversalRenderPipeline通过UniversalRenderPipelineAsset对ShadowData进行初始化时,添加级联阴影相关的数据。修改完后,我们就可以在主光源阴影的Pass中获取级联阴影的相关数据。

image-20240213230640458

阅读全文 »

image-20230819184600738

补充:

a). VSM

在PCSS第三步中,想要阴影越软,查询区域就越大,频繁的贴图采样可能造成IO瓶颈。因此,通过切比雪夫不等式求得PCSS第三步PCF中当前着色点深度在周围区域中的位置(深度小于当前着色点的比例)

image-20231008151324301

b). VSSM

在求Average Block时,也应用切比雪夫不等式;

c). 切比雪夫不等式准确的条件

  • filter的平均深度大于着色点的深度(但大部分情况下不用管这个);
  • 深度大致符合正态分布,不会有过于高频的变化(如多隔断的窗户就很可能造成阴影的不准确);
阅读全文 »

a). SSR

优点: 实现简单,效果较好;

缺点:

  1. 只能反射屏幕内的物体(屏幕空间算法的通病);
    • 解决方式:SSR作为主方案,Reflection Probe作为备选项,在SSR失效的地方(如屏幕边缘)对两者做平滑过渡;
  2. 需要Ray Marching、频繁读取纹理,可能造成IO瓶颈;
  3. 被反射物只有漫反射的时候才是完全物理正确的;
  4. Ray Marching次数限制,容易出现物体断裂;
    • 解决方法: 一般会引入Thickness来防止物体出现断裂,即ray marching的点除了深度需要大于深度图的深度值,还需要步进的步数小于Thickness;

优化:

  1. Hierarchical Z;
  2. Dither;
  3. 下采样;

b). Stochastic SSR

针对情况: Gloosy物体(对于普通SSR来说,只可通过roughness对反射图进行blur)

阅读全文 »

OIT(Order Independent Transparency)

a). Depth Peeling(深度剥离)

image-20230817143032060

  • 优点:
    • 遍历都是无序的,也就是说不依赖对物体的排序,所以也就不会出现半透明排序的问题;
    • 基本无硬件要求
  • 缺点:
    • 需要重复多次Pass进行深度剥离,性能开销大;

b). Per-Pixel Linked Lists(L.L)

v2-90dde925b1db37ccedb64859560a1ea1_b

在 Pixel Shader 中使用两个可写的纹理(DX11,SM 5.0,UAV),一个屏幕大小的链表头纹理(Start Offset buffer),一个屏幕大小 N 倍的链表节点纹理( Fragment & Link buffer)。链表头纹理的每个像素存储每个像素链表在节点纹理中的偏移量。

v2-fd030b2ba60255a3d750c02fc4c272cb_b

  • 优点:
    • 比 Depth Peeling 快了很多。性能开销也比 Depth Peeling 更加节省
  • 缺点:
    • 节点纹理具体需要多大无法事先做准确的预估,因此显存的具体消耗不可控(因此多用于离线渲染)
    • 仅支持DX11、SM5.0以上;
阅读全文 »

0). 前言

最近实际做项目的时候发现对自身知识体系做整理的重要性,因此之后会慢慢做一些总结和思维导图,比如剔除、GI(GI方案、反射、AO等)、阴影等。本篇就以剔除开始;

a). 粗粒度剔除(CPU为主)

包括视锥剔除和遮挡剔除,为物体层面。

  • 发生阶段:CPU应用阶段

a.1). 视锥剔除

CPU阶段,物体的AABB包围盒与视锥体6个面分别作判断,剔除包围盒完全处于视锥体外的物体;

a.2). 遮挡剔除

a.2.1). 基于Occlusion Query

在深度测试时得到待剔除物体相关数据,在应用程序阶段执行。

  • Occlusion Query: 在绘制命令执行前向GPU插入一条查询,在绘制结束后的某个时刻,从GPU将查询结果回读到内存中,得到某次DrawCall中通过Depth Test的Sample数量
  • 基础做法:
    1. Depth-Only的Pass将场景整体绘制一遍,将物体(的包围盒)深度写入Z-Buffer中;
    2. 使用物体的包围盒传入GPU进行Occlusion Query。如query得到的sample数大于0,则表示该物体(部分)可见,剔除掉Sample等于0的物体
    3. 执行正常的渲染流程;
  • 缺点:
    1. 对于复杂场景,Depth-Only也有较大的开销;
    2. 需要将查询结果读回内存(VRAM -> System RAM),需要走PCI-E(IMR架构);
      • 常见的解决方法:回读上一帧Occlusion Query的结果,但可能导致一定的错误(但之后深度测试也可保证画面正确,因此此处出错只是增加了一部分渲染开销);

a.2.2). 基于Software Rasterization(软件剔除)

最早由Frostbite提出,用于战地3的剔除方案。

  • CPU构造一个低分辨率的Z-Buffer,在其中绘制一些场景中较大的遮挡物(美术设定的一些大物体+地形);
  • 在构造好的Z-Buffer上,绘制小物体的包围盒,执行类似Occlusion Query的操作进行剔除;

image-20230814111511843

阅读全文 »

a). 引擎架构分层简介

  • Tool Layer
    • 打开一个游戏引擎会直接看到各种类型的编辑器。这个直接和开发者进行交互的层称为工具层(tool layer)
  • Function Layer
    • 在工具层下面包含功能层(function layer),用来实现游戏的渲染、动画、交互等不同类型的功能;
  • Resource Layer
    • 在此基础上还需要资源层(resource layer)来管理各种各样的场景美术资源;
  • Core Layer
    • 再下一层是核心层(core layer),它包括支持游戏渲染、动画、物理系统、内存管理等不同系统的核心代码;
  • Platform Layer
    • 最底层是平台层(platform layer),一般包括各种图形API、输入设备支持以及不同游戏平台的底层代码;

Total_Layer

阅读全文 »

之前刚想写一篇DX12和OpenGL在Unity Shader中的差异,没想到官网就写了……

附上链接:为不同的图形 API 编写着色器 - Unity 手册 (unity3d.com)

以下正文


在某些情况下,不同图形 API 之间的图形渲染行为方式存在差异。大多数情况下,Unity 编辑器会隐藏这些差异,但在某些情况下,编辑器无法为您执行此操作。下面列出了这些情况以及发生这些情况时需要采取的操作。

渲染纹理坐标

垂直纹理坐标约定在两种类型的平台之间有所不同,分别是 Direct3D 类和 OpenGL 类平台。

  • Direct3D 类:顶部坐标为 0 并向下增加。此类型适用于 Direct3D、Metal 和游戏主机。
  • OpenGL 类:底部坐标为 0 并向上增加。此类适用于 OpenGL 和 OpenGL ES。

除了渲染到渲染纹理的情况下,这种差异不会对您的项目产生任何影响。在 Direct3D 类平台上渲染到纹理时,Unity 会在内部上下翻转渲染。这样就会使坐标约定在平台之间匹配,并以 OpenGL 类平台约定作为标准。

在着色器中,有两种常见情况需要您采取操作确保不同的坐标约定不会在项目中产生问题,这两种情况就是图像效果和 UV 空间中的渲染。

阅读全文 »

阴影PCSS

PCSS

Precomputed Radiance Transfer,PRT

prt

prt2

屏幕空间反射

SSR

Kulla-Conty Approximation

Kulla

TAA

un

1

a). Anti-Aliasing

a.1). Temporal Anti-Aliasing (TAA)

  • 复用先前帧的样本,假设画面不动,就可在单个像素内随时间规律移动感知点,进行(加权)平均;
    • 为何规律移动感知点: 随机采样会引入高频噪声;
  • 如画面移动,则和频域降噪相同,使用Motion vector找到对应像素,再规律移动感知点。同时也可引入Clamp和Detection的操作;

TAA01

TAA02

a.2). MSAA vs. SSAA

SSAA:

  • 相当于用更大分辨率渲染后降采样,做2倍的SSAA,相当于一个像素做4次shading;
  • 质量最好,但是性能开销大;

MSAA:

  • 在一个像素内,同一个图元只着色一次;(如图,0、2、3为图元A,着色一次(左边的绿点);1为图元B,着色一次;)

    • 因此,MSAA会维护一张表,表中记录当前感知点记录的color(albedo?) 和 深度

    MSAA01

  • 在像素间复用样本;

    MSAA02

a.3). Image Based Anti-Aliasing Solution

ImageBasedAA

a.4). Note

  • G-buffers一定不能做抗锯齿
阅读全文 »