UE5.1移动端PreintegratedSkinBxDF解析

Part 1

头文件 MobileBasePassPixelShader.usf
主要看Main函数:

#if MOBILE_MULTI_VIEW
	ResolvedView = ResolveView(BasePassInterpolants.MultiViewId);
#else
	ResolvedView = ResolveView();
#endif

这玩意Shader文件找不到,感觉是个全局变量的东西。万幸有大佬搞出来了,具体怎么弄我也不懂==》UE4-Render-RenderPrePass-HLSL

头文件 InstancedStereo.ush

#define PrimaryView GetPrimaryView()

static ViewState ResolvedView = (ViewState)0.0f;

ViewState ResolveView()
{
	return GetPrimaryView();
}

...

#if !(COMPILER_METAL && (COMPILER_HLSLCC == 1)) && (INSTANCED_STEREO || MOBILE_MULTI_VIEW)
ViewState ResolveView(uint ViewIndex)
{
	if (ViewIndex == 0)
	{
		return GetPrimaryView();
	}
	else
	{
		return GetInstancedView();
	}
}
#endif

Part 2 ViewState

struct ViewState
{
    float4x4 TranslatedWorldToClip;
    float4x4 WorldToClip;
    float4x4 TranslatedWorldToView;
    float4x4 ViewToTranslatedWorld;
    float4x4 TranslatedWorldToCameraView;
    float4x4 CameraViewToTranslatedWorld;
    float4x4 ViewToClip;
    float4x4 ViewToClipNoAA;
    float4x4 ClipToView;
    float4x4 ClipToTranslatedWorld;
    float4x4 SVPositionToTranslatedWorld;
    float4x4 ScreenToWorld;
    float4x4 ScreenToTranslatedWorld;
    float3  ViewForward;
    float3  ViewUp;
    float3  ViewRight;
    float3  HMDViewNoRollUp;
    float3  HMDViewNoRollRight;
    float4 InvDeviceZToWorldZTransform;
    float4  ScreenPositionScaleBias;
    float3 WorldCameraOrigin;
    float3 TranslatedWorldCameraOrigin;
    float3 WorldViewOrigin;
    float3 PreViewTranslation;
    float4x4 PrevProjection;
    float4x4 PrevViewProj;
    float4x4 PrevViewRotationProj;
    float4x4 PrevViewToClip;
    float4x4 PrevClipToView;
    float4x4 PrevTranslatedWorldToClip;
    float4x4 PrevTranslatedWorldToView;
    float4x4 PrevViewToTranslatedWorld;
    float4x4 PrevTranslatedWorldToCameraView;
    float4x4 PrevCameraViewToTranslatedWorld;
    float3 PrevWorldCameraOrigin;
    float3 PrevWorldViewOrigin;
    float3 PrevPreViewTranslation;
    float4x4 PrevInvViewProj;
    float4x4 PrevScreenToTranslatedWorld;
    float4x4 ClipToPrevClip;
    float4 TemporalAAJitter;
    float4 GlobalClippingPlane;
    float2 FieldOfViewWideAngles;
    float2 PrevFieldOfViewWideAngles;
    float4  ViewRectMin;
    float4 ViewSizeAndInvSize;
    float4 BufferSizeAndInvSize;
    float4 BufferBilinearUVMinMax;
    int NumSceneColorMSAASamples;
    float  PreExposure;
    float  OneOverPreExposure;
    float4  DiffuseOverrideParameter;
    float4  SpecularOverrideParameter;
    float4  NormalOverrideParameter;
    float2  RoughnessOverrideParameter;
    float PrevFrameGameTime;
    float PrevFrameRealTime;
    float  OutOfBoundsMask;
    float3 WorldCameraMovementSinceLastFrame;
    float CullingSign;
    float  NearPlane;
    float AdaptiveTessellationFactor;
    float GameTime;
    float RealTime;
    float MaterialTextureMipBias;
    float MaterialTextureDerivativeMultiply;
    uint Random;
    uint FrameNumber;
    uint StateFrameIndexMod8;
    float  CameraCut;
    float  UnlitViewmodeMask;
    float4  DirectionalLightColor;
    float3  DirectionalLightDirection;
    float4 TranslucencyLightingVolumeMin[2];
    float4 TranslucencyLightingVolumeInvSize[2];
    float4 TemporalAAParams;
    float4 CircleDOFParams;
    float DepthOfFieldSensorWidth;
    float DepthOfFieldFocalDistance;
    float DepthOfFieldScale;
    float DepthOfFieldFocalLength;
    float DepthOfFieldFocalRegion;
    float DepthOfFieldNearTransitionRegion;
    float DepthOfFieldFarTransitionRegion;
    float MotionBlurNormalizedToPixel;
    float bSubsurfacePostprocessEnabled;
    float GeneralPurposeTweak;
    float  DemosaicVposOffset;
    float3 IndirectLightingColorScale;
    float  HDR32bppEncodingMode;
    float3 AtmosphericFogSunDirection;
    float  AtmosphericFogSunPower;
    float  AtmosphericFogPower;
    float  AtmosphericFogDensityScale;
    float  AtmosphericFogDensityOffset;
    float  AtmosphericFogGroundOffset;
    float  AtmosphericFogDistanceScale;
    float  AtmosphericFogAltitudeScale;
    float  AtmosphericFogHeightScaleRayleigh;
    float  AtmosphericFogStartDistance;
    float  AtmosphericFogDistanceOffset;
    float  AtmosphericFogSunDiscScale;
    uint AtmosphericFogRenderMask;
    uint AtmosphericFogInscatterAltitudeSampleNum;
    float4 AtmosphericFogSunColor;
    float3 NormalCurvatureToRoughnessScaleBias;
    float RenderingReflectionCaptureMask;
    float4 AmbientCubemapTint;
    float AmbientCubemapIntensity;
    float SkyLightParameters;
    float4 SkyLightColor;
    float4 SkyIrradianceEnvironmentMap[7];
    float MobilePreviewMode;
    float HMDEyePaddingOffset;
    float  ReflectionCubemapMaxMip;
    float ShowDecalsMask;
    uint DistanceFieldAOSpecularOcclusionMode;
    float IndirectCapsuleSelfShadowingIntensity;
    float3 ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight;
    int StereoPassIndex;
    float4 GlobalVolumeCenterAndExtent[4];
    float4 GlobalVolumeWorldToUVAddAndMul[4];
    float GlobalVolumeDimension;
    float GlobalVolumeTexelSize;
    float MaxGlobalDistance;
    float bCheckerboardSubsurfaceProfileRendering;
    float3 VolumetricFogInvGridSize;
    float3 VolumetricFogGridZParams;
    float2 VolumetricFogSVPosToVolumeUV;
    float VolumetricFogMaxDistance;
    float3 VolumetricLightmapWorldToUVScale;
    float3 VolumetricLightmapWorldToUVAdd;
    float3 VolumetricLightmapIndirectionTextureSize;
    float VolumetricLightmapBrickSize;
    float3 VolumetricLightmapBrickTexelSize;
    float StereoIPD;
};

Part 3 GetPrimaryView()

ViewState GetPrimaryView()
{
    ViewState Result;
    Result.TranslatedWorldToClip = View_TranslatedWorldToClip;
    Result.WorldToClip = View_WorldToClip;
    Result.TranslatedWorldToView = View_TranslatedWorldToView;
    Result.ViewToTranslatedWorld = View_ViewToTranslatedWorld;
    Result.TranslatedWorldToCameraView = View_TranslatedWorldToCameraView;
    Result.CameraViewToTranslatedWorld = View_CameraViewToTranslatedWorld;
    Result.ViewToClip = View_ViewToClip;
    Result.ViewToClipNoAA = View_ViewToClipNoAA;
    Result.ClipToView = View_ClipToView;
    Result.ClipToTranslatedWorld = View_ClipToTranslatedWorld;
    Result.SVPositionToTranslatedWorld = View_SVPositionToTranslatedWorld;
    Result.ScreenToWorld = View_ScreenToWorld;
    Result.ScreenToTranslatedWorld = View_ScreenToTranslatedWorld;
    Result.ViewForward = View_ViewForward;
    Result.ViewUp = View_ViewUp;
    Result.ViewRight = View_ViewRight;
    Result.HMDViewNoRollUp = View_HMDViewNoRollUp;
    Result.HMDViewNoRollRight = View_HMDViewNoRollRight;
    Result.InvDeviceZToWorldZTransform = View_InvDeviceZToWorldZTransform;
    Result.ScreenPositionScaleBias = View_ScreenPositionScaleBias;
    Result.WorldCameraOrigin = View_WorldCameraOrigin;
    Result.TranslatedWorldCameraOrigin = View_TranslatedWorldCameraOrigin;
    Result.WorldViewOrigin = View_WorldViewOrigin;
    Result.PreViewTranslation = View_PreViewTranslation;
    Result.PrevProjection = View_PrevProjection;
    Result.PrevViewProj = View_PrevViewProj;
    Result.PrevViewRotationProj = View_PrevViewRotationProj;
    Result.PrevViewToClip = View_PrevViewToClip;
    Result.PrevClipToView = View_PrevClipToView;
    Result.PrevTranslatedWorldToClip = View_PrevTranslatedWorldToClip;
    Result.PrevTranslatedWorldToView = View_PrevTranslatedWorldToView;
    Result.PrevViewToTranslatedWorld = View_PrevViewToTranslatedWorld;
    Result.PrevTranslatedWorldToCameraView = View_PrevTranslatedWorldToCameraView;
    Result.PrevCameraViewToTranslatedWorld = View_PrevCameraViewToTranslatedWorld;
    Result.PrevWorldCameraOrigin = View_PrevWorldCameraOrigin;
    Result.PrevWorldViewOrigin = View_PrevWorldViewOrigin;
    Result.PrevPreViewTranslation = View_PrevPreViewTranslation;
    Result.PrevInvViewProj = View_PrevInvViewProj;
    Result.PrevScreenToTranslatedWorld = View_PrevScreenToTranslatedWorld;
    Result.ClipToPrevClip = View_ClipToPrevClip;
    Result.TemporalAAJitter = View_TemporalAAJitter;
    Result.GlobalClippingPlane = View_GlobalClippingPlane;
    Result.FieldOfViewWideAngles = View_FieldOfViewWideAngles;
    Result.PrevFieldOfViewWideAngles = View_PrevFieldOfViewWideAngles;
    Result.ViewRectMin = View_ViewRectMin;
    Result.ViewSizeAndInvSize = View_ViewSizeAndInvSize;
    Result.BufferSizeAndInvSize = View_BufferSizeAndInvSize;
    Result.BufferBilinearUVMinMax = View_BufferBilinearUVMinMax;
    Result.NumSceneColorMSAASamples = View_NumSceneColorMSAASamples;
    Result.PreExposure = View_PreExposure;
    Result.OneOverPreExposure = View_OneOverPreExposure;
    Result.DiffuseOverrideParameter = View_DiffuseOverrideParameter;
    Result.SpecularOverrideParameter = View_SpecularOverrideParameter;
    Result.NormalOverrideParameter = View_NormalOverrideParameter;
    Result.RoughnessOverrideParameter = View_RoughnessOverrideParameter;
    Result.PrevFrameGameTime = View_PrevFrameGameTime;
    Result.PrevFrameRealTime = View_PrevFrameRealTime;
    Result.OutOfBoundsMask = View_OutOfBoundsMask;
    Result.WorldCameraMovementSinceLastFrame = View_WorldCameraMovementSinceLastFrame;
    Result.CullingSign = View_CullingSign;
    Result.NearPlane = View_NearPlane;
    Result.AdaptiveTessellationFactor = View_AdaptiveTessellationFactor;
    Result.GameTime = View_GameTime;
    Result.RealTime = View_RealTime;
    Result.MaterialTextureMipBias = View_MaterialTextureMipBias;
    Result.MaterialTextureDerivativeMultiply = View_MaterialTextureDerivativeMultiply;
    Result.Random = View_Random;
    Result.FrameNumber = View_FrameNumber;
    Result.StateFrameIndexMod8 = View_StateFrameIndexMod8;
    Result.CameraCut = View_CameraCut;
    Result.UnlitViewmodeMask = View_UnlitViewmodeMask;
    Result.DirectionalLightColor = View_DirectionalLightColor;
    Result.DirectionalLightDirection = View_DirectionalLightDirection;
    Result.TranslucencyLightingVolumeMin = View_TranslucencyLightingVolumeMin;
    Result.TranslucencyLightingVolumeInvSize = View_TranslucencyLightingVolumeInvSize;
    Result.TemporalAAParams = View_TemporalAAParams;
    Result.CircleDOFParams = View_CircleDOFParams;
    Result.DepthOfFieldSensorWidth = View_DepthOfFieldSensorWidth;
    Result.DepthOfFieldFocalDistance = View_DepthOfFieldFocalDistance;
    Result.DepthOfFieldScale = View_DepthOfFieldScale;
    Result.DepthOfFieldFocalLength = View_DepthOfFieldFocalLength;
    Result.DepthOfFieldFocalRegion = View_DepthOfFieldFocalRegion;
    Result.DepthOfFieldNearTransitionRegion = View_DepthOfFieldNearTransitionRegion;
    Result.DepthOfFieldFarTransitionRegion = View_DepthOfFieldFarTransitionRegion;
    Result.MotionBlurNormalizedToPixel = View_MotionBlurNormalizedToPixel;
    Result.bSubsurfacePostprocessEnabled = View_bSubsurfacePostprocessEnabled;
    Result.GeneralPurposeTweak = View_GeneralPurposeTweak;
    Result.DemosaicVposOffset = View_DemosaicVposOffset;
    Result.IndirectLightingColorScale = View_IndirectLightingColorScale;
    Result.HDR32bppEncodingMode = View_HDR32bppEncodingMode;
    Result.AtmosphericFogSunDirection = View_AtmosphericFogSunDirection;
    Result.AtmosphericFogSunPower = View_AtmosphericFogSunPower;
    Result.AtmosphericFogPower = View_AtmosphericFogPower;
    Result.AtmosphericFogDensityScale = View_AtmosphericFogDensityScale;
    Result.AtmosphericFogDensityOffset = View_AtmosphericFogDensityOffset;
    Result.AtmosphericFogGroundOffset = View_AtmosphericFogGroundOffset;
    Result.AtmosphericFogDistanceScale = View_AtmosphericFogDistanceScale;
    Result.AtmosphericFogAltitudeScale = View_AtmosphericFogAltitudeScale;
    Result.AtmosphericFogHeightScaleRayleigh = View_AtmosphericFogHeightScaleRayleigh;
    Result.AtmosphericFogStartDistance = View_AtmosphericFogStartDistance;
    Result.AtmosphericFogDistanceOffset = View_AtmosphericFogDistanceOffset;
    Result.AtmosphericFogSunDiscScale = View_AtmosphericFogSunDiscScale;
    Result.AtmosphericFogRenderMask = View_AtmosphericFogRenderMask;
    Result.AtmosphericFogInscatterAltitudeSampleNum = View_AtmosphericFogInscatterAltitudeSampleNum;
    Result.AtmosphericFogSunColor = View_AtmosphericFogSunColor;
    Result.NormalCurvatureToRoughnessScaleBias = View_NormalCurvatureToRoughnessScaleBias;
    Result.RenderingReflectionCaptureMask = View_RenderingReflectionCaptureMask;
    Result.AmbientCubemapTint = View_AmbientCubemapTint;
    Result.AmbientCubemapIntensity = View_AmbientCubemapIntensity;
    Result.SkyLightParameters = View_SkyLightParameters;
    Result.SkyLightColor = View_SkyLightColor;
    Result.SkyIrradianceEnvironmentMap = View_SkyIrradianceEnvironmentMap;
    Result.MobilePreviewMode = View_MobilePreviewMode;
    Result.HMDEyePaddingOffset = View_HMDEyePaddingOffset;
    Result.ReflectionCubemapMaxMip = View_ReflectionCubemapMaxMip;
    Result.ShowDecalsMask = View_ShowDecalsMask;
    Result.DistanceFieldAOSpecularOcclusionMode = View_DistanceFieldAOSpecularOcclusionMode;
    Result.IndirectCapsuleSelfShadowingIntensity = View_IndirectCapsuleSelfShadowingIntensity;
    Result.ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight = View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight;
    Result.StereoPassIndex = View_StereoPassIndex;
    Result.GlobalVolumeCenterAndExtent = View_GlobalVolumeCenterAndExtent;
    Result.GlobalVolumeWorldToUVAddAndMul = View_GlobalVolumeWorldToUVAddAndMul;
    Result.GlobalVolumeDimension = View_GlobalVolumeDimension;
    Result.GlobalVolumeTexelSize = View_GlobalVolumeTexelSize;
    Result.MaxGlobalDistance = View_MaxGlobalDistance;
    Result.bCheckerboardSubsurfaceProfileRendering = View_bCheckerboardSubsurfaceProfileRendering;
    Result.VolumetricFogInvGridSize = View_VolumetricFogInvGridSize;
    Result.VolumetricFogGridZParams = View_VolumetricFogGridZParams;
    Result.VolumetricFogSVPosToVolumeUV = View_VolumetricFogSVPosToVolumeUV;
    Result.VolumetricFogMaxDistance = View_VolumetricFogMaxDistance;
    Result.VolumetricLightmapWorldToUVScale = View_VolumetricLightmapWorldToUVScale;
    Result.VolumetricLightmapWorldToUVAdd = View_VolumetricLightmapWorldToUVAdd;
    Result.VolumetricLightmapIndirectionTextureSize = View_VolumetricLightmapIndirectionTextureSize;
    Result.VolumetricLightmapBrickSize = View_VolumetricLightmapBrickSize;
    Result.VolumetricLightmapBrickTexelSize = View_VolumetricLightmapBrickTexelSize;
    Result.StereoIPD = View_StereoIPD;
    return Result;
}

Part 4

没明白这个DiffuseOverrideParameter是干嘛的

#if (MATERIAL_SHADINGMODEL_SUBSURFACE || MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN || MATERIAL_SHADINGMODEL_SUBSURFACE_PROFILE || MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE || MATERIAL_SHADINGMODEL_CLOTH || MATERIAL_SHADINGMODEL_EYE) 
	if (ShadingModelID == SHADINGMODELID_SUBSURFACE || ShadingModelID == SHADINGMODELID_PREINTEGRATED_SKIN || ShadingModelID == SHADINGMODELID_SUBSURFACE_PROFILE || ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE || ShadingModelID == SHADINGMODELID_CLOTH || ShadingModelID == SHADINGMODELID_EYE)
	{
		half4 SubsurfaceData = GetMaterialSubsurfaceData(PixelMaterialInputs);

		// If the subsurface feature is disabled, the subsurface color should be black
		// This will also ensure that the subsurface profile does not contribute when subsurface scattering is disabled
		SubsurfaceData *= View.bSubsurfacePostprocessEnabled;

		if (ShadingModelID == SHADINGMODELID_SUBSURFACE || ShadingModelID == SHADINGMODELID_PREINTEGRATED_SKIN || ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE)
		{
			SubsurfaceColor = SubsurfaceData.rgb * ResolvedView.DiffuseOverrideParameter.w + ResolvedView.DiffuseOverrideParameter.xyz;
		}
		else if (ShadingModelID == SHADINGMODELID_CLOTH)
		{
			SubsurfaceColor = SubsurfaceData.rgb;
		}

		SubsurfaceProfile = SubsurfaceData.a;
	}
#endif

获取材质上的SubsurfaceColor

// .rgb:SubsurfaceColor, .a:SSProfileId in 0..1 range
half4 GetMaterialSubsurfaceDataRaw(FPixelMaterialInputs PixelMaterialInputs)
{
	return PixelMaterialInputs.Subsurface;
}

half4 GetMaterialSubsurfaceData(FPixelMaterialInputs PixelMaterialInputs)
{
	half4 OutSubsurface = GetMaterialSubsurfaceDataRaw(PixelMaterialInputs);
	OutSubsurface.rgb = saturate(OutSubsurface.rgb);
	return OutSubsurface;
}

SetGBufferForShadingModel函数:把SubsurfaceColorOpacity放进GBuffer.CustomData

SetGBufferForShadingModel(
		GBuffer,
		MaterialParameters,
		Opacity,
		BaseColor,
		Metallic,
		Specular,
		Roughness,
		Anisotropy,
		SubsurfaceColor,
		SubsurfaceProfile,
		0.0f,
		ShadingModelID
	);
	
···

#if MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN
	else if (ShadingModel == SHADINGMODELID_PREINTEGRATED_SKIN)
	{
		GBuffer.CustomData.rgb = EncodeSubsurfaceColor(SubsurfaceColor);
		GBuffer.CustomData.a = Opacity;
	}
#endif

···

float3 EncodeSubsurfaceColor(float3 SubsurfaceColor)
{
	return sqrt(saturate(SubsurfaceColor));
}

计算GBuffer.SpecularColorGBuffer.DiffuseColor

#if NONMETAL
	GBuffer.DiffuseColor = GBuffer.BaseColor;
	GBuffer.SpecularColor = 0.04;
#else
	GBuffer.SpecularColor = ComputeF0(GBuffer.Specular, GBuffer.BaseColor, GBuffer.Metallic);
	GBuffer.DiffuseColor = GBuffer.BaseColor - GBuffer.BaseColor * GBuffer.Metallic;
#endif

这个MOBILE_EMULATION宏的意思是移动模拟?只在开发中用到?

#if MOBILE_EMULATION && !MOBILE_DEFERRED_LIGHTING
	{
		// this feature is only needed for development/editor - we can compile it out for a shipping build (see r.CompileShadersForDevelopment cvar help)
		GBuffer.DiffuseColor = GBuffer.DiffuseColor * ResolvedView.DiffuseOverrideParameter.w + ResolvedView.DiffuseOverrideParameter.xyz;
		GBuffer.SpecularColor = GBuffer.SpecularColor * ResolvedView.SpecularOverrideParameter.w + ResolvedView.SpecularOverrideParameter.xyz;
	}
#endif

SubsurfaceColor加到间接漫反射上

	half IndirectIrradiance = 0;
	half3 DiffuseIndirectLighting = 0;
	half3 SubsurfaceIndirectLighting = 0;

	half3 DiffuseColorForIndirect = GBuffer.DiffuseColor;
	half3 DiffuseDir = ShadingOcclusion.BentNormal;

#if MATERIAL_SHADINGMODEL_SUBSURFACE || MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN
	if (GBuffer.ShadingModelID == SHADINGMODELID_SUBSURFACE || GBuffer.ShadingModelID == SHADINGMODELID_PREINTEGRATED_SKIN)
	{
		// Add subsurface energy to diffuse
		//@todo - better subsurface handling for these shading models with skylight and precomputed GI
		
		DiffuseColorForIndirect += SubsurfaceColor;
	}
#endif

获取预计算间接光照和天光

GetPrecomputedIndirectLightingAndSkyLight(LightmapVTPageTableResult, 
	Interpolants, bEvaluateBackface, DiffuseDir, bApplySkyLighting, ResolvedView.SkyLightColor.rgb, 	
	DiffuseIndirectLighting, SubsurfaceIndirectLighting, IndirectIrradiance, WaterDiffuseIndirectLuminance);

Part 5

DiffuseColor

	// Apply MaterialAO since we don't have the DiffuseIndirectComposite pass on mobile deferred.
	IndirectIrradiance *= GBuffer.GBufferAO;

	half3 DiffuseColor = (DiffuseIndirectLighting * DiffuseColorForIndirect + SubsurfaceIndirectLighting * 	
		SubsurfaceColor) * AOMultiBounce(GBuffer.BaseColor, ShadingOcclusion.DiffOcclusion);

····

// [ Jimenez et al. 2016, "Practical Realtime Strategies for Accurate Indirect Occlusion" ]
half3 AOMultiBounce(half3 BaseColor, half AO)
{
	if (SHADING_PATH_MOBILE && !MOBILE_HIGH_QUALITY_BRDF)
	{
		return AO;
	}
	else
	{
		half3 a = 2.0404 * BaseColor - 0.3324;
		half3 b = -4.7951 * BaseColor + 0.6417;
		half3 c = 2.7552 * BaseColor + 0.6903;
		return max(AO, ((AO * a + b) * AO + c) * AO);
	}
}

计算总光照和烘焙阴影

FLightAccumulator DirectLighting = (FLightAccumulator)0;
LightAccumulator_AddSplit(DirectLighting, DiffuseColor, 0.0f, DiffuseColor, 1.0f, false);

GBuffer.PrecomputedShadowFactors = GetPrimaryPrecomputedShadowMask(LightmapVTPageTableResult, Interpolants,
	MaterialParameters);

···

void LightAccumulator_AddSplit(inout FLightAccumulator In, float3 DiffuseTotalLight, float3 SpecularTotalLight, 
		float3 ScatterableLight, float3 CommonMultiplier, const bool bNeedsSeparateSubsurfaceLightAccumulation)
{
	// 3 mad
	In.TotalLight += (DiffuseTotalLight + SpecularTotalLight) * CommonMultiplier;

	// This should ideally be evaluated statically outside of this function to avoid the branch
	if (bNeedsSeparateSubsurfaceLightAccumulation)
	{
		if (SUBSURFACE_CHANNEL_MODE == 1)
		{
			if (View.bCheckerboardSubsurfaceProfileRendering == 0)
			{
				In.ScatterableLightLuma += Luminance(ScatterableLight * CommonMultiplier);
			}
		}
		else if (SUBSURFACE_CHANNEL_MODE == 2)
		{
			// 3 mad
			In.ScatterableLight += ScatterableLight * CommonMultiplier;
		}
	}

	In.TotalLightDiffuse += DiffuseTotalLight * CommonMultiplier;
	In.TotalLightSpecular += SpecularTotalLight * CommonMultiplier;
}

···

// Used by mobile renderer only
half4 GetPrimaryPrecomputedShadowMask(VTPageTableResult LightmapVTPageTableResult, 
			FVertexFactoryInterpolantsVSToPS Interpolants, FMaterialPixelParameters MaterialParameters)
{
	#if STATICLIGHTING_TEXTUREMASK && STATICLIGHTING_SIGNEDDISTANCEFIELD

		LightmapUVType ShadowMapCoordinate;
		uint LightmapDataIndex;
		GetShadowMapCoordinate(Interpolants, ShadowMapCoordinate, LightmapDataIndex);

		// Fetch the distance field data
		#if LIGHTMAP_VT_ENABLED
			half4 DistanceField = SampleLightmapVT(LightmapVTPageTableResult, 2u, LightmapDataIndex, LightmapResourceCluster.VTStaticShadowTexture, LightmapResourceCluster.StaticShadowTextureSampler);
		#else
			half4 DistanceField = Texture2DSample(LightmapResourceCluster.StaticShadowTexture, LightmapResourceCluster.StaticShadowTextureSampler, ShadowMapCoordinate);
		#endif
		float4 InvUniformPenumbraSizes = GetLightmapData(LightmapDataIndex).InvUniformPenumbraSizes;
		float4 DistanceFieldBias = -.5f * InvUniformPenumbraSizes + .5f;
		// Compute shadow factors by scaling and biasing the distance
		half4 ShadowFactor = saturate( DistanceField * InvUniformPenumbraSizes + DistanceFieldBias );
		return GetLightmapData(LightmapDataIndex).StaticShadowMapMasks * ShadowFactor * ShadowFactor;
	#elif MOVABLE_DIRECTIONAL_LIGHT
		// Do this before checking for lightmaps as we might have a lightmap + movable directional light
		return 1.0f;
	#elif HQ_TEXTURE_LIGHTMAP || LQ_TEXTURE_LIGHTMAP
		// Mark as shadowed for lightmapped objects with no shadowmap
		// This is necessary because objects inside a light's influence that were determined to be completely shadowed won't be rendered with STATICLIGHTING_TEXTUREMASK==1
		return 0.0f;
	#else
		#if CACHED_POINT_INDIRECT_LIGHTING || CACHED_VOLUME_INDIRECT_LIGHTING
			// output per-primitive directional light shadowing if requested
			if ((GetPrimitiveData(MaterialParameters).Flags & PRIMITIVE_SCENE_DATA_FLAG_USE_SINGLE_SAMPLE_SHADOW_SL) != 0 && ResolvedView.IndirectLightingCacheShowFlag > 0.0f)
			{
				return half4(IndirectLightingCache.DirectionalLightShadowing, 1, 1, 1);
			}
		#endif
	#endif

	return 1.0f;
}

···

void GetShadowMapCoordinate(FVertexFactoryInterpolantsVSToPS Interpolants, out float2 ShadowMapCoordinate, out uint LightmapDataIndex)
{
	ShadowMapCoordinate = Interpolants.ShadowMapCoordinate;
	
#if VF_USE_PRIMITIVE_SCENE_DATA
	LightmapDataIndex = GetPrimitiveData(Interpolants.PrimitiveId).LightmapDataIndex;
#else
	LightmapDataIndex = 0;
#endif

}
#endif

Lightmap相关==>LightmapData.ush


// Must match FPrecomputedLightingUniformParameters in C++
struct FLightmapSceneData
{
	float4 StaticShadowMapMasks;
	float4 InvUniformPenumbraSizes;
	float4 LightMapCoordinateScaleBias;
	float4 ShadowMapCoordinateScaleBias;
	float4 LightMapScale[2];
	float4 LightMapAdd[2];
	uint4 LightmapVTPackedPageTableUniform[2];
	uint4 LightmapVTPackedUniform[5];
};

// Stride of a single lightmap data entry in float4's, must match C++
#define LIGHTMAP_SCENE_DATA_STRIDE 15

#if USE_GLOBAL_GPU_LIGHTMAP_DATA
StructuredBuffer<float4> GPUSceneLightmapData;
#endif

float4 LoadLightmapDataElement(uint Index)
{
#if USE_GLOBAL_GPU_LIGHTMAP_DATA
	checkStructuredBufferAccessSlow(GPUSceneLightmapData, Index);
	return GPUSceneLightmapData[Index];
#else
	checkStructuredBufferAccessSlow(View.LightmapSceneData, Index);
	return View.LightmapSceneData[Index];
#endif
}

// Fetch from scene lightmap data buffer
FLightmapSceneData GetLightmapData(uint LightmapDataIndex) 
{
	// Note: layout must match FLightmapSceneShaderData in C++
	// Relying on optimizer to remove unused loads

	FLightmapSceneData LightmapData;
	uint LightmapDataBaseOffset = LightmapDataIndex * LIGHTMAP_SCENE_DATA_STRIDE;
	LightmapData.StaticShadowMapMasks = LoadLightmapDataElement(LightmapDataBaseOffset + 0);
	LightmapData.InvUniformPenumbraSizes = LoadLightmapDataElement(LightmapDataBaseOffset + 1);
	LightmapData.LightMapCoordinateScaleBias = LoadLightmapDataElement(LightmapDataBaseOffset + 2);
	LightmapData.ShadowMapCoordinateScaleBias = LoadLightmapDataElement(LightmapDataBaseOffset + 3);
	LightmapData.LightMapScale[0] = LoadLightmapDataElement(LightmapDataBaseOffset + 4);
	LightmapData.LightMapScale[1] = LoadLightmapDataElement(LightmapDataBaseOffset + 5);
	LightmapData.LightMapAdd[0] = LoadLightmapDataElement(LightmapDataBaseOffset + 6);
	LightmapData.LightMapAdd[1] = LoadLightmapDataElement(LightmapDataBaseOffset + 7);
	LightmapData.LightmapVTPackedPageTableUniform[0] = asuint(LoadLightmapDataElement(LightmapDataBaseOffset + 8));
	LightmapData.LightmapVTPackedPageTableUniform[1] = asuint(LoadLightmapDataElement(LightmapDataBaseOffset + 9));

	UNROLL
	for (uint i = 0u; i < 5u; ++i)
	{
		LightmapData.LightmapVTPackedUniform[i] = asuint(LoadLightmapDataElement(LightmapDataBaseOffset + 10 + i));
	}

	return LightmapData;
}

Part 6

动态光照

half4 DynamicShadowFactors = 1.0f;
float DirectionalLightShadow = 1.0f;

// Directional light
AccumulateDirectionalLighting(GBuffer, MaterialParameters.WorldPosition_CamRelative, CameraVector, 
		MaterialParameters.ScreenPosition, SvPosition, DynamicShadowFactors, DirectionalLightShadow, 	
		DirectLighting);

MobileLightingCommon.ush

void AccumulateDirectionalLighting(FGBufferData GBuffer, float3 TranslatedWorldPosition, half3 CameraVector, 
	float4 ScreenPosition, float4 SvPosition, inout half4 DynamicShadowFactors, inout float OutDirectionalLightShadow, 
	inout FLightAccumulator DirectLighting)
{
#if USE_SHADOWMASKTEXTURE
	half4 PreviewShadowMapChannelMask = half4(1.0f, 0.0f, 0.0f, 0.0f);
	DynamicShadowFactors = Texture2DSample(MobileBasePass.ScreenSpaceShadowMaskTexture, 
			MobileBasePass.ScreenSpaceShadowMaskSampler, SvPositionToBufferUV(SvPosition));
	DynamicShadowFactors = DecodeLightAttenuation(DynamicShadowFactors);
		
	PreviewShadowMapChannelMask = UnpackShadowMapChannelMask(MobileDirectionalLight.DirectionalLightShadowMapChannelMask >> 4);

	half DynamicShadowing = dot(PreviewShadowMapChannelMask, DynamicShadowFactors);
#else

	float  ShadowPositionZ = 0;
	half ShadowMap = MobileDirectionalLightCSM(ScreenPosition.xy, ScreenPosition.w, ShadowPositionZ);
	half DynamicShadowing = 1.0f;

	#if !MOBILE_DEFERRED_SHADING && DIRECTIONAL_LIGHT_CSM && !MATERIAL_SHADINGMODEL_SINGLELAYERWATER
		// Cascaded Shadow Map
		if (IsCSMEnabled())
		{		
			DynamicShadowing = ShadowMap;
		}
	#elif MOBILE_DEFERRED_SHADING
		DynamicShadowing = ShadowMap;
	#endif
#endif

	FDeferredLightData LightData = (FDeferredLightData)0;
	LightData.Color = MobileDirectionalLight.DirectionalLightColor.rgb;
	LightData.FalloffExponent = 0;
	LightData.Direction = MobileDirectionalLight.DirectionalLightDirectionAndShadowTransition.xyz;
	LightData.bRadialLight = false;
	LightData.SpecularScale = MobileDirectionalLight.DirectionalLightDistanceFadeMADAndSpecularScale.z;
	LightData.ShadowedBits = 1;
	LightData.HairTransmittance = InitHairTransmittanceData();
	LightData.ShadowMapChannelMask = UnpackShadowMapChannelMask(MobileDirectionalLight.DirectionalLightShadowMapChannelMask);

	half4 LightAttenuation = half4(1, 1, DynamicShadowing, DynamicShadowing);

	FLightAccumulator NewLighting = AccumulateDynamicLighting(TranslatedWorldPosition, CameraVector, GBuffer, 1, 
			GBuffer.ShadingModelID, LightData, LightAttenuation, 0, uint2(0, 0), OutDirectionalLightShadow);
	DirectLighting = LightAccumulator_Add(DirectLighting, NewLighting);
}

···
FLightAccumulator LightAccumulator_Add(FLightAccumulator A, FLightAccumulator B)
{
	FLightAccumulator Sum = (FLightAccumulator)0;
	Sum.TotalLight = A.TotalLight + B.TotalLight;
	Sum.ScatterableLightLuma = A.ScatterableLightLuma + B.ScatterableLightLuma;
	Sum.ScatterableLight = A.ScatterableLight + B.ScatterableLight;
	Sum.EstimatedCost = A.EstimatedCost + B.EstimatedCost;
	Sum.TotalLightDiffuse = A.TotalLightDiffuse + B.TotalLightDiffuse;
	Sum.TotalLightSpecular = A.TotalLightSpecular + B.TotalLightSpecular;
	return Sum;
}

DeferredLightingCommon.ush
这里进入BXDF

FLightAccumulator AccumulateDynamicLighting(
	float3 TranslatedWorldPosition, half3 CameraVector, FGBufferData GBuffer, half AmbientOcclusion, uint ShadingModelID,
	FDeferredLightData LightData, half4 LightAttenuation, float Dither, uint2 SVPos, 
	inout float SurfaceShadow)
{
	···
	#if SHADING_PATH_MOBILE
		const bool bNeedsSeparateSubsurfaceLightAccumulation = UseSubsurfaceProfile(GBuffer.ShadingModelID);
		
		FDirectLighting Lighting = (FDirectLighting)0;

		half NoL = max(0, dot(GBuffer.WorldNormal, L));
	#if TRANSLUCENCY_NON_DIRECTIONAL
		NoL = 1.0f;
	#endif
		Lighting = EvaluateBxDF(GBuffer, N, V, L, NoL, Shadow);

		Lighting.Specular *= LightData.SpecularScale;
				
		LightAccumulator_AddSplit( LightAccumulator, Lighting.Diffuse, Lighting.Specular, Lighting.Diffuse, MaskedLightColor * 
			Shadow.SurfaceShadow, bNeedsSeparateSubsurfaceLightAccumulation );
		LightAccumulator_AddSplit( LightAccumulator, Lighting.Transmission, 0.0f, Lighting.Transmission, MaskedLightColor * 
			Shadow.TransmissionShadow, bNeedsSeparateSubsurfaceLightAccumulation );
	#else // SHADING_PATH_MOBILE
	···
}

ShadingModels.ush

FDirectLighting PreintegratedSkinBxDF( FGBufferData GBuffer, half3 N, half3 V, half3 L, float Falloff, half NoL, FAreaLight AreaLight, FShadowTerms Shadow )
{
	FDirectLighting Lighting = DefaultLitBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
	
	half3 SubsurfaceColor = ExtractSubsurfaceColor(GBuffer);
	half Opacity = GBuffer.CustomData.a;

	half3 PreintegratedBRDF = Texture2DSampleLevel(View.PreIntegratedBRDF, View.PreIntegratedBRDFSampler, float2(saturate(dot(N, L) * .5 + .5), 1 - Opacity), 0).rgb;
	Lighting.Transmission = AreaLight.FalloffColor * Falloff * PreintegratedBRDF * SubsurfaceColor;

	return Lighting;
}

FDirectLighting IntegrateBxDF( FGBufferData GBuffer, half3 N, half3 V, half3 L, float Falloff, half NoL, FAreaLight AreaLight, FShadowTerms Shadow )
{
	switch( GBuffer.ShadingModelID )
	{
		case SHADINGMODELID_DEFAULT_LIT:
		case SHADINGMODELID_SINGLELAYERWATER:
		case SHADINGMODELID_THIN_TRANSLUCENT:
			return DefaultLitBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		case SHADINGMODELID_SUBSURFACE:
			return SubsurfaceBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		case SHADINGMODELID_PREINTEGRATED_SKIN:
			return PreintegratedSkinBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		case SHADINGMODELID_CLEAR_COAT:
			return ClearCoatBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		case SHADINGMODELID_SUBSURFACE_PROFILE:
			return SubsurfaceProfileBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		case SHADINGMODELID_TWOSIDED_FOLIAGE:
			return TwoSidedBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		case SHADINGMODELID_HAIR:
			return HairBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		case SHADINGMODELID_CLOTH:
			return ClothBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		case SHADINGMODELID_EYE:
			return EyeBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		default:
			return (FDirectLighting)0;
	}
}

FDirectLighting EvaluateBxDF( FGBufferData GBuffer, half3 N, half3 V, half3 L, float NoL, FShadowTerms Shadow )
{
	FAreaLight AreaLight;
	AreaLight.SphereSinAlpha = 0;
	AreaLight.SphereSinAlphaSoft = 0;
	AreaLight.LineCosSubtended = 1;
	AreaLight.FalloffColor = 1;
	AreaLight.Rect = (FRect)0;
	AreaLight.IsRectAndDiffuseMicroReflWeight = 0;
	AreaLight.Texture = InitRectTexture();

	return IntegrateBxDF( GBuffer, N, V, L, 1, NoL, AreaLight, Shadow );
}

最后走的还是 DefaultLitBxDF

FDirectLighting DefaultLitBxDF( FGBufferData GBuffer, half3 N, half3 V, half3 L, float Falloff, half NoL, FAreaLight AreaLight, FShadowTerms Shadow )
{
	BxDFContext Context;
	FDirectLighting Lighting;

#if SUPPORTS_ANISOTROPIC_MATERIALS
	bool bHasAnisotropy = HasAnisotropy(GBuffer.SelectiveOutputMask);
#else
	bool bHasAnisotropy = false;
#endif

	float NoV, VoH, NoH;
	BRANCH
	if (bHasAnisotropy)
	{
		half3 X = GBuffer.WorldTangent;
		half3 Y = normalize(cross(N, X));
		Init(Context, N, X, Y, V, L);

		NoV = Context.NoV;
		VoH = Context.VoH;
		NoH = Context.NoH;
	}
	else
	{
#if SHADING_PATH_MOBILE
		InitMobile(Context, N, V, L, NoL);
#else
		Init(Context, N, V, L);
#endif

		NoV = Context.NoV;
		VoH = Context.VoH;
		NoH = Context.NoH;

		SphereMaxNoH(Context, AreaLight.SphereSinAlpha, true);
	}

	Context.NoV = saturate(abs( Context.NoV ) + 1e-5);

#if MATERIAL_ROUGHDIFFUSE
	// Chan diffuse model with roughness == specular roughness. This is not necessarily a good modelisation of reality because when the mean free path is super small, the diffuse can in fact looks rougher. But this is a start.
	// Also we cannot use the morphed context maximising NoH as this is causing visual artefact when interpolating rough/smooth diffuse response. 
	Lighting.Diffuse = Diffuse_Chan(GBuffer.DiffuseColor, Pow4(GBuffer.Roughness), NoV, NoL, VoH, NoH, GetAreaLightDiffuseMicroReflWeight(AreaLight));
#else
	Lighting.Diffuse = Diffuse_Lambert(GBuffer.DiffuseColor);
#endif
	Lighting.Diffuse *= AreaLight.FalloffColor * (Falloff * NoL);

	BRANCH
	if (bHasAnisotropy)
	{
		//Lighting.Specular = GBuffer.WorldTangent * .5f + .5f;
		Lighting.Specular = AreaLight.FalloffColor * (Falloff * NoL) * SpecularGGX(GBuffer.Roughness, GBuffer.Anisotropy, GBuffer.SpecularColor, Context, NoL, AreaLight);
	}
	else
	{
		if( IsRectLight(AreaLight) )
		{
			Lighting.Specular = RectGGXApproxLTC(GBuffer.Roughness, GBuffer.SpecularColor, N, V, AreaLight.Rect, AreaLight.Texture);
		}
		else
		{
			Lighting.Specular = AreaLight.FalloffColor * (Falloff * NoL) * SpecularGGX(GBuffer.Roughness, GBuffer.SpecularColor, Context, NoL, AreaLight);
		}
	}

	FBxDFEnergyTerms EnergyTerms = ComputeGGXSpecEnergyTerms(GBuffer.Roughness, Context.NoV, GBuffer.SpecularColor);

	// Add energy presevation (i.e. attenuation of the specular layer onto the diffuse component
	Lighting.Diffuse *= ComputeEnergyPreservation(EnergyTerms);

	// Add specular microfacet multiple scattering term (energy-conservation)
	Lighting.Specular *= ComputeEnergyConservation(EnergyTerms);

	Lighting.Transmission = 0;
	return Lighting;
}

SpecularGGX

float3 SpecularGGX( float Roughness, float3 SpecularColor, BxDFContext Context, half NoL, FAreaLight AreaLight )
{
	float a2 = Pow4( Roughness );
	//EnergyNormalization感觉涉及到AreaLight暂时忽略
	float Energy = EnergyNormalization( a2, Context.VoH, AreaLight );
	
#if SHADING_PATH_MOBILE
	half D = GGX_Mobile(Roughness, Context.NoH) * Energy;
	return MobileSpecularGGXInner(D, SpecularColor, Roughness, Context.NoV, NoL, Context.VoH, MOBILE_HIGH_QUALITY_BRDF);
#else
	// Generalized microfacet specular
	float D = D_GGX( a2, Context.NoH ) * Energy;
	float Vis = Vis_SmithJointApprox( a2, Context.NoV, NoL );
	float3 F = F_Schlick( SpecularColor, Context.VoH );

	return (D * Vis) * F;
#endif
}

···

half GGX_Mobile(half Roughness, float NoH)
{
    // Walter et al. 2007, "Microfacet Models for Refraction through Rough Surfaces"
	float OneMinusNoHSqr = 1.0 - NoH * NoH; 
	half a = Roughness * Roughness;
	half n = NoH * a;
	half p = a / (OneMinusNoHSqr + n * n);
	half d = p * p;
	// clamp to avoid overlfow in a bright env
	return min(d, 2048.0);
}

···

half3 MobileSpecularGGXInner(half D, half3 SpecularColor, half Roughness, half NoV, half NoL, half VoH, bool bHighQualityBRDF)
{
	half Vis = (Roughness * 0.25 + 0.25);
	half3 F = GetEnvBRDF(SpecularColor, Roughness, NoV);
	
	//使用高质量计算完整的G(几何函数)项和F项
	if (bHighQualityBRDF)
	{
		Vis = saturate(Vis_SmithJointApprox(Roughness * Roughness * Roughness * Roughness, NoV, NoL));
		F = F_Schlick(SpecularColor, VoH);
	}

	return (D * Vis) * F;
}

使用高质量计算完整的G(几何函数)项和F项

看看EnvBRDF

half3 GetEnvBRDF(half3 SpecularColor, half Roughness, half NoV)
{
#if FULLY_ROUGH
	return 0.0f;
#elif MOBILE_USE_PREINTEGRATED_GF
	return EnvBRDF(SpecularColor, Roughness, NoV);
#elif NONMETAL
	// If nothing is hooked up to Metalic and Specular,
	// then defaults are the same as a non-metal,
	// so this define is safe.
	return EnvBRDFApproxNonmetal(Roughness, NoV).xxx;
#else
	return EnvBRDFApprox(SpecularColor, Roughness, NoV);
#endif
}

···

half2 EnvBRDFApproxLazarov(half Roughness, half NoV)
{
	// [ Lazarov 2013, "Getting More Physical in Call of Duty: Black Ops II" ]
	// Adaptation to fit our G term.
	const half4 c0 = { -1, -0.0275, -0.572, 0.022 };
	const half4 c1 = { 1, 0.0425, 1.04, -0.04 };
	half4 r = Roughness * c0 + c1;
	half a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y;
	half2 AB = half2(-1.04, 1.04) * a004 + r.zw;
	return AB;
}

half3 EnvBRDFApprox( half3 SpecularColor, half Roughness, half NoV )
{
	half2 AB = EnvBRDFApproxLazarov(Roughness, NoV);

	// Anything less than 2% is physically impossible and is instead considered to be shadowing
	// Note: this is needed for the 'specular' show flag to work, since it uses a SpecularColor of 0
	float F90 = saturate( 50.0 * SpecularColor.g );

	return SpecularColor * AB.x + F90 * AB.y;
}

前向渲染正常走的是EnvBRDFApprox除非勾了材质里的简单IBL的预整合GF。
UE5.1移动端PreintegratedSkinBxDF解析_第1张图片

Part 7

SpecularIBL
MATERIALBLENDING_SOLID对应的是Opaque Mode

#if MATERIALBLENDING_MASKED || MATERIALBLENDING_SOLID || TRANSLUCENCY_LIGHTING_SURFACE_FORWARDSHADING || MATERIAL_SHADINGMODEL_SINGLELAYERWATER
	// Reflection IBL
	AccumulateReflection(GBuffer
		, CameraVector
		, MaterialParameters.WorldPosition_CamRelative
		, MaterialParameters.ReflectionVector
		, IndirectIrradiance
		, GridIndex
		, DirectLighting);
#endif

AccumulateReflection

void AccumulateReflection(FGBufferData GBuffer
	, half3 CameraVector
	, float3 TranslatedWorldPosition
	, half3 ReflectionVector
	, half IndirectIrradiance
	, uint GridIndex
	, inout FLightAccumulator DirectLighting)
{
	half3 SpecularIBLLighting = (half3)0.0f;

	half3 N = GBuffer.WorldNormal;
	half3 V = -CameraVector;
	half NoV = saturate(abs(dot(N, V)) + 1e-5);

	half3 TopLayerR = ReflectionVector;
	half SpecularOcclusion = GBuffer.GBufferAO;
	if (MOBILE_HIGH_QUALITY_BRDF)
	{
		// Point lobe in off-specular peak direction
		ReflectionVector = GetOffSpecularPeakReflectionDir(N, ReflectionVector, GBuffer.Roughness);

		half RoughnessSq = GBuffer.Roughness * GBuffer.Roughness;
		SpecularOcclusion = GetSpecularOcclusion(NoV, RoughnessSq, SpecularOcclusion);
	}

	half3 SpecularIBL = GetImageBasedReflectionLighting(ReflectionVector
		, TranslatedWorldPosition
		, GBuffer.Roughness
		, IndirectIrradiance
		, SpecularOcclusion
		, GridIndex
	);

#if ENABLE_PLANAR_REFLECTION || MATERIAL_PLANAR_FORWARD_REFLECTIONS
	BRANCH
	if (abs(dot(PlanarReflectionStruct.ReflectionPlane.xyz, 1)) > .0001f)
	{
		half4 PlanarReflection = GetPlanarReflection(TranslatedWorldPosition, GBuffer.WorldNormal, GBuffer.Roughness);
		// Planar reflections win over reflection environment
		SpecularIBL = lerp(SpecularIBL, PlanarReflection.rgb, PlanarReflection.a);
	}
#endif

	half3 DiffuseColor = GBuffer.DiffuseColor;
	half3 SpecularColor = GBuffer.SpecularColor;

	if (GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT)
	{
		//省略部分代码
		···
	}
	else if (GBuffer.ShadingModelID == SHADINGMODELID_HAIR)
	{
		//Skip IBL for Hair
	}
	else
	{
		SpecularIBLLighting += SpecularIBL * GetEnvBRDF(SpecularColor, GBuffer.Roughness, NoV);
	}
	LightAccumulator_AddSplit(DirectLighting, 0.0f, SpecularIBLLighting, 0.0f, 1.0f, false);
}

GetImageBasedReflectionLightingGetMobileSkyLightReflection

#if IS_MOBILE_BASE_PASS
/** Prenormalized capture of the scene that's closest to the object being rendered. */
half3 GetMobileSkyLightReflection(half3 ReflectionVector, half Roughness, half CubemapMaxMip)
{
	half AbsoluteSpecularMip = ComputeReflectionCaptureMipFromRoughness(Roughness, CubemapMaxMip);
	half4 Reflection = MobileReflectionCapture.Texture.SampleLevel(MobileReflectionCapture.TextureSampler, ReflectionVector, AbsoluteSpecularMip);
	return Reflection.rgb * ResolvedView.SkyLightColor.rgb;
}
#endif

half3 GetImageBasedReflectionLighting(half3 ReflectionVector
	, float3 TranslatedWorldPosition
	, half Roughness
	, half IndirectIrradiance
	, half CompositeAlpha
	, uint GridIndex
)
{
	half3 SpecularIBL = (half3)0.0f;

#if ENABLE_CLUSTERED_REFLECTION //混合多个Cubemap光照,好像移动端并没有这个功能
 	uint NumCulledEntryIndex = (ForwardLightData.NumGridCells + GridIndex) * NUM_CULLED_LIGHTS_GRID_STRIDE;
	uint NumLocalReflectionCaptures = min(ForwardLightData.NumCulledLightsGrid[NumCulledEntryIndex + 0], ForwardLightData.NumReflectionCaptures);
	uint DataStartIndex = ForwardLightData.NumCulledLightsGrid[NumCulledEntryIndex + 1];

	SpecularIBL = CompositeReflectionCapturesAndSkylightTWS(
		CompositeAlpha,
		TranslatedWorldPosition,
		ReflectionVector,//RayDirection,
		Roughness,
		IndirectIrradiance,
		1.0f,
		0.0f,
		NumLocalReflectionCaptures,
		DataStartIndex,
		0,
		true);
#elif MOBILE_DEFERRED_LIGHTING
	float SkyAverageBrightness = 1.0f;
	SpecularIBL = GetSkyLightReflection(ReflectionVector, Roughness, SkyAverageBrightness);
	
	#if ALLOW_STATIC_LIGHTING
	SpecularIBL *= ComputeMixingWeight(IndirectIrradiance, SkyAverageBrightness, Roughness);
	#endif

	SpecularIBL *= CompositeAlpha;
#else // !(ENABLE_CLUSTERED_REFLECTION || MOBILE_DEFERRED_LIGHTING)

	half UsingSkyReflection = MobileReflectionCapture.Params.y > 0.0f;
	if (UsingSkyReflection)
	{
		// Apply sky colour if the reflection map is the sky.
		SpecularIBL = GetMobileSkyLightReflection(ReflectionVector, Roughness, MobileReflectionCapture.Params.y);
	}
	else
	{
		half AbsoluteSpecularMip = ComputeReflectionCaptureMipFromRoughness(Roughness, ResolvedView.ReflectionCubemapMaxMip);
		SpecularIBL = MobileReflectionCapture.Texture.SampleLevel(MobileReflectionCapture.TextureSampler, ReflectionVector, AbsoluteSpecularMip).rgb;

		half ReflectionCaptureBrightness = MobileReflectionCapture.Params.w;
		SpecularIBL = SpecularIBL * ReflectionCaptureBrightness;
	}

	#if ALLOW_STATIC_LIGHTING
	SpecularIBL *= ComputeMixingWeight(IndirectIrradiance, MobileReflectionCapture.Params.x, Roughness);
	#endif

	SpecularIBL *= CompositeAlpha;
#endif

	return SpecularIBL;
}

AccumulateReflection函数之后MobileBasePassPixelShader.usf就没有光照计算的的代码了

#if !MATERIAL_SHADINGMODEL_UNLIT
	half3 Color = DirectLighting.TotalLight;
#else
	half3 Color = 0.0f;
#endif

其实只看LightAccumulator_AddSplitLightAccumulator_Add就可大概了解光照的流程了。
第一次是DiffuseColor

LightAccumulator_AddSplit(DirectLighting, DiffuseColor, 0.0f, DiffuseColor, 1.0f, false);

第二和第三次是BXDF之后:

LightAccumulator_AddSplit( LightAccumulator, Lighting.Diffuse, Lighting.Specular, Lighting.Diffuse, MaskedLightColor * 
			Shadow.SurfaceShadow, bNeedsSeparateSubsurfaceLightAccumulation );
LightAccumulator_AddSplit( LightAccumulator, Lighting.Transmission, 0.0f, Lighting.Transmission, MaskedLightColor * 
			Shadow.TransmissionShadow, bNeedsSeparateSubsurfaceLightAccumulation );
//PreintegratedSkinBxDF
//Lighting.Transmission = AreaLight.FalloffColor * Falloff * PreintegratedBRDF * SubsurfaceColor;

LightAccumulator_AddDiffuseColorBXDF相加:

DirectLighting = LightAccumulator_Add(DirectLighting, NewLighting);

第四次是把SpecularIBLLighting加上:

LightAccumulator_AddSplit(DirectLighting, 0.0f, SpecularIBLLighting, 0.0f, 1.0f, false);

以上,完。

你可能感兴趣的:(UE5,ue5,移动端,皮肤,预计分皮肤)