BlueRoseNote/02-Note/演讲与教程笔记/虚幻开放日2024/虚幻引擎4移动端渲染管线改造总结分享.md

212 lines
9.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 移动端SSR
## GBuffer
- SSR计算阶段需要的WorldNormal来自GBufferA,Roughness来自GBufferB
- SSR结果转换成间接高光需要的SpecularColor来自GBufferB和GbufferC
```c++
derived from BaseColor,Metalness,Specular
GBuffer.SpecularColor = ComputeF0(GBuffer.Specular,GBuffer.BaseColor,GBuffer.Metallic);
```
MobileBasePass片段着色器额外增加一张RT--OutColorAux,rgb通道存SpecularColor,a通道存Roughness
```c++
PIXELSHADER_EARLYDEPTHSTENCIL
void Main(
FVertexFactory InterpolantsVSTOPS Interpolants
, FMobileBasePassInterpolantsVSTOPS BasePassInterpolantts
, in float4 SvPosition:SV_Position
OPTIONAL_IsFrontFace
, out half4 OutColor : SV_Target0
, out half4 OutColorAux : SV_Target1
#if DEFERRED_SHADING_PATH
```
```c++
OutColorAux.rgb=ShadingModelContext.Specularcolor;
OutColorAux.a=GBuffer.Roughness;
```
- 其中SpecularColor初始化值为计算得到的间接高光(延迟管线是在混合阶段计算)
```c++
ShadingModelContext.SpecularColor = (DielectricSpecular -)
ShadingModelContext.SpecularColor = GetEnvBRDF(ShadingMode
```
## TemporalAAHistory
- TemporalAA多帧累积的SceneColor,用于射线RayCast交点的屏幕坐标采样获取颜色
- 降噪作用(SSR默认Quality每个像素打一根Ray)
- 移植DesktopTAA替换MobileTAA(详细见图像处)
## HZBFurthest
- 可以理解为场景深度的Mipmap用于RayMarching求交加速。
- 参考UE4.27移植(不是必须)
## SSR计算
- SpecularColor和Roughness从OutColorAux获取,WorldNormal通过SceneDepth重构获得
```c++
#if SHADING_PATH_DEFERRED
FGBufferData GBuffer = GetGBufferDataFromSceneTextures(UV
#else
FGBufferData GBuffer = (FGBufferData)0;
GBuffer.ShadingModelID
= SHADINGMODELID_DEFAULT_LIT;
GBuffer.WorldNormal = normalize(ReconstructNorma1FromDept
GBuffer.SpecularColor = MobileSceneColorAux.SampleLevel(
GBuffer.Roughness = MobileSceneColorAux.SampleLevel(Mobil
GBuffer.Depth = CalcSceneDepthByTexture(UV);
#endif
```
- SSR结果预乘SpecularColor,这样可以与SceneColorMobile做Blend One One混合
```c++
#if FEATURE_LEVEL == FEATURE_LEVEL_ES3_1
Outcolor.rgb*=GBuffer.SpecularColor;
#endif
```
## 结论
- 不足:重建的WorldNormal是面法线,没有延迟管线GBuffer的像素级法线,某些角度反射结果会有差异
- 早期的方案:OutColorAux的rg通道存WorldNormal,a通道存Roughness,b通道存SpecularColor的灰度值(某些光照环境下结果不准确,放弃)
# 实时平面反射
平面反射与DepthPass的兼容问题修改。
## 需求
在包含平面反射(裁剪平面开启)的场景中,开启Full Prepass的情况下,平面反射绘制的内容出现深度遮挡错误
**裁剪平面**
平面反射的裁剪平面(Global Clip Plane)用于保证绘制结果的正确--那些在反射相机的视锥体内,但在反射平面下方的物体不应该参与反射,需要被剔除掉
**硬件实现**
默认实现是通过SV_ClipDistance语义在模型的光栅化阶段剔除,但不是所有的平台都支持,移动平台BasePass走的是PS的clip剔除
## 实现方法
1. 自定义语义
DepthOnlyVS设置ClipDistance值,通过自定义语义插值传递给片段着色器DepthOnlyPS。
```c++
struct FDepthonlyVSTOPS
{
#if USE_PS_CLIP_PLANE
float OutclipDistance : OUTCLIPDIST;
#endif
```
2. PS剔除
在DepthOnlyPS中用clip函数剔除(负值表示在裁剪平面以下,会被剔除)
```c++
#if USE_PS_CLIP_PLANE
clip(Interpolants.OutClipDistance);
#endif
```
3. PS绑定条件
在移动平台,当场景包含平面反射的情况下走DepthOnlyPS
## 结论
- Depth Pass走PS会有额外开销,但仅限场景中包含平面反射的时候,其它情况下Depth Pass仍然可以不需要PS
- 另一种修改方案:当场景中包含平面反射的时候关闭Full Prepass,在某些效果依赖Full Prepass的时候不行(详细见接下来动态阴影分享)
# CSM策略优化
- 移除视锥外物体的阴影渲染
# ModulatedShadow渲染管线改造
## 需求
- 在角色展示时CSM阴影精度不够,阴影效果不稳定(ViewDependentWholeScene的阴影方式)
- 解决方案:Modulated Shadow具有独立的阴影视锥和阴影深度图区域,在阴影精度方面更有优势(Per-Object的阴影方式)
## 问题1:阴影重叠
- Modulated Shadow独立计算各个投影物体的阴影,与SceneColorMobile相乘输出,导致投影重叠区域多次与阴影颜色相乘被压黑
- 解决方案:增加一个中间RenderTarget,做为每个Per-Object阴影视锥的输出目标,最后对RT统一阴影颜色处理后,再与SceneColorMobile相乘输出
## 问题2:透明物体无阴影接收
- 阴影方式处理依赖场景深度,而透明物体不写场景深度
- 解决方案:透明物体的阴影Receive还是走CSM
## 问题3:在MobileBasePass之后计算
- 阴影信息需要早于MobileBassPass构造好,用于着色计算
- 考虑过的方案:MobileBassPass用上一帧的Modulated Shadow信息,但存在阴影拖影和透明物体阴影结合的问题
- 最终方案:参考UE4.27移植并开启Full Prepass,在MobileBassPass之前获得场景深度,构造好Modulated Shadow
## 结论
项目应用两套阴影方案:角色展示场景主要用Modulated Shadow,满足高精度的阴影效果需求,战斗场景用CSM,效率优先
# 特效性能 Separate Translucency透明渲染管线改进
修改方案:参考非移动端做透明渲染RenderPass与MobileBasePass分离。
1. SeparateTranslucencyColor
申请低分辨率的RenderTarget用于透明绘制,然后Upsample到SceneColorMobile上
2. SeparateTranslucencyDepth
SceneDepth需要跟SeparateTranslucencyColor做同比例Downsample
注意:SceneDepth的Resolve跨RenderPass渲染目标改变,基于Memoryless的SceneDepth获取方式需要改为从Texture中获取,比如:DepthFade,LookupDeviceZ
3. 重设SceneTextures
增加EMobileSceneTextureSetupMode去设置降分辨率后的SceneDepthTexture
```c++
(buseSeparateTranslucencyDepth && SceneContext.SeparaateTranslucencyDepth)
SceneTextureParameters.SceneDepthTexture=GetRDG(SceneContext.Separate
```
## 进一步需求
- 角色的透明材质不想受降透明分辨率影响
1.保证角色渲染的精度;2.透明和不透明的衔接部分因为精度不一样出现裂缝问题
## 解决方案
- 通过扩展材质上的SeparateTranslucency的勾选项灵活控制走Normal还是SeparateTranslucencyPass
## 与其他透明的乱序问题
- 通过角色透明写CustomeDepth,其他透明判断CustomDepth解决
## 结论
- 通过透明渲染分辨率可根据机型、画质和场景的不同灵活控制特效的GPU开销
- 透明渲染Pass拆分产生了更多的透明渲染乱序问题,通过设置Sort Priority,配合CustomDepth解决
- SceneCapture下的透明渲染:还是走Normal Translucency (SceneCapture需要使用alpha通道)
# 图像处理 Desktop Temporal AA移动端移植
## 需求
- MSAA对Depth Resolve支持的不好,无法满足渲染管线特性扩展的需求(SSPR、AO和Full Prepass等都需要Depth的Resolve)
- TemporalAA通过每帧使用不同的像素抖动Jitter,把采样结果分散到多帧,累积到History帧与当前帧混合,可以达到很好的抗锯效果
- MobileTAA只做两帧混合,抗锯效果不够,而且没有基于Velocity的像素修正,快速移动会有鬼影(Ghosting)
## 解决方案
**增加Velocity Pass**
- 可移动模型:更新Primitive的LocalToWorld和PreviousLocalToWorld
- 骨骼模型:需要上一帧的骨骼矩阵计算顶点位置,使用SRV Buffer代替Uniform Buffer传递骨骼变换矩阵(UniformBuffer有大小上限)
- VS计算出顶点当前和上一帧的屏幕空间坐标,传递给PS计算差值作为Velocity输出
```c++
// 3d velocity,includes camera an object motion
float3 Velocity = float3(ScreenPos - PrevScreenPos, DeeviceZ - PrevDeviceZ);
```
**Reprojection位置纠正**
- 在后期阶段,通过变换计算当前屏幕坐标在上一帧中的屏幕坐标,再结合Velocity数据对History帧做正确采样
```c++
float2 BackN = PosN.xy - PrevScreen;
BackN = DecodeVelocityFromTexture(EncodedVeloc:ty).xy;
HistoryScreenPosition = InputParams.ScreenPoS -BackN;
```
## 结论
- TAA整体抗锯效果最好,而且基于多帧的时间域实现,可以更好的与新渲染特性兼容,且对SSR起到降噪的作用
- TAA后期位置需放在Bloom之前,避免放在Bloom之后产生的flicker
- 在后期的末端加上FXAA,弥补TAA在后期管线上靠前对有些效果(比如AfterTonemap)抗锯不生效的问题
# 图像处理 Mobile FSR
## 具体方案
从UE5移植Mobile FSR 1.0主要包含针对移动端优化的Upscale和锐化两个Pass。
# 3D UMG
Canvas Panel 3D
- 继承自Canvas Panel,增加透视相关参数,比如Camera的Anchor、FOV和Panel的Rotation、Offset等参数,OnPaint时转换成ViewProjection矩阵传递给Widget
- 优点:1.顶点还是2D,没有增加渲染开销;2.可在编辑器实时预览3D效果
- 不足:只有Canvas的深度信息,无法做顶点级别的深度效果
## 场景交互3DUI
- 新增SeparateTranslucencyAfterPostProcess半透明材质标识,对应新增一个Mesh Pass和Processor收集此类型MeshBatch,放在Tonemap之后绘制
- 解决默认的WidgetComponent受到Tonemap影响带来的色差问题
- 本质上是Mesh的透明渲染,有顶点级别的深度信息,可以访问SceneDepth来实现场景交互
## 需处理的问题
- Tonemap之后绘制,需跳过MobileBasePass的颜色纠正和Android平台的Y轴翻转
- TAA早于TranslucencyAfterPostprocess Pass生效,在该Pass绘制前,View的投影矩阵像素Jitter需去掉(HackRemoveTemporalAAProjectionJitter)
## 结论
- Canvas Panel3D类型满足最常用的界面需求;TranslucencyAfterPostprocess类型满足与场景交互的界面需求
- 抗锯齿:Canvas Panel 3D类型通过带MSAA的中间RenderTarget方式处理;TranslucencyAfterPostprocess类型依靠后期末尾的FXAA
- 其他:使用第三方NiagaraUIRenderer插件来满足UMG上显示特效的需求