12 KiB
Raw Blame History

title, date, excerpt, tags, rating
title date excerpt tags rating
ToonReflection 2025-03-20 17:04:16

反射功能相关Pass

ReflectionEnvironmentAndSky

位于IndirectLightRendering.cpp的RenderDeferredReflectionsAndSkyLighting() => AddSkyReflectionPass()

DiffuseIndirectMethod = EDiffuseIndirectMethod::Lumen也就是开启Lumen GI如果反射方法为Lumen或者SSR则不会执行后续逻辑。

不开启Lumen GI反射方法为

  • LumenRenderLumenReflections()
  • Rtx ReflectionRenderRayTracingReflections()
  • SSRScreenSpaceRayTracing::RenderScreenSpaceReflections()

RenderDeferredReflectionsAndSkyLighting()主要执行了:

  1. SkyLightDiffuse
    1. RenderDistanceFieldLighting()
      1. RenderDistanceFieldAOScreenGrid()渲染距离场AO。
      2. RenderCapsuleShadowsForMovableSkylight():渲染胶囊阴影。
  2. ReflectionIndirect
    • RenderLumenReflections()
    • RenderRayTracingReflections()
    • RenderScreenSpaceReflections()
  3. Denoise
    • DenoiserIScreenSpaceDenoiser::DenoiseReflections()
    • TemporalFilterAddTemporalAAPass()
  4. RenderDeferredPlanarReflections():合成平面反射结果。
  5. AddSkyReflectionPass()

几种反射方式的大致执行逻辑:

  • LumenReflection
    1. 输出FRDGTextureRef ReflectionsColor。
  • SSR与Rtx
    1. 输出结果到IScreenSpaceDenoiser::FReflectionsInputs DenoiserInputs的FRDGTextureRef Color。
    2. 执行对应的降噪算法。
    3. 结果赋予给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、MaxOpticalDepthMeanExtinction最终计算出体积云阴影。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

  1. 计算float3 SkyLightingNormal、FSkyLightVisibilityData SkyVisData。
  2. 计算Normal、ViewVector、NoV。
  3. 针对制定ShadingModel进行额外计算
    1. SHADINGMODELID_TWOSIDED_FOLIAGE使用Normal反向量取得SkySHDiffuse在乘以SubsurfaceColor、SkyVisData.SkyDiffuseLookUpMul后累加到结果上。
    2. SHADINGMODELID_SUBSURFACE、SHADINGMODELID_PREINTEGRATED_SKIN从GBuffer中提取SubsurfaceColor并累加到结果上。
    3. SHADINGMODELID_CLOTH从GBuffer中提取ClothFuzz(SubsurfaceColor)乘以CustomData.a并累加到结果上。
    4. SHADINGMODELID_HAIR
      1. DiffuseColor = EvaluateEnvHair(GBuffer, V, N, L);
      2. SkyVisData.SkyDiffuseLookUpNormal = L;
      3. DiffuseWeight = 1.0f;
  4. 调用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);
}

DiffuseIndirectComposite

位于IndirectLightRendering.cpp的RenderDiffuseIndirectAndAmbientOcclusion()