direction light

[mobile]

  • MobileGGX.ush
  • MobileShadingModels.ush
  • MobileBasePassPixelShader.usf
// Specular BRDF
half CalcSpecular(half Roughness, half NoH)
{
	return (Roughness*0.25 + 0.25) * GGX_Mobile(Roughness, NoH);
}
// Taken from https://gist.github.com/romainguy/a2e9208f14cae37c579448be99f78f25
// Modified by Epic Games, Inc. To account for premultiplied light color and code style rules.
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);
}

最小的roughness值设定

// The smallest normalized value that can be represented in IEEE 754 (FP16) is 2^-24 = 5.96e-8.
// The code will make the following computation involving roughness: 1.0 / Roughness^4.
// Therefore to prevent division by zero on devices that do not support denormals, Roughness^4
// must be >= 5.96e-8. We will clamp to 0.015625 because 0.015625^4 = 5.96e-8.
GBuffer.Roughness = max(0.015625, GetMaterialRoughness(PixelMaterialInputs));

[pc]

FDirectLighting DefaultLitBxDF( FGBufferData GBuffer, half3 N, half3 V, half3 L, float Falloff, float NoL, FAreaLight AreaLight, FShadowTerms Shadow )

diffuse项:

Diffuse  = AreaLight.FalloffColor * (Falloff * NoL) * Diffuse_Lambert( GBuffer.DiffuseColor );

specular项:

Specular = AreaLight.FalloffColor * (Falloff * NoL) * SpecularGGX(GBuffer.Roughness, GBuffer.SpecularColor, Context, NoL, AreaLight);

SpecularGGX

float3 SpecularGGX( float Roughness, float3 SpecularColor, BxDFContext Context, float NoL, FAreaLight AreaLight )
{
	float a2 = Pow4( Roughness );
	float Energy = EnergyNormalization( a2, Context.VoH, AreaLight );
	
	// 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;
}

最小的roughness值设定 [SceneView.cpp]

void FSceneView::SetupCommonViewUniformBufferParameters
	ViewUniformShaderParameters.MinRoughness = FMath::Clamp(CVarGlobalMinRoughnessOverride.GetValueOnRenderThread(), 0.02f, 1.0f);

[CapsuleLightIntegrate.ush]

FDirectLighting IntegrateBxDF( FGBufferData GBuffer, half3 N, half3 V, FCapsuleLight Capsule, FShadowTerms Shadow, bool bInverseSquared )
		GBuffer.Roughness = max( GBuffer.Roughness, View.MinRoughness );

IBL

[mobile]

Private/MobileBasePassPixelShader.usf

void GatherSpecularIBL(FMaterialPixelParameters MaterialParameters
    , TextureCube ReflectionCube
    , SamplerState ReflectionSampler
    , half Roughness
    , half IndirectIrradiance
    , half MaxValue
    , inout half4 ImageBasedReflections
#if HQ_REFLECTIONS
    , int ReflectionIndex
    , inout half3 ExtraIndirectSpecular
    , inout half2 CompositedAverageBrightness
#endif
)

half AbsoluteSpecularMip = ComputeReflectionCaptureMipFromRoughness(Roughness, ResolvedView.ReflectionCubemapMaxMip);
half4 SpecularIBLSample = ReflectionCube.SampleLevel(ReflectionSampler, ProjectedCaptureVector, AbsoluteSpecularMip);

SpecularIBL = RGBMDecode(SpecularIBLSample, MaxValue);
SpecularIBL = SpecularIBL * SpecularIBL; // Specular BRDF

[pc]

  • Private/ReflectionEnvironmentComposite.ush
  • Private/ReflectionEnvironmentPixelShader.usf

IBL高光 IBL高光计算中分离和的第二部分:EnvBRDF( SpecularColor, GBuffer.Roughness, NoV ),根据roughness和dot(Normal, ViewDir)采样BRDF-LUT

CompositeReflectionCapturesAndSkylight

float3 ReflectionEnvironment(FGBufferData GBuffer, float AmbientOcclusion, float2 BufferUV, float2 ScreenPosition, float4 SvPosition, float3 BentNormal, float3 SpecularColor)

BRANCH
if( GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT)
{
	...
}
else
{
    Color.rgb *= EnvBRDF( SpecularColor, GBuffer.Roughness, NoV );
}