2023-12-08 18:00:41 +08:00
---
2023-12-18 09:59:26 +08:00
title: GBuffer& Material& BasePass
2023-12-08 18:00:41 +08:00
date: 2023-12-08 17:34:58
excerpt:
tags:
rating: ⭐
---
2023-12-18 09:59:26 +08:00
# # GBuffer
2024-02-28 19:06:34 +08:00
目前UE5.3会调用
- WriteGBufferInfoAutogen()
- **EncodeGBufferToMRT()**
2024-02-29 16:38:31 +08:00
动态生成BasePassPixelShader.usf中的**EncodeGBufferToMRT()** 的代码, 并且会生成一个AutogenShaderHeaders.ush文件。其路径为:
`Engine\Intermediate\ShaderAutogen\PCD3D_SM5` 或者`Engine\Intermediate\ShaderAutogen\PCD3D_ES3_1`
1. ** *给FGBufferData添加结构体数据时需要在此添加额外代码逻辑***
2024-03-06 22:21:43 +08:00
2. GBuffer精度在FetchLegacyGBufferInfo()设置。
3. 是否往GBuffer中写入Velocity, 主要靠这个宏**WRITES_VELOCITY_TO_GBUFFER**。具体决定其数值的逻辑位于**FShaderGlobalDefines FetchShaderGlobalDefines**。主要还是靠**r.VelocityOutputPass**进行开启。
1. PS. MSAA以及VR绝对不会开启Velocity输出选项。还有就是**r.Velocity.ForceOutput**, 但经过测试不开启r.VelocityOutputPass依然无法输出。以及FPrimitiveSceneProxy的bAlwaysHasVelocity与bHasWorldPositionOffsetVelocity。
2. 其他相关FSR、TSR?
4. 如何添加GBuffer
1. https://zhuanlan.zhihu.com/p/568775542
2. https://zhuanlan.zhihu.com/p/677772284
2024-02-28 19:06:34 +08:00
2024-03-06 22:21:43 +08:00
## UE5 GBuffer内容:
2023-12-19 15:13:51 +08:00
[[UE GBuffer存储数据]]
2023-12-08 18:00:41 +08:00
```c#
2024-03-06 22:21:43 +08:00
OutGBufferA(MRT1) = WorldNormal/PerObjectGBufferData (GBT_Float_16_16_16_16/GBT_Unorm_11_11_10/GBT_Unorm_8_8_8_8)
OutGBufferB(MRT2) = Metallic/Specular/Roughness/EncodeShadingModelIdAndSelectiveOutputMask (GBT_Float_16_16_16_16/GBT_Unorm_8_8_8_8)
OutGBufferC(MRT3) = BaseColor/GBufferAO (GBT_Unorm_8_8_8_8)
OutGBufferD = GBuffer.CustomData (GBT_Unorm_8_8_8_8)
OutGBufferE = GBuffer.PrecomputedShadowFactors (GBT_Unorm_8_8_8_8)
TargetVelocity / OutGBufferF = velocity / tangent (默认不开启 带有深度< 开启Lumen与距离场 或者 开启光线追踪 > GBC_Raw_Float_16_16_16_16 不带深度 GBC_Raw_Float_16_16)
TargetSeparatedMainDirLight = SingleLayerWater相关 (有SingleLayerWater才会开启 GBC_Raw_Float_11_11_10)
2023-12-18 10:48:54 +08:00
// 0..1, 2 bits, use CastContactShadow(GBuffer) or HasDynamicIndirectShadowCasterRepresentation(GBuffer) to extract
half PerObjectGBufferData;
2023-12-08 18:00:41 +08:00
```
2024-03-06 22:21:43 +08:00
GBuffer相关信息( 精度、顺序) 可以参考FetchLegacyGBufferInfo()。
- 不存在Velocity与Tangent:
- OutGBufferD(MRT4)
- OutGBufferD(MRT5)
- ~~TargetSeparatedMainDirLight(MRT6)~~
- 存在Velocity:
- TargetVelocity(MRT4)
- OutGBufferD(MRT5)
- OutGBufferE(MRT6)
- ~~TargetSeparatedMainDirLight(MRT7)~~
- 存在Tangent:
- OutGBufferF(MRT4)
- OutGBufferD(MRT5)
- OutGBufferE(MRT6)
- ~~TargetSeparatedMainDirLight(MRT7)~~
几个动态MRT的存在条件与Shader判断宏:
***查找IsUsingBasePassVelocity()*** 被使用过的地方。
class RPGGAMEPLAYABILITY_API USDHCommonSettings : public UDeveloperSettings
UCLASS(config=Engine, defaultconfig, meta=(DisplayName="Rendering"), MinimalAPI)
class URendererSettings : public UDeveloperSettings
UPROPERTY(config, EditAnywhere, Category = VirtualTextures, meta = (
ConsoleVariable = "r.VirtualTextures", DisplayName = "Enable virtual texture support",
ToolTip = "When enabled, Textures can be streamed using the virtual texture system. Changing this setting requires restarting the editor.",
ConfigRestartRequired = true))
uint32 bVirtualTextures : 1;
2023-12-18 09:59:26 +08:00
2024-03-06 22:21:43 +08:00
- OutGBufferE(PrecomputedShadowFactors): r.AllowStaticLighting = 1
-
- TargetVelocity: (IsUsingBasePassVelocity(Platform) || Layout == GBL_ForceVelocity) ? 1 : 0;//r.VelocityOutputPass = 1
-
- Tangent: false, 目前单独使用另一组MRT来存储。
-
### ToonGBuffer修改&数据存储
2023-12-08 18:00:41 +08:00
```c#
2023-12-18 11:48:10 +08:00
OutGBufferA:PerObjectGBufferData => 可以存储额外的有关Tonn渲染功能参数。
OutGBufferB:Metallic/Specular/Roughness =>
2024-03-06 22:21:43 +08:00
? / SpcularPower(控制高光亮度与Mask) / ? / ?
2023-12-18 11:48:10 +08:00
//ToonHairMask OffsetShadowMask/SpcularMask/SpecularValue
2024-03-06 22:21:43 +08:00
OutGBufferC:GBufferAO =>
2023-12-18 11:48:10 +08:00
OutGBufferD:CustomData.xyzw =>
ShaderColor.rgb / NoLOffset //ShadowColor这里可以在Material里通过主光向量、ShadowStep、Shadow羽化计算多层阴影效果。
OutGBufferE:GBuffer.PrecomputedShadowFactors.xyzw =>
ToonDataID/ ToonObjectID(判断是否是一个物体) /OutlineMask 控制Outline绘制以及Outline强度 / ToonAO
2024-03-06 22:21:43 +08:00
TargetVelocity / OutGBufferF = velocity / tangent //目前先不考虑输出Velocity的情况
2023-12-18 11:48:10 +08:00
? / ? / ? / ?
2023-12-08 18:00:41 +08:00
```
2023-12-18 11:48:10 +08:00
蓝色协议的方案
![[蓝色协议的方案#GBuffer ]]
2023-12-18 10:48:54 +08:00
2024-03-06 22:21:43 +08:00
### 是否需要Toon
在材质中:
```c++
FMaterialRelevance UMaterialInterface::GetRelevance_Internal(const UMaterial* Material, ERHIFeatureLevel::Type InFeatureLevel) const
{
if(Material)
{
//YivanLee's Modify 这里仅仅针对人物, 因为它决定了是否开启ToonGBuffer, 但是对于ToonLevel, ToonFoliage, ToonGrass这里并不需要开启
bool bUseToonData = MaterialResource->GetShadingModels().HasAnyShadingModel({ MSM_ToonStandard, MSM_ToonSkin, MSM_ToonHair, MSM_ToonFace, MSM_ToonEyeBrow });
}
···
MaterialRelevance.bUsesToonData = bUseToonData;
···
}
```
在渲染管线中:
```c++
bool FDeferredShadingSceneRenderer::ShouldRenderToonDataPass() const
{
if (!SupportsToonDataMaterials(FeatureLevel, ShaderPlatform))
{
return false;
}
if (IsForwardShadingEnabled(GetFeatureLevelShaderPlatform(FeatureLevel)))
{
return false;
}
for (auto& View : Views)
{
if (View.ShouldRenderView() & & View.ParallelMeshDrawCommandPasses[EMeshPass::ToonDataPass].HasAnyDraw())
{
return true;
}
}
return false;
}
```
2023-12-18 11:48:10 +08:00
## Toon PerObjectGBufferData具体功能表
从3开始, 0、1、2已被占用。
- ?
2023-12-18 10:48:54 +08:00
2023-12-18 11:48:10 +08:00
## ToonData
2023-12-08 18:00:41 +08:00
## 高光
- PBR高光( 使用Roughness控制是否可行? 是否需要传入GBuffer一个Mask贴图)
- 自定义高光:高光贴图、高光颜色、参数化高光形状、多层高光
2024-03-06 22:21:43 +08:00
# BasePassPixelShader
Velocity相关代码段:
```c++
#if USES_GBUFFER
// -0.5 .. 0.5, could be optimzed as lower quality noise would be sufficient
float QuantizationBias = PseudoRandom( MaterialParameters.SvPosition.xy ) - 0.5f;
GBuffer.IndirectIrradiance = IndirectIrradiance;
// this is the new encode, the older encode is the #else , keeping it around briefly until the new version is confirmed stable.
#if 1
{
// change this so that we can pack everything into the gbuffer, but leave this for now
#if GBUFFER_HAS_DIFFUSE_SAMPLE_OCCLUSION
GBuffer.GenericAO = float(GBuffer.DiffuseIndirectSampleOcclusion) * (1.0f / 255.0f);
#elif ALLOW_STATIC_LIGHTING
// No space for AO. Multiply IndirectIrradiance by AO instead of storing.
GBuffer.GenericAO = EncodeIndirectIrradiance(GBuffer.IndirectIrradiance * GBuffer.GBufferAO) + QuantizationBias * (1.0 / 255.0); // Stationary sky light path
#else
GBuffer.GenericAO = GBuffer.GBufferAO; // Movable sky light path
#endif
EncodeGBufferToMRT(Out, GBuffer, QuantizationBias);
if (GBuffer.ShadingModelID == SHADINGMODELID_UNLIT & & !STRATA_ENABLED) // Do not touch what strata outputs
{
Out.MRT[1] = 0;
SetGBufferForUnlit(Out.MRT[2]);
Out.MRT[3] = 0;
Out.MRT[GBUFFER_HAS_VELOCITY ? 5 : 4] = 0;
Out.MRT[GBUFFER_HAS_VELOCITY ? 6 : 5] = 0;
}
#if SINGLE_LAYER_WATER_SEPARATED_MAIN_LIGHT
// In deferred, we always output the directional light in a separated buffer.
// This is used to apply distance field shadows or light function to the main directional light.
// Strata also writes it through MRT because this is faster than through UAV.
#if STRATA_ENABLED && STRATA_INLINE_SINGLELAYERWATER
Out.MRT[(GBUFFER_HAS_VELOCITY ? 2 : 1) + (GBUFFER_HAS_PRECSHADOWFACTOR ? 1 : 0)] = float4(SeparatedWaterMainDirLightLuminance * View.PreExposure, 1.0f);
#else
if (GBuffer.ShadingModelID == SHADINGMODELID_SINGLELAYERWATER)
{
Out.MRT[(GBUFFER_HAS_VELOCITY ? 6 : 5) + (GBUFFER_HAS_PRECSHADOWFACTOR ? 1 : 0)] = float4(SeparatedWaterMainDirLightLuminance * View.PreExposure, 1.0f);
}
#endif
#endif
}
```
2023-12-18 11:48:10 +08:00
# 顶点色
## 蓝色协议
2023-12-08 18:00:41 +08:00
用于存储一些低精度数据,插值即可
2023-12-18 11:48:10 +08:00
- 顶点色:
- R:阴影区域控制(强度) 0~1
- G:描边宽度
- B:ToonAO
- 第二套顶点色( UV Channel1) :
- R:深度偏移
- G:用来区分内轮廓不同部位的ID
2023-12-08 18:00:41 +08:00
2023-12-18 11:48:10 +08:00
蓝色协议的R:阴影区域标记 与 B:AO, 而罪恶装备使用贴图来传递信息。
## 罪恶装备
对阴影判断阈值的偏移。( 见前面着色部分, 顶点AO+手绘修正)
R:阴影偏移
G:轮廓线根据与相机的距离扩大多少的系数
B:等高线 Z 轴偏移值
# 罪恶装备
8,G为阴影控( AO) , R为高光强度参数, 金属和光滑材质的部分设置的更大一些。B通道: 用于照明控制。最大值为高光, 反之, 值越小高光越淡。
2023-12-08 18:00:41 +08:00

https://zhuanlan.zhihu.com/p/360229590一文中介绍了崩坏3与原神的计算方式
崩坏3的LightMap计算方式:
```c++
half4 baseColor = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv.xy);
half4 LightMapColor = SAMPLE_TEXTURE2D(_LightMap, sampler_LightMap, input.uv.xy);
half3 ShadowColor = baseColor.rgb * _ShadowMultColor.rgb;
half3 DarkShadowColor = baseColor.rgb * _DarkShadowMultColor.rgb;
//如果SFactor = 0,ShallowShadowColor为一级阴影色,否则为BaseColor。
float SWeight = (LightMapColor.g * input.color.r + input.lambert) * 0.5 + 1.125;
float SFactor = floor(SWeight - _ShadowArea);
half3 ShallowShadowColor = SFactor * baseColor.rgb + (1 - SFactor) * ShadowColor.rgb;
```
二级阴影计算:
```c++
//如果SFactor = 0,DarkShadowColor为二级阴影色,否则为一级阴影色。
SFactor = floor(SWeight - _DarkShadowArea);
DarkShadowColor = SFactor * (_FixDarkShadow * ShadowColor + (1 - _FixDarkShadow) * ShallowShadowColor) + (1 - SFactor) * DarkShadowColor;
// 平滑阴影边缘
half rampS = smoothstep(0, _ShadowSmooth, input.lambert - _ShadowArea);
half rampDS = smoothstep(0, _DarkShadowSmooth, input.lambert - _DarkShadowArea);
ShallowShadowColor.rgb = lerp(ShadowColor, baseColor.rgb, rampS);
DarkShadowColor.rgb = lerp(DarkShadowColor.rgb, ShadowColor, rampDS);
//如果SFactor = 0,FinalColor为二级阴影, 否则为一级阴影。
SFactor = floor(LightMapColor.g * input.color.r + 0.9f);
half4 FinalColor;
FinalColor.rgb = SFactor * ShallowShadowColor + (1 - SFactor) * DarkShadowColor;
```
**罪恶装备**:
对阴影判断阈值的偏移。( 见前面着色部分, 顶点AO+手绘修正)
G : 轮廓线根据与相机的距离扩大多少的系数
B : 等高线 Z 轴偏移值
A : 轮廓厚度系数。0.5为标准, 1为最大厚度, 0为无等高线
2023-12-18 11:48:10 +08:00
# 蓝色协议
2023-12-16 23:09:19 +08:00
[[蓝色协议的方案]]
2023-12-18 11:48:10 +08:00
# 米哈游