IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 虚幻4场景渲染源码分析概述 -> 正文阅读

[游戏开发]虚幻4场景渲染源码分析概述

大学时候跟舍友两个人搞的,可能也没啥用,先存在这吧,基本就是对官网的一个翻译。

  1. ?主要类关系

主要类关系图:

?

说明:FSceneRenderer类包含了FScene类、FMeshElementCollector类、FViewInfo类和FSceneViewFamily类的实例,分别表示被渲染的场景、封装了来自不同FPrimitiveSceneProxy类的网格集合、存放多种场景信息的对象和被渲染的视图族。FDeferredShadingSceneRenderer是延迟渲染,FForwardShadingSceneRenderer是前置渲染,两者皆继承自FSceneRenderer类。

2.??延迟渲染介绍:

UE4的渲染引擎多采用延迟渲染(Deferred Rendering)。所谓延迟渲染,是指将一个场景的几何体(3D模型、多边形)的光照、阴影、质感搁置到一旁,先着手于绘画,然后在后半段再对光照、阴影、质感进行处理的处理方式。即给人一种把原本的多边形先绘制出来的印象,实际上不仅要绘制多边形,前者的参数还需要配合后面光照和阴影的处理。其输出目标,在成为复数缓冲时具有普遍性,这里的缓冲我们称之为“物理缓冲”。延迟渲染有两个优点。第一个优点就是能将十分复杂的光照、阴影以每次一像素的方式进行处理。第二个优点是并不明确限定用于光照的动态光源数,所以可以进行丰富的光照渲染。为了全力回避像素着色器处理像素的编写和撤销导致的耗时严重、性能下降而开发出的就是延迟渲染。

3.??render函数内渲染pass流程

Render函数是渲染主函数,在FSceneRenderer类中声明,在FDeferredShadingSceneRenderer类中重写。Render函数内多轮pass的流程图如下:

?

  1. ?剔除

render函数首先调用了FdeferredShadingSceneRenderer类中的InitViews函数,InitViews函数调用了FsceneRenderer类中的ComputeViewVIsibility计算视图可见性,包括视锥体裁剪、遮挡剔除等,裁剪后的几何体可见性存于FviewInfo对象中,供后面渲染使用。

在计算视图可见性中,利用了PrimitiveVisibilityMap——从片元ID到可见性布尔值的一个map数据结构。在做完视锥体裁剪和遮挡剔除后,都更新了这个数据结构。这个数据结构存储的数据在后序渲染中使用,减少了不必要片元的渲染,提高了渲染效率。

.2.?多轮渲染pass概述

pass是在GPU上执行的一组绘制调用(确保读取它们是什么)。它们通过管道中的功能组合在一起,如渲染透明网格或进行后期处理。这个组织是为了方便起见并确保正确的执行顺序 —— 因为一些pass可能需要特定先前传递的输出。大多数pass的输出看起来很陌生。深度计算或阴影投影看起来不像熟悉的纹理场景。实际上,只有base pass和半透明使用在编辑器中设置的完整材料。大多数其他pass执行任务与base pass和半透明pass不同,他们使用他们自己的专用着色器。

在每一轮pass结束后,pass的结果输出到渲染缓冲队列中。经过多轮pass后,渲染结果能更加接近真实。

2.1?PrePass

调用了FdeferredShadingSceneRenderer类中RenderPrePass函数。负责从非半透明网格中提前渲染深度(Z)。用FDepthDrawingPolicy策略进行绘制,只绘制depth到Depth-Buffer,这个有利于减少后面的Base pass中的pixel填充,节省pixel-shader的执行。 效率受不透明网格的三角网格数影响和Early Z设置——三角形数和蒙面材料的复杂性的影响。PrePass的 结果可能在之后的DBuffer纹理贴图和遮挡裁剪中使用。

???????2.2?ComputeLightGrid

调用了FdeferredShadingSceneRenderer类中的ComputeLightGrid函数,将灯光分配给空间中的网格单元Grid。Grid小:影响每个grid的灯光少。Grid大:光分配和阴影的效率高。切分方案:视图空间中的指数间距。好处:grid在投影下观察时不至于许多是像素大小的视图,使得性能变差。ComputeLightGrid操作具有自己的成本,但之后能更快地确定哪些灯影响哪个网格。

???????2.3?RenderOcclusion

调用了FdeferredShadingSceneRenderer类中的RenderOcclusion函数进行occlusion pass的渲染。与之前的剔除不同的是,这里的遮挡裁剪是像素点级别的,而之前的剔除(包括视锥体裁剪、遮挡剔除等)是片元级别的。

其中,调用了父类FSceneRenderer类中的BeginOcclusionTests函数进行遮挡查询。遮挡查询(默认使用硬件遮挡查询)occluder的所有内容渲染到一个深度缓冲区后,创建一个遮挡查询(使用z-test和前面创建的深度缓冲区),CPU读回查询返回通过z-test的像素数后判断是否提交渲染这个物体。

这样的遮挡查询有两个缺点和问题——一帧内多次调用drawcall(CPU发送至GPU),

CPU和GPU的同步问题。

解决方法:对于CPU和GPU的同步问题,可以CPU推迟读取多个帧的查询数据进行解决。

对于多次调用drawcall问题,可以将查询分组(分为可见组和不可见组),可不可见由先前帧的查询数据决定。可见则标记为下一帧可渲染且单个查询(Individual Queries),不可见则使用分组查询(Grouped Queries)确认下一帧的可见性,分组查询可以批量查询最多八个物体的边界框,如果作为一个整体可见则再分解单个查询。好处:如果摄像机和物体是静态或者缓慢移动,分组查询可将必要的遮挡查询数量减少至1/8。

为了完善occlusion pass,需要进行ShadowFrustumQueries。为局部灯光(点光源或聚光灯)的球形边界网格发出硬件遮挡查询。如果被遮挡则没有必要为他们进行照明或阴影计算。对于会计算每个物体阴影的静态动态灯光,会用截头椎体作边界网格。

PlanarReflectionQueries:计算平面反射时执行的遮挡测试。

???????2.4?HZB

通过调用FdeferredShadingSceneRenderer类中的RenderHzb函数生成Hierarchical Z-Buffer。并创建Mip链(连续地对其下采样)。HZB的渲染效率取决于渲染分辨率。HZB用于遮挡剔除方法并通过屏幕空间技术用于环境遮挡和反射。

???????2.5?RenderShadowDepthMaps

ShadowDepths pass生成阴影投射灯光的深度maps。这就像从每个灯光的角度渲染场景的深度,结果是阴影深度图。引擎从摄像机的角度计算每个像素到光源的距离——但仍然在光的坐标空间中。通过将此值与深度图进行比较,在ShadowProjection过程中,可以测试像素是被给定光照亮还是在阴影中。

它的成本主要受阴影投射灯的数量和范围的影响。同样重要的是可移动阴影投射物体的数量和三角形数量。

根据组合,可以使用静态网格物体和静态光源 ——然后成本为零,因为静态光源只是纹理:它们是预先计算的。但是,您也可以使用固定或可移动的灯光以及其范围内的静态或可移动物体。这两种组合在一起时,需要引擎分别针对每个光源从这些网格中生成阴影。每个光源生成一个立方体阴影贴图,使用几何着色器来选择渲染哪个面(可以减少drawcall)。因为可移动光源不一定会移动,所以对于静态物体使用阴影贴图缓存,只渲染可移动物体。

优化:

阴影通常是渲染中最重要的部分之一。控制其性能的最简单的方法是为每个不需要的光源禁用阴影。很多时候你会发现你可以在没有玩家注意的情况下不使用阴影,特别是对于那些远离玩家运动区域的光源。这是一个很好的解决方法,因为在一大组灯光中只用单个光启用阴影投影。

对于要渲染阴影的灯光,最大的影响效率的因素是必须渲染到阴影深度图的多边形数量。光源的衰减半径设置是渲染范围的硬限制。比如说需要绘制阴影的聚光灯比点光源渲染阴影效率高,因为聚光灯的体积是锥形,而不是完整的球形。它们的外锥角越小,渲染速度越好,因为可能更少的物体会落入这盏灯的光照体积。

在渲染阴影时,定向光具有多分辨率方法,称为级联阴影贴图(CSM)。这是必要的,因为定向光(通常是太阳光)需要覆盖巨大的区域。基本的Shadow mapping在大场景下存在阴影图精度问题:主相机整个视锥生成一张阴影图,会导致单个物体占用阴影图的比例太小,读取阴影图时出现采样精度不够(多个像素采样一个图素),产生锯齿。使用尺寸更大的阴影图可以改善这个问题,但会导致内存使用增加。相机近端和远端物体对阴影图采样精度一样,会导致近端物体采样精度不够,远端物体采样精度浪费。所以大场景方向光动态阴影的解决方案一般是采用CSM技术。CSM通过把相机的视锥体按远近划分为几个级别,处于各个级别下的物体深度信息绘制到各级阴影图中,显示时采样各自对应的阴影图。

CopyCachedShadowMap pass:

由于可移动光源不一定会移动,所以ShadowDepths pass用的立方体阴影贴图可以拷贝过来使用,然后再在顶部渲染动态物体的阴影贴图。如果可移动光源移动了,会每帧渲染所有静态几何体的立方体阴影贴图,然后将动态物体的阴影贴图添加上去。

?ShadowProjection:

阴影投影是阴影的最终渲染。此过程读取深度图并将其与场景进行比较,以检测哪些

区域位于阴影中。

???????2.6?ComputeVolumetricFog

通过调用FdeferredShadingSceneRenderer类中的ComputeVolumetricFog函数计算体积雾(使用compute shader)。仅使用表面位置计算并存储体积纹理中的透射率和光散射。也按指数分了slices。

???????2.7?Base Pass

通过调用FdeferredShadingSceneRenderer类中的RenderBasePass函数负责将不透明或Masked材质的最终属性渲染到GBuffer;读取静态照明并将其保存到GBuffer;应用Dbuffer纹理;应用雾;计算最终速度。Gbuffer之后会被其他pass使用。

Base pass从光照贴图,间接照明缓存中读取静态光照,并通过立即与材质的颜色混合来应用它。Base pass也应用Dbuffer纹理。视图中的纹理被投影到对象上,运行着色器并将结果与G缓冲区的内容混合。在这个过程中,雾也混合在一起。

GBuffer内容有:SceneColorDeferred、GBufferA世界空间法线、Distortion各种材料属性、GBufferC:RGB中的反照率(反照辐射量/入射辐射量)和Alpha中的AO、GBufferE基于着色模型的自定义数据、GBufferD预烘焙阴影因子、Stencil模块缓冲区,以标记属于它渲染的实体几何体的像素。

???????2.8?RenderVelocities

通过调用FdeferredShadingSceneRenderer类中的RenderVelocities函数,负责保存每个顶点的速度(稍后用于运动模糊和时间抗锯齿)。

???????2.9?Lighting Pass

之前所说的ComputeLightGrid属于直接光照,而在这里讨论的是间接光照。

首先进行PreLighting Pass。包括屏幕空间环境遮挡(SSAO)和非DBuffer类型的纹理贴图。空间环境遮挡是一种近似于遮挡引起的光衰减的效应。除了标准的全局照明之外,这通常最好用作微妙的效果,使角落,裂缝或其他特征变暗,以创造更自然,逼真的外观。PreLighting从G-Buffer和分层Z-Buffer(HZB)获取有关场景的信息。 多亏了这一点,它可以在屏幕空间中执行所有计算,从而无需查询任何3D几何体。

CompositionAfterLighting pass,包括Subsurface scattering(SSS)of Subsurface Profile type次表面轮廓型的次表面散射(SSS)。这种SSS使用单独的缓冲区来计算对象的厚度。它具有实时近似几何厚度的成本,然后在着色器中使用该缓冲区。

Image Space Lighting 图像空间光照:分为两部分:屏幕空间反射和环境反射。首先全屏计算屏幕空间反射:使用Hi-Z Buffer(通过在射线追踪期间根据表面粗糙度选择Hi-Z mip来加速交叉点的计算,因为对于较粗糙的表面来说反射的细节更难以看见)。这里着色器在射线追踪期间确定击中时,使用的颜色是前一帧的渲染颜色。最后,每一帧的光线开始位置都被抖动——为了与时间抗锯齿相结合,增加反射图像的质量。(屏幕空间反射应用于主渲染目标,使用计算着色器)。环境反射:在游戏启动期间会生成两个反射探头,使用的也是计算着色器,用于捕获环境反射(仅捕获静态几何体),并存储在每个探针的mipmapped立方体贴图中。

???????2.10?RenderAtmosphere

通过调用FdeferredShadingSceneRenderer类中的RenderAtmosphere函数渲染大气。

???????2.11?RenderFog

通过调用FdeferredShadingSceneRenderer类中RenderFog函数渲染指数高度雾(Exponential Height Fog)类型的雾。为了控制体积雾(前面所说的),可以调整指数高度雾的属性和每一个光。指数高度分布为体积雾提供了一个全局密度。

???????2.12?Translucency and its lighting

通过调用FdeferredShadingSceneRenderer类中的RenderTranslucency函数进行透明

度渲染。先渲染物体:使用预先计算的大气模拟纹理、烘焙光照贴图数据、半透明照明体积(包含来自定向光、局部光源以及反射探头立方体贴图的光照),并使用它们计算光照。使用Surface ForwardShading的材质照明。

Translucency lighting:创建用于简化半透明网格照明的全局体积纹理。半透明物体的照明不是直接计算的。相反,从相机的视角计算金字塔形网格。这样做是为了加快渲染点

的半透明度。这种缓存利用了半透明材料通常用于粒子、体积效应的假设——因此不需要

精确的照明。实际上,与不透明材料相比,透明物体的光照渲染更加简化了。通过使用更

昂贵的着色模式Surface ForwardShading,可以避免体积缓存。

???????2.13?ParticleSimulation,ParticleInjection

粒子模拟和粒子喷射:GPU上的粒子模拟(仅限GPU sprites粒子类型)。如果你在粒子发射器中启用了GPU精灵,那么他们的物理模拟就在这里完成了。成本取决于这种发射器产生的粒子数量。启用碰撞模块会增加模拟的复杂性。GPU精灵与场景其他部分的碰撞是根据屏幕空间数据(例如Z-depth)进行测试的。这使得它比传统的基于CPU的粒子与实际3D网格的碰撞更快。它将成本转移到了GPU上。必须模拟的粒子数量越多(尤其是碰撞),成本就越高。可以使用LOD(level of detail)来限制生成的粒子数。

???????2.14?PostProcessing pass

最后进行后处理渲染,包括Depth of Field景深效果(BokehDOFRecombine)、时间抗

锯齿、读速度值、运动模糊、色调映射、自动曝光、从渲染分辨率升级到显示分辨率等。

运动模糊基于运动模糊对象的运动。该系统通过全屏速度图(full screen velocity map)工作,该全屏速度图以较低的分辨率创建,对象根据对该图的数据信息而模糊。

景深效果(DOF)是模拟摄像机镜头对焦特性的一种常见的后处理效果。在现实生活中,相机只能对特定距离内的物体进行锐利的聚焦;离相机较近或较远的物体会有些失焦。模糊不仅提供了一个关于物体距离的视觉提示,还引入了焦外成像(Bokeh), Bokeh是一个术语,用来描述当物体失去焦点时,在图像明亮区域周围出现的令人愉悦的视觉效果。

在虚幻引擎4中,有几种方法可以执行景深效果。它们分为两类:

电影:这些方法提供了电影和电影的景深效果。这些方法的调整也更符合摄影和电影摄影中常用的相机选项。这些方法对于移动平台来说也被认为花销昂贵,但是对于桌面和控制台平台来说效果很好。

移动:这种方法提供了优化和低成本的DOF选项,对移动平台来说是可接受的。

实现:景深被分解成三层(或区域);近、远和焦区。每一个单独处理,然后组合在一起以获得最终的图像效果。近处和远方的物体总是完全模糊。它们与非模糊场景混合,以获得最终结果。

时间抗锯齿主要是为了修复场景帧率小于运动物体运动速度的锯齿问题,当帧率太低时候,运动的物体就会卡顿,为了避免这种造成的锯齿,原理上帧率刷新速度应该大于两倍运动速度才行。

抗锯齿(AA)是指在计算机显示器上显示时锯齿状或锯齿状线条的平滑。虚幻引擎4中的抗锯齿是在进行后处理中使用FXAA执行的,FXAA是一种高效的GPU MLAA实现。 此方法解决了锯齿伪像的大多数原因,但无法完全防止时间锯齿。可以通过show flag

Post-process Anti-aliasing禁用该功能。

参考文献:

https://docs.unrealengine.com/en-us/虚幻4官方文档

https://unrealartoptimization.github.io/book/profiling/passes/ 虚幻渲染Pass

景深效果(Depth of Field)_逍遥剑客-CSDN博客景深效果

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-10-03 17:21:42  更:2021-10-03 17:23:16 
 
开发: 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/28 2:34:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码