33 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	title, date, excerpt, tags, rating
| title | date | excerpt | tags | rating | 
|---|---|---|---|---|
| ToonReflection | 2025-03-20 17:04:16 | ⭐ | 
反射功能相关Pass
- ReflectionIndirect(None)
 - DiffuseIndirectAndAO(Lumen/SSR)
- LumenReflections
 
 
PS. DiffuseIndirectAndAO Pass会根据 ViewPipelineState.DiffuseIndirectMethod是否为Lumen,出现在Light Pass之前(GI方法为Lumen)或者之后(GI方法为非Lumen)。
ReflectionEnvironmentAndSky
位于IndirectLightRendering.cpp的RenderDeferredReflectionsAndSkyLighting() => AddSkyReflectionPass()
当DiffuseIndirectMethod = EDiffuseIndirectMethod::Lumen(也就是开启Lumen GI),如果反射方法为Lumen或者SSR则不会执行后续逻辑。
不开启Lumen GI,反射方法为:
- Lumen:
RenderLumenReflections() - RT Reflection:
RenderRayTracingReflections() - SSR:
ScreenSpaceRayTracing::RenderScreenSpaceReflections() 
RenderDeferredReflectionsAndSkyLighting()主要执行了:
- SkyLightDiffuse
- RenderDistanceFieldLighting()
- RenderDistanceFieldAOScreenGrid():渲染距离场AO。
 - RenderCapsuleShadowsForMovableSkylight():渲染胶囊阴影。
 
 
 - RenderDistanceFieldLighting()
 - ReflectionIndirect
- RenderLumenReflections()
 - RenderRayTracingReflections()
 - RenderScreenSpaceReflections()
 
 - Denoise
- Denoiser:IScreenSpaceDenoiser::DenoiseReflections()
 - TemporalFilter:AddTemporalAAPass()
 
 - RenderDeferredPlanarReflections():合成平面反射结果。
 - AddSkyReflectionPass()
 
几种反射方式的大致执行逻辑:
- LumenReflection
- 输出FRDGTextureRef ReflectionsColor。
 
 - SSR与RT
- 输出结果到IScreenSpaceDenoiser::FReflectionsInputs DenoiserInputs的FRDGTextureRef Color。
 - 执行对应的降噪算法。
 - 结果赋予给FRDGTextureRef ReflectionsColor。
 
 - 执行完上述反射方法后,最后执行
AddSkyReflectionPass() 
FReflectionEnvironmentSkyLightingPS位于/Engine/Private/ReflectionEnvironmentPixelShader.usf的ReflectionEnvironmentSkyLighting()。
ReflectionEnvironmentSkyLighting
void ReflectionEnvironmentSkyLighting(
	in float4 SvPosition : SV_Position,
	out float4 OutColor : SV_Target0
#if STRATA_OPAQUE_ROUGH_REFRACTION_ENABLED
	, out float3 OutOpaqueRoughRefractionSceneColor : SV_Target1
	, out float3 OutSubSurfaceSceneColor : SV_Target2
#endif
	)
{
	ResolvedView = ResolveView();
	//计算获去BufferUV、ScreenPosition
	uint2 PixelPos = SvPosition.xy;
	float2 BufferUV = SvPositionToBufferUV(SvPosition);
	float2 ScreenPosition = SvPositionToScreenPosition(SvPosition).xy;
	
	OutColor = 0.0f;
#if STRATA_OPAQUE_ROUGH_REFRACTION_ENABLED
	OutOpaqueRoughRefractionSceneColor = 0.0f;
	OutSubSurfaceSceneColor = 0.0f;
#endif
#if STRATA_ENABLED
...
...
#else // STRATA_ENABLED
	// Sample scene textures.
	FGBufferData GBuffer = GetGBufferDataFromSceneTextures(BufferUV);
	uint ShadingModelID = GBuffer.ShadingModelID;
	const bool bUnlitMaterial = ShadingModelID == SHADINGMODELID_UNLIT;
	float3 DiffuseColor = GBuffer.DiffuseColor;
	float3 SpecularColor = GBuffer.SpecularColor;
	RemapClearCoatDiffuseAndSpecularColor(GBuffer, ScreenPosition, DiffuseColor, SpecularColor);//针对清漆材质进行Diffuse颜色与Specular颜色重新映射
	// Sample the ambient occlusion that is dynamically generated every frame.
	float AmbientOcclusion = AmbientOcclusionTexture.SampleLevel(AmbientOcclusionSampler, BufferUV, 0).r;
	float3 BentNormal = GBuffer.WorldNormal;
#if APPLY_SKY_SHADOWING
	{
		BentNormal = UpsampleDFAO(BufferUV, GBuffer.Depth, GBuffer.WorldNormal);
	}
#endif
#if ENABLE_DYNAMIC_SKY_LIGHT
	BRANCH
	if (!bUnlitMaterial) // Only light pixels marked as lit //Unlit材质不会计算动态天光GI的效果。
	{
		float3 TranslatedWorldPosition = mul(float4(GetScreenPositionForProjectionType(ScreenPosition, GBuffer.Depth), GBuffer.Depth, 1), View.ScreenToTranslatedWorld).xyz;
		const float CloudVolumetricAOShadow = GetCloudVolumetricAOShadow(TranslatedWorldPosition);//从体积云 VolumetricCloudShadowMapTexture中取得ShadowFrontDepthKm、MaxOpticalDepth,MeanExtinction,最终计算出体积云阴影。UE5.3该函数没有启用。
		float3 SkyLighting = CloudVolumetricAOShadow * SkyLightDiffuse(GBuffer, AmbientOcclusion, BufferUV, ScreenPosition, BentNormal, DiffuseColor);
		FLightAccumulator LightAccumulator = (FLightAccumulator)0;
		const bool bNeedsSeparateSubsurfaceLightAccumulation = UseSubsurfaceProfile(ShadingModelID);
		LightAccumulator_Add(LightAccumulator, SkyLighting, SkyLighting, 1.0f, bNeedsSeparateSubsurfaceLightAccumulation);
		OutColor = LightAccumulator_GetResult(LightAccumulator);
	}
#endif // ENABLE_DYNAMIC_SKY_LIGHT 
	BRANCH
	if (!bUnlitMaterial && ShadingModelID != SHADINGMODELID_HAIR)//
	{
		OutColor.xyz += ReflectionEnvironment(GBuffer, AmbientOcclusion, BufferUV, ScreenPosition, SvPosition, BentNormal, SpecularColor, ShadingModelID);
	}
#endif // STRATA_ENABLED
}
SkyLightDiffuse
- 计算float3 SkyLightingNormal、FSkyLightVisibilityData SkyVisData。
 - 计算Normal、ViewVector、NoV。
 - 针对制定ShadingModel进行额外计算:
- SHADINGMODELID_TWOSIDED_FOLIAGE:使用Normal反向量取得SkySHDiffuse,在乘以SubsurfaceColor、SkyVisData.SkyDiffuseLookUpMul后累加到结果上。
 - SHADINGMODELID_SUBSURFACE、SHADINGMODELID_PREINTEGRATED_SKIN:从GBuffer中提取SubsurfaceColor并累加到结果上。
 - SHADINGMODELID_CLOTH:从GBuffer中提取ClothFuzz(SubsurfaceColor)乘以CustomData.a,并累加到结果上。
 - SHADINGMODELID_HAIR:
- DiffuseColor = EvaluateEnvHair(GBuffer, V, N, L);
 - SkyVisData.SkyDiffuseLookUpNormal = L;
 - DiffuseWeight = 1.0f;
 
 
 - 调用GetSkySHDiffuse()计算天光光照效果。GetSkySHDiffuse()本质是采样球谐贴图,来获得天光GI结果。
 
ReflectionEnvironment
float3 ReflectionEnvironment(FGBufferData GBuffer, float AmbientOcclusion, float2 BufferUV, float2 ScreenPosition, float4 SvPosition, float3 BentNormal, float3 SpecularColor, uint ShadingModelID)
{
	float4 Color = float4(0, 0, 0, 1);
	float IndirectIrradiance = GBuffer.IndirectIrradiance;
	
#if ENABLE_SKY_LIGHT && ALLOW_STATIC_LIGHTING
	BRANCH
	// Add in diffuse contribution from dynamic skylights so reflection captures will have something to mix with
	if (ReflectionStruct.SkyLightParameters.y > 0 && ReflectionStruct.SkyLightParameters.z > 0)
	{
		//如果开启天光、并且开启静态关照。会在这里采样SkySH,以此累加间接照明。
		IndirectIrradiance += GetDynamicSkyIndirectIrradiance(BentNormal, GBuffer.WorldNormal);
	}
#endif
	//计算反射Vector、WorldNormal、ViewVector
	float3 TranslatedWorldPosition = mul(float4(GetScreenPositionForProjectionType(ScreenPosition, GBuffer.Depth), GBuffer.Depth, 1), View.ScreenToTranslatedWorld).xyz;
	float3 CameraToPixel = normalize(TranslatedWorldPosition - View.TranslatedWorldCameraOrigin);
	float3 ReflectionVector = reflect(CameraToPixel, GBuffer.WorldNormal);
    float3 V = -CameraToPixel;
	float3 N = GBuffer.WorldNormal;
	const float3 SavedTopLayerNormal = N;
#if SUPPORTS_ANISOTROPIC_MATERIALS
	ModifyGGXAnisotropicNormalRoughness(GBuffer.WorldTangent, GBuffer.Anisotropy, GBuffer.Roughness, N, V);
#endif
	float3 R = 2 * dot( V, N ) * N - V;
	float NoV = saturate( dot( N, V ) );
	// Point lobe in off-specular peak direction
	R = GetOffSpecularPeakReflectionDir(N, R, GBuffer.Roughness);
	// 采样 SSR, planar reflections, RT reflections or Lumen 反射结果。
	float4 ReflectionInput = Texture2DSample(ReflectionTexture, ReflectionTextureSampler, BufferUV);
	Color = CompositeReflections(ReflectionInput, BufferUV, GBuffer.Roughness, ShadingModelID);//Color = float4(ReflectionInput.rgb, 1 - ReflectionInput.a)
#if RAY_TRACED_REFLECTIONS
	float4 SavedColor = Color;	// When a clear coat material is encountered, we save the reflection buffer color for it to not be affected by operations.
#endif
	if(GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT )
	{
#if RAY_TRACED_REFLECTIONS
		Color = float4(0, 0, 0, 1); // Clear coat reflection is expected to be computed on a black background
#endif
		const float ClearCoat = GBuffer.CustomData.x;
		Color = lerp( Color, float4(0,0,0,1), ClearCoat );
#if CLEAR_COAT_BOTTOM_NORMAL
		const float2 oct1 = ((float2(GBuffer.CustomData.a, GBuffer.CustomData.z) * 4) - (512.0/255.0)) + UnitVectorToOctahedron(GBuffer.WorldNormal);
		const float3 ClearCoatUnderNormal = OctahedronToUnitVector(oct1);
		const float3 BottomEffectiveNormal = ClearCoatUnderNormal;			
		R = 2 * dot( V, ClearCoatUnderNormal ) * ClearCoatUnderNormal - V;
#endif
	}
	float AO = GBuffer.GBufferAO * AmbientOcclusion;//AmbientOcclusion为SSAO或者RTAO或者DFAO或者Lumen……
	float RoughnessSq = GBuffer.Roughness * GBuffer.Roughness;
	float SpecularOcclusion = GetSpecularOcclusion(NoV, RoughnessSq, AO);
	Color.a *= SpecularOcclusion;
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM5
	float2 LocalPosition = SvPosition.xy - View.ViewRectMin.xy;
	uint GridIndex = ComputeLightGridCellIndex(uint2(LocalPosition.x, LocalPosition.y), GBuffer.Depth);
	uint NumCulledEntryIndex = (ForwardLightData.NumGridCells + GridIndex) * NUM_CULLED_LIGHTS_GRID_STRIDE;
	uint NumCulledReflectionCaptures = min(ForwardLightData.NumCulledLightsGrid[NumCulledEntryIndex + 0], ForwardLightData.NumReflectionCaptures);
	uint DataStartIndex = ForwardLightData.NumCulledLightsGrid[NumCulledEntryIndex + 1];
#else
	uint DataStartIndex = 0;
	uint NumCulledReflectionCaptures = 0;
#endif
	const FBxDFEnergyTerms EnergyTerms = ComputeGGXSpecEnergyTerms(GBuffer.Roughness, NoV, GBuffer.SpecularColor);
	//常规反射 或 底层清漆 光照计算
	//Top of regular reflection or bottom layer of clear coat.
	Color.rgb += View.PreExposure * GatherRadiance(Color.a, TranslatedWorldPosition, R, GBuffer.Roughness, BentNormal, IndirectIrradiance, GBuffer.ShadingModelID, NumCulledReflectionCaptures, DataStartIndex);
	BRANCH
	if( GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT)
	{
		const float ClearCoat			= GBuffer.CustomData.x;
		const float ClearCoatRoughness	= GBuffer.CustomData.y;
		// Restore saved values needed for the top layer.
		GBuffer.WorldNormal = SavedTopLayerNormal;
		// Recompute some values unaffected by anistropy for the top layer
		N = GBuffer.WorldNormal;
		R = 2 * dot(V, N) * N - V;
		NoV = saturate(dot(N, V));
		R = GetOffSpecularPeakReflectionDir(N, R, ClearCoatRoughness);
		// TODO EnvBRDF should have a mask param
		#if USE_ENERGY_CONSERVATION
		Color.rgb *= EnergyTerms.E * (1 - ClearCoat);
		#else
		// Hack: Ensures when clear coat is >0, grazing angle does not get too much energy, 
		//       but preserve response at normal incidence 
		float2 AB = PreIntegratedGF.SampleLevel(PreIntegratedGFSampler, float2(NoV, GBuffer.Roughness), 0).rg;
		Color.rgb *= SpecularColor * AB.x + AB.y * saturate(50 * SpecularColor.g) * (1 - ClearCoat);
		#endif
		// F_Schlick
		const float CoatF0 = 0.04f;
		#if USE_ENERGY_CONSERVATION
		float F = ComputeGGXSpecEnergyTerms(ClearCoatRoughness, NoV, CoatF0).E.x;
		#else
		float F = EnvBRDF(CoatF0, ClearCoatRoughness, NoV).x;
		#endif
		F *= ClearCoat;
			
		float LayerAttenuation = (1 - F);		
		Color.rgb *= LayerAttenuation;
		Color.a = F;
		
#if !RAY_TRACED_REFLECTIONS	
		Color.rgb += ReflectionInput.rgb * F;
		Color.a *= 1 - ReflectionInput.a;
#endif
			
		Color.a *= SpecularOcclusion;
		float3 TopLayerR = 2 * dot( V, N ) * N - V;
		Color.rgb += View.PreExposure * GatherRadiance(Color.a, TranslatedWorldPosition, TopLayerR, ClearCoatRoughness, BentNormal, IndirectIrradiance, GBuffer.ShadingModelID, NumCulledReflectionCaptures, DataStartIndex);
	#if RAY_TRACED_REFLECTIONS
		Color.rgb = SavedColor.rgb +  Color.rgb * SavedColor.a; // Compose default clear coat reflection over regular refelction (using Premultiplied alpha where SaveColor.a=transmittance)
	#endif
	}
	else
	{
		#if USE_ENERGY_CONSERVATION
		Color.rgb *= EnergyTerms.E;
		#else
		Color.rgb *= EnvBRDF( SpecularColor, GBuffer.Roughness, NoV );
		#endif
	}
	// Transform NaNs to black, transform negative colors to black.
	return -min(-Color.rgb, 0.0);
}
GatherRadiance()
GatherRadiance()主要计算了SkyLightTexture(天空盒贴图)以及ReflectionCapture(Box、Sphere反射球),最终根据之前计算的Color.a进行合成。
float3 GatherRadiance(float CompositeAlpha, float3 TranslatedWorldPosition, float3 RayDirection, float Roughness, float3 BentNormal, float IndirectIrradiance, uint ShadingModelID, uint NumCulledReflectionCaptures, uint CaptureDataStartIndex)
{
	// Indirect occlusion from DFAO, which should be applied to reflection captures and skylight specular, but not SSR
	float IndirectSpecularOcclusion = 1.0f;
	float3 ExtraIndirectSpecular = 0;
#if SUPPORT_DFAO_INDIRECT_OCCLUSION
	float IndirectDiffuseOcclusion;
	GetDistanceFieldAOSpecularOcclusion(BentNormal, RayDirection, Roughness, ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE, IndirectSpecularOcclusion, IndirectDiffuseOcclusion, ExtraIndirectSpecular);
	// Apply DFAO to IndirectIrradiance before mixing with indirect specular
	IndirectIrradiance *= IndirectDiffuseOcclusion;
#endif
	const bool bCompositeSkylight = true;
	return CompositeReflectionCapturesAndSkylightTWS(
		CompositeAlpha, 
		TranslatedWorldPosition, 
		RayDirection, 
		Roughness, 
		IndirectIrradiance, 
		IndirectSpecularOcclusion, 
		ExtraIndirectSpecular, 
		NumCulledReflectionCaptures, 
		CaptureDataStartIndex, 
		0,
		bCompositeSkylight);
}
主要逻辑位于CompositeReflectionCapturesAndSkylightTWS():
float3 CompositeReflectionCapturesAndSkylightTWS(
	float CompositeAlpha, 
	float3 TranslatedWorldPosition, 
	float3 RayDirection, 
	float Roughness, 
	float IndirectIrradiance, 
	float IndirectSpecularOcclusion,
	float3 ExtraIndirectSpecular,
	uint NumCapturesAffectingTile,
	uint CaptureDataStartIndex, 
	int SingleCaptureIndex,
	bool bCompositeSkylight,
	uint EyeIndex)
{
	float Mip = ComputeReflectionCaptureMipFromRoughness(Roughness, View.ReflectionCubemapMaxMip);
	float4 ImageBasedReflections = float4(0, 0, 0, CompositeAlpha);
	float2 CompositedAverageBrightness = float2(0.0f, 1.0f);
#if REFLECTION_COMPOSITE_USE_BLENDED_REFLECTION_CAPTURES
	// Accumulate reflections from captures affecting this tile, applying largest captures first so that the smallest ones display on top
	//ReflectionCapture Blend,其顺序为大范围在前
	LOOP
	for (uint TileCaptureIndex = 0; TileCaptureIndex < NumCapturesAffectingTile; TileCaptureIndex++) 
	{
		BRANCH
		if (ImageBasedReflections.a < 0.001)//如果Alpha小于0.001则停止循环,结束合成计算。
		{
			break;
		}
		//计算CaptureIndex
		uint CaptureIndex = 0;
#ifdef REFLECTION_COMPOSITE_NO_CULLING_DATA
		CaptureIndex = TileCaptureIndex;	// Go from 0 to NumCapturesAffectingTile as absolute index in capture array
#else
	#if (INSTANCED_STEREO || MOBILE_MULTI_VIEW)//VR或者移动端多View
		BRANCH
		if (EyeIndex == 0)
		{
	#endif
	
			CaptureIndex = GetCulledLightDataGrid(CaptureDataStartIndex + TileCaptureIndex);
	
	#if (INSTANCED_STEREO || MOBILE_MULTI_VIEW)
		}
		else
		{
			CaptureIndex = GetCulledLightDataGridISR(CaptureDataStartIndex + TileCaptureIndex);
		}
	#endif
#endif
		FLWCVector3 CaptureWorldPosition = MakeLWCVector3(GetReflectionTilePosition(CaptureIndex).xyz, GetReflectionPositionAndRadius(CaptureIndex).xyz);
		float3 CaptureTranslatedWorldPosition = LWCToFloat(LWCAdd(CaptureWorldPosition, ResolvedView.PreViewTranslation));
		float CaptureRadius = GetReflectionPositionAndRadius(CaptureIndex).w;
		float4 CaptureProperties = GetReflectionCaptureProperties(CaptureIndex);
		float3 CaptureVector = TranslatedWorldPosition - CaptureTranslatedWorldPosition;
		float CaptureVectorLength = sqrt(dot(CaptureVector, CaptureVector));		
		float NormalizedDistanceToCapture = saturate(CaptureVectorLength / CaptureRadius);
		BRANCH
		if (CaptureVectorLength < CaptureRadius)//当前像素处于ReflectionCapture范围内
		{
			float3 ProjectedCaptureVector = RayDirection;
			float4 CaptureOffsetAndAverageBrightness = GetReflectionCaptureOffsetAndAverageBrightness(CaptureIndex);
			// Fade out based on distance to capture
			float DistanceAlpha = 0;
			
			#define PROJECT_ONTO_SHAPE 1
			#if PROJECT_ONTO_SHAPE
				//盒形反射球
				#if REFLECTION_COMPOSITE_HAS_BOX_CAPTURES
					#if REFLECTION_COMPOSITE_HAS_SPHERE_CAPTURES
					// Box
					BRANCH if (CaptureProperties.b > 0)
					#endif
					{
						ProjectedCaptureVector = GetLookupVectorForBoxCapture(RayDirection, TranslatedWorldPosition, float4(CaptureTranslatedWorldPosition, CaptureRadius),
																			 GetReflectionBoxTransform(CaptureIndex), GetReflectionBoxScales(CaptureIndex), CaptureOffsetAndAverageBrightness.xyz, DistanceAlpha);
					}
				#endif
				
				//球形反射球
				#if REFLECTION_COMPOSITE_HAS_SPHERE_CAPTURES
					// Sphere
					#if REFLECTION_COMPOSITE_HAS_BOX_CAPTURES
					else
					#endif
					{
						ProjectedCaptureVector = GetLookupVectorForSphereCapture(RayDirection, TranslatedWorldPosition, float4(CaptureTranslatedWorldPosition, CaptureRadius), NormalizedDistanceToCapture, CaptureOffsetAndAverageBrightness.xyz, DistanceAlpha);
					}
				#endif
			#else 
				DistanceAlpha = 1.0;
			#endif //PROJECT_ONTO_SHAPE
			float CaptureArrayIndex = CaptureProperties.g;
			{
				//采样对应的ReflectionCubeMap,Sample.a为根据距离计算的Alpha。最后结果累加到ImageBasedReflections中。
				float4 Sample = ReflectionStruct.ReflectionCubemap.SampleLevel(ReflectionStruct.ReflectionCubemapSampler, float4(ProjectedCaptureVector, CaptureArrayIndex), Mip);
				Sample.rgb *= CaptureProperties.r;
				Sample *= DistanceAlpha;
				// Under operator (back to front)
				ImageBasedReflections.rgb += Sample.rgb * ImageBasedReflections.a * IndirectSpecularOcclusion;
				ImageBasedReflections.a *= 1 - Sample.a;
				float AverageBrightness = CaptureOffsetAndAverageBrightness.w;
				CompositedAverageBrightness.x += AverageBrightness * DistanceAlpha * CompositedAverageBrightness.y;
				CompositedAverageBrightness.y *= 1 - DistanceAlpha;
			}
		}
	}
#else
	//非ReflectionCapture Blend
	float3 ProjectedCaptureVector = RayDirection;
	FLWCVector3 SingleCaptureWorldPosition = MakeLWCVector3(GetReflectionTilePosition(SingleCaptureIndex).xyz, GetReflectionPositionAndRadius(SingleCaptureIndex).xyz);
	float3 SingleCaptureTranslatedWorldPosition = LWCToFloat(LWCAdd(SingleCaptureWorldPosition, ResolvedView.PreViewTranslation));
	float SingleCaptureRadius = GetReflectionPositionAndRadius(SingleCaptureIndex).w;
	float4 SingleCaptureOffsetAndAverageBrightness = GetReflectionCaptureOffsetAndAverageBrightness(SingleCaptureIndex);
	float SingleCaptureBrightness = GetReflectionCaptureProperties(SingleCaptureIndex).x;
	float SingleCaptureArrayIndex = GetReflectionCaptureProperties(SingleCaptureIndex).y;
	#define APPROXIMATE_CONTINUOUS_SINGLE_CAPTURE_PARALLAX 0
	#if APPROXIMATE_CONTINUOUS_SINGLE_CAPTURE_PARALLAX
		float3 CaptureVector = TranslatedWorldPosition - SingleCaptureTranslatedWorldPosition;
		float CaptureVectorLength = sqrt(dot(CaptureVector, CaptureVector));		
		float NormalizedDistanceToCapture = saturate(CaptureVectorLength / SingleCaptureRadius);
		float UnusedDistanceAlpha = 0;
		ProjectedCaptureVector = GetLookupVectorForSphereCapture(RayDirection, TranslatedWorldPosition, float4(SingleCaptureTranslatedWorldPosition, SingleCaptureRadius), NormalizedDistanceToCapture, SingleCaptureOffsetAndAverageBrightness.xyz, UnusedDistanceAlpha);
		
		float x = saturate(NormalizedDistanceToCapture);
		float DistanceAlpha = 1 - x * x * (3 - 2 * x);
		// Lerp between sphere parallax corrected and infinite based on distance to shape
		ProjectedCaptureVector = lerp(RayDirection, normalize(ProjectedCaptureVector), DistanceAlpha);
	#endif
	float4 Sample = TextureCubeArraySampleLevel(ReflectionStruct.ReflectionCubemap, ReflectionStruct.ReflectionCubemapSampler, ProjectedCaptureVector, SingleCaptureArrayIndex, Mip);
	Sample.rgb *= SingleCaptureBrightness;
	ImageBasedReflections = float4(Sample.rgb, 1 - Sample.a);
	float AverageBrightness = SingleCaptureOffsetAndAverageBrightness.w;
	CompositedAverageBrightness.x += AverageBrightness * CompositedAverageBrightness.y;
	CompositedAverageBrightness.y = 0;
#endif
	// Apply indirect lighting scale while we have only accumulated reflection captures
	ImageBasedReflections.rgb *= View.PrecomputedIndirectSpecularColorScale;
	CompositedAverageBrightness.x *= Luminance( View.PrecomputedIndirectSpecularColorScale );
#if ENABLE_SKY_LIGHT
	BRANCH  
	if (ReflectionStruct.SkyLightParameters.y > 0 && bCompositeSkylight)
	{
		float SkyAverageBrightness = 1.0f;
		// 不支持Blend的,结果大致为SkyLightCubeMap * View.SkyLightColor。支持Blend的,lerp(Reflection, BlendDestinationReflection * View.SkyLightColor.rgb, ReflectionStruct.SkyLightParameters.w);
		#if REFLECTION_COMPOSITE_SUPPORT_SKYLIGHT_BLEND
			float3 SkyLighting = GetSkyLightReflectionSupportingBlend(RayDirection, Roughness, SkyAverageBrightness);
		#else
			float3 SkyLighting = GetSkyLightReflection(RayDirection, Roughness, SkyAverageBrightness);
		#endif
		// Normalize for static skylight types which mix with lightmaps, material ambient occlusion as well as diffuse/specular occlusion.
		bool bNormalize = ReflectionStruct.SkyLightParameters.z < 1 && ALLOW_STATIC_LIGHTING;
		FLATTEN
		if (bNormalize)
		{
			ImageBasedReflections.rgb += ImageBasedReflections.a * SkyLighting * IndirectSpecularOcclusion;
			CompositedAverageBrightness.x += SkyAverageBrightness * CompositedAverageBrightness.y;
		}
		else
		{
			ExtraIndirectSpecular += SkyLighting * IndirectSpecularOcclusion;
		}
	}
#endif
#if ALLOW_STATIC_LIGHTING
	ImageBasedReflections.rgb *= ComputeMixingWeight(IndirectIrradiance, CompositedAverageBrightness.x, Roughness);
#endif
	ImageBasedReflections.rgb += ImageBasedReflections.a * ExtraIndirectSpecular;
	return ImageBasedReflections.rgb;
}
DiffuseIndirectComposite
位于IndirectLightRendering.cpp的RenderDiffuseIndirectAndAmbientOcclusion()
RenderDiffuseIndirectAndAmbientOcclusion()主要执行了:
- 进行判断是否跳过当前View的计算。(主要是判断是否开启Lumen,以及传入的bCompositeRegularLumenOnly变量)
 - SetupCommonDiffuseIndirectParameters()
 - 计算GI
- ScreenSpaceGI
 - RTGI
 - Lumen
- Lumen Reflection:输出结果到OutTextures.Textures[3]。
 - SSR:输出结果到OutTextures.Textures[3]。
 - 其他Reflection:结果输出为黑色。
 
 
 - 使用降噪器对SSGI与RTGI进行降噪
 - 渲染AO
- 禁用
 - RTAO
 - SSAO
 - 其他没有实现的会谈报错提醒
 
 - 将渲染的AO结果赋予SceneTextures.ScreenSpaceAO
 - RenderHairStrandsAmbientOcclusion()
 - 应用GI到渲染结果上。
 - ApplyAmbientCubemapComposite()
 
FDiffuseIndirectCompositePS位于/Engine/Private/DiffuseIndirectComposite.usf的MainPS()
FDiffuseIndirectCompositePS
void MainPS(
	float4 SvPosition : SV_POSITION
#if DIM_APPLY_DIFFUSE_INDIRECT
#if ENABLE_DUAL_SRC_BLENDING
	, out float4 OutAddColor      DUAL_SOURCE_BLENDING_SLOT(0) : SV_Target0
	, out float4 OutMultiplyColor DUAL_SOURCE_BLENDING_SLOT(1) : SV_Target1
#else
	, out float4 OutColor 		  : SV_Target0
#endif
#else
	, out float4 OutMultiplyColor : SV_Target0
#endif
)
{
	const uint2 PixelPos = SvPosition.xy;
	const float2 SceneBufferUV = SvPositionToBufferUV(SvPosition);
	const float2 ScreenPosition = SvPositionToScreenPosition(SvPosition).xy;
	#if !ENABLE_DUAL_SRC_BLENDING && DIM_APPLY_DIFFUSE_INDIRECT
	float4 OutAddColor = float4(0.0, 0.0, 0.0, 0.0);
	float4 OutMultiplyColor;
	const float4 SceneColor = SceneColorTexture.SampleLevel(SceneColorSampler, SceneBufferUV, 0);
	#endif
	// Sample scene textures.
	const FLumenMaterialData Material = ReadMaterialData(PixelPos, SceneBufferUV);
	// Sample the ambient occlusion that is dynamically generated every frame.
	const float DynamicAmbientOcclusion = AmbientOcclusionTexture.SampleLevel(AmbientOcclusionSampler, SceneBufferUV, 0).r;
	// Compute the final ambient occlusion to be applied. Lumen handles material AO internally.
	float FinalAmbientOcclusion = 1.0f;
	#if DIM_APPLY_DIFFUSE_INDIRECT != DIM_APPLY_DIFFUSE_INDIRECT_SCREEN_PROBE_GATHER
	{
		float AOMask = IsValid(Material);
		FinalAmbientOcclusion = lerp(1.0f, Material.MaterialAO * DynamicAmbientOcclusion, AOMask * AmbientOcclusionStaticFraction);
	}
	#endif
	const float3 TranslatedWorldPosition = mul(float4(GetScreenPositionForProjectionType(ScreenPosition, Material.SceneDepth), Material.SceneDepth, 1), View.ScreenToTranslatedWorld).xyz;
	const float3 N = Material.WorldNormal;
	const float3 V = normalize(View.TranslatedWorldCameraOrigin - TranslatedWorldPosition);
	const float NoV = saturate(dot(N, V));
	// Apply diffuse indirect.
	//这里的DIM可能是Diffuse Indirect Map的缩写
	#if DIM_APPLY_DIFFUSE_INDIRECT
	OutAddColor = 0;
	{
		FDirectLighting IndirectLighting = (FDirectLighting)0;
		if (IsValid(Material))
		{
			float3 DiffuseIndirectLighting = 0;
			float3 RoughSpecularIndirectLighting = 0;
			float4 SpecularIndirectLighting = 0;
			//直接从屏幕空间探针中获取数据(Lumen)
			#if DIM_APPLY_DIFFUSE_INDIRECT == DIM_APPLY_DIFFUSE_INDIRECT_SCREEN_PROBE_GATHER
				DiffuseIndirectLighting = DiffuseIndirect_Textures_0.SampleLevel(GlobalPointClampedSampler, SceneBufferUV, 0).rgb;
				RoughSpecularIndirectLighting = DiffuseIndirect_Textures_2.SampleLevel(GlobalPointClampedSampler, SceneBufferUV, 0).rgb;
				SpecularIndirectLighting = DiffuseIndirect_Textures_3.SampleLevel(GlobalPointClampedSampler, SceneBufferUV, 0).rgba;
			#else
			{
				//设置降噪器参数
				// Sample the output of the denoiser.
				FSSDKernelConfig KernelConfig = CreateKernelConfig();
				
				#if DEBUG_OUTPUT
				{
					KernelConfig.DebugPixelPosition = uint2(SvPosition.xy);
					KernelConfig.DebugEventCounter = 0;
				}
				#endif
				// Compile time.
				KernelConfig.bSampleKernelCenter = true;
				KernelConfig.BufferLayout = CONFIG_SIGNAL_INPUT_LAYOUT;
				KernelConfig.bUnroll = true;
				#if DIM_UPSCALE_DIFFUSE_INDIRECT
				{
					KernelConfig.SampleSet = SAMPLE_SET_2X2_BILINEAR;
					KernelConfig.BilateralDistanceComputation = SIGNAL_WORLD_FREQUENCY_REF_METADATA_ONLY;
					KernelConfig.WorldBluringDistanceMultiplier = 16.0;
				
					KernelConfig.BilateralSettings[0] = BILATERAL_POSITION_BASED(3);
				
					// SGPRs
					KernelConfig.BufferSizeAndInvSize = View.BufferSizeAndInvSize * float4(0.5, 0.5, 2.0, 2.0);
					KernelConfig.BufferBilinearUVMinMax = View.BufferBilinearUVMinMax;
				}
				#else
				{
					KernelConfig.SampleSet = SAMPLE_SET_1X1;
					KernelConfig.bNormalizeSample = true;
				
					// SGPRs
					KernelConfig.BufferSizeAndInvSize = View.BufferSizeAndInvSize;
					KernelConfig.BufferBilinearUVMinMax = View.BufferBilinearUVMinMax;
				}
				#endif
				// VGPRs
				KernelConfig.BufferUV = SceneBufferUV; 
				{
					// STRATA_TODO: We use the top layer data, but we should resolve lighting for each BSDFs.
					KernelConfig.CompressedRefSceneMetadata = MaterialToCompressedSceneMetadata(Material.SceneDepth, Material.WorldNormal, Material.Roughness, Material.ShadingID);
					KernelConfig.RefBufferUV = SceneBufferUV;
					KernelConfig.RefSceneMetadataLayout = METADATA_BUFFER_LAYOUT_DISABLED;
				}
				KernelConfig.HammersleySeed = Rand3DPCG16(int3(SvPosition.xy, View.StateFrameIndexMod8)).xy;
				
				FSSDSignalAccumulatorArray UncompressedAccumulators = CreateSignalAccumulatorArray();
				FSSDCompressedSignalAccumulatorArray CompressedAccumulators = CompressAccumulatorArray(
					UncompressedAccumulators, CONFIG_ACCUMULATOR_VGPR_COMPRESSION);
				AccumulateKernel(
					KernelConfig,
					DiffuseIndirect_Textures_0,
					DiffuseIndirect_Textures_1,
					DiffuseIndirect_Textures_2,
					DiffuseIndirect_Textures_3,
					/* inout */ UncompressedAccumulators,
					/* inout */ CompressedAccumulators);
				//PassDebugOutput[uint2(SvPosition.xy)] = float4(UncompressedAccumulators.Array[0].Moment1.SampleCount, 0, 0, 0);
				FSSDSignalSample Sample;
				#if DIM_UPSCALE_DIFFUSE_INDIRECT
					Sample = NormalizeToOneSample(UncompressedAccumulators.Array[0].Moment1);
				#else
					Sample = UncompressedAccumulators.Array[0].Moment1;
				#endif
				//SSGI、RTGI直接将降噪(上采样)结果赋予DiffuseIndirectLighting
				#if DIM_APPLY_DIFFUSE_INDIRECT == DIM_APPLY_DIFFUSE_INDIRECT_SSGI || DIM_APPLY_DIFFUSE_INDIRECT == DIM_APPLY_DIFFUSE_INDIRECT_RTGI
				{
					DiffuseIndirectLighting = Sample.SceneColor.rgb;
				}
				#else
					#error Unimplemented
				#endif
			}
			#endif
			#if STRATA_ENABLED
			{
				FStrataAddressing StrataAddressing = GetStrataPixelDataByteOffset(PixelPos, uint2(View.BufferSizeAndInvSize.xy), Strata.MaxBytesPerPixel);
				FStrataPixelHeader StrataPixelHeader = UnpackStrataHeaderIn(Strata.MaterialTextureArray, StrataAddressing, Strata.TopLayerTexture);
				if (StrataPixelHeader.GetMaterialMode() > HEADER_MATERIALMODE_NONE)
				{
					const FStrataDeferredLighting IndirectLighting_Strata = StrataIndirectLighting(
						PixelPos,
						Strata.MaterialTextureArray,
						StrataAddressing,
						StrataPixelHeader,
						V,
						DynamicAmbientOcclusion,
						DiffuseIndirectLighting,
						SpecularIndirectLighting);
					OutAddColor = IndirectLighting_Strata.SceneColor;
				#if STRATA_OPAQUE_ROUGH_REFRACTION_ENABLED
					const uint2 OutCoord = PixelPos;
					OutOpaqueRoughRefractionSceneColor[OutCoord] = IndirectLighting_Strata.OpaqueRoughRefractionSceneColor;
					OutSubSurfaceSceneColor[OutCoord] = IndirectLighting_Strata.SubSurfaceSceneColor;
				#endif
				}
			}
			#else // STRATA_ENABLED
			{
			FGBufferData GBuffer = Material.GBufferData;
			float3 DiffuseColor = bVisualizeDiffuseIndirect ? float3(.18f, .18f, .18f) : GBuffer.DiffuseColor;
			float3 SpecularColor = GBuffer.SpecularColor;
			#if DIM_APPLY_DIFFUSE_INDIRECT == DIM_APPLY_DIFFUSE_INDIRECT_SCREEN_PROBE_GATHER
				RemapClearCoatDiffuseAndSpecularColor(GBuffer, NoV, DiffuseColor, SpecularColor);
			#endif
			//取得AO
			FShadingOcclusion Occlusion = GetShadingOcclusion(PixelPos, V, N, GBuffer.Roughness, GBuffer.BaseColor, DynamicAmbientOcclusion);
			//对双面植被与次表面进行DiffuseOcclusion适配
			if (GBuffer.ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE || GBuffer.ShadingModelID == SHADINGMODELID_SUBSURFACE)
			{
				Occlusion.DiffuseOcclusion = lerp(1, Occlusion.DiffuseOcclusion, LumenFoliageOcclusionStrength);
			}
			//Hair需要单独处理
			if (GBuffer.ShadingModelID == SHADINGMODELID_HAIR)
			{
				float3 L = 0;
				const float3 IndirectDiffuseColor = EvaluateEnvHair(GBuffer, V, N, L /*out*/);
				IndirectLighting.Diffuse = DiffuseIndirectLighting * Occlusion.DiffuseOcclusion * IndirectDiffuseColor;
				IndirectLighting.Specular = 0;
			}
			else
			{
				float3 BackfaceDiffuseIndirectLighting = 0;
				//双面植被,计算BackfaceDiffuseIndirectLighting。如果不支持BackfaceDiffuse则将预积分结果加到DiffuseColor中。
				if (GBuffer.ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE)
				{
					float3 SubsurfaceColor = ExtractSubsurfaceColor(GBuffer);
					if (bLumenSupportBackfaceDiffuse > 0)
					{
						BackfaceDiffuseIndirectLighting += SubsurfaceColor * DiffuseIndirect_Textures_1.SampleLevel(GlobalPointClampedSampler, SceneBufferUV, 0).rgb;
					}
					else
					{
						// Adding Subsurface energy to the diffuse lobe is a poor approximation when DiffuseColor is small and SubsurfaceColor is large
						// Reduce the error by attenuating SubsurfaceColor, even though diffuse already has the 1/PI for Lambert.
						const float PreintegratedTwoSidedBxDF = 1.0f / PI;
						DiffuseColor += SubsurfaceColor * PreintegratedTwoSidedBxDF;
					}
				}
				//次表面、预积分皮肤,直接将次表面颜色加到Diffsue上。
				if (GBuffer.ShadingModelID == SHADINGMODELID_SUBSURFACE || GBuffer.ShadingModelID == SHADINGMODELID_PREINTEGRATED_SKIN)
				{
					float3 SubsurfaceColor = ExtractSubsurfaceColor(GBuffer);
					// Add subsurface energy to diffuse
					DiffuseColor += SubsurfaceColor;
				}
				//布料计算
				if (GBuffer.ShadingModelID == SHADINGMODELID_CLOTH)
				{
					float3 ClothFuzz = ExtractSubsurfaceColor(GBuffer);
					DiffuseColor += ClothFuzz * GBuffer.CustomData.a;
				}
				//最终GI结果计算
				IndirectLighting.Diffuse = (DiffuseIndirectLighting * DiffuseColor + BackfaceDiffuseIndirectLighting) * Occlusion.DiffuseOcclusion;
				IndirectLighting.Transmission = 0;
				#if DIM_APPLY_DIFFUSE_INDIRECT == DIM_APPLY_DIFFUSE_INDIRECT_SCREEN_PROBE_GATHER
					//Lumen计算的反射
					RoughSpecularIndirectLighting *= Occlusion.SpecularOcclusion;
					IndirectLighting.Specular = CombineRoughSpecular(GBuffer, HasBackfaceDiffuse(Material), NoV, SpecularIndirectLighting, RoughSpecularIndirectLighting, SpecularColor);
				#else
					//SSGI、RTGI等其他GI方法的反射结果
					IndirectLighting.Specular = AddContrastAndSpecularScale(SpecularIndirectLighting.xyz) * EnvBRDF(SpecularColor, GBuffer.Roughness, NoV);
				#endif
			}
			}
			#endif // STRATA_ENABLED
		}
		// Accumulate lighting into the final buffers
	#if !STRATA_ENABLED
		IndirectLighting.Specular *= GetSSSCheckerboadSpecularScale(PixelPos, Material.bNeedsSeparateLightAccumulation);
		FLightAccumulator LightAccumulator = (FLightAccumulator)0;
		LightAccumulator_Add(
			LightAccumulator,
			IndirectLighting.Diffuse + IndirectLighting.Specular,
			IndirectLighting.Diffuse,
			1.0f,
			Material.bNeedsSeparateLightAccumulation);
		OutAddColor = LightAccumulator_GetResult(LightAccumulator);
	#endif // !STRATA_ENABLED
	}
	#endif
	OutMultiplyColor = FinalAmbientOcclusion;
	#if !ENABLE_DUAL_SRC_BLENDING && DIM_APPLY_DIFFUSE_INDIRECT
	OutColor = SceneColor * OutMultiplyColor + OutAddColor;
	#endif
}
PS.
- 采样自DiffuseIndirect_Textures_2的RoughSpecularIndirectLighting只会用在Lumen的计算中。