You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#rb wei.liu #jira none #preflight 627b5f586842238976719cc3 [CL 20134438 by Dmitriy Dyomin in ue5-main branch]
450 lines
17 KiB
Plaintext
450 lines
17 KiB
Plaintext
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "BRDF.ush"
|
|
#include "MobileGGX.ush"
|
|
#include "ShadingCommon.ush"
|
|
#include "ShadowFilteringCommon.ush"
|
|
#include "DeferredShadingCommon.ush"
|
|
#include "HairBsdf.ush"
|
|
#include "BurleyNormalizedSSSCommon.ush"
|
|
|
|
#ifndef MAX_MOBILE_SHADOWCASCADES
|
|
#define MAX_MOBILE_SHADOWCASCADES 0
|
|
#endif
|
|
|
|
#ifndef MOBILE_SHADOW_QUALITY
|
|
#define MOBILE_SHADOW_QUALITY 2
|
|
#endif
|
|
|
|
#ifndef MOBILE_HIGH_QUALITY_BRDF
|
|
#define MOBILE_HIGH_QUALITY_BRDF 0
|
|
#endif
|
|
|
|
//It's always 0 in mobile deferred lighting shaders
|
|
#ifndef FULLY_ROUGH
|
|
#define FULLY_ROUGH 0
|
|
#endif
|
|
|
|
//It's always 0 in mobile deferred lighting shaders
|
|
#ifndef NONMETAL
|
|
#define NONMETAL 0
|
|
#endif
|
|
|
|
//It's always 0 in mobile deferred lighting shaders
|
|
#ifndef MATERIAL_SHADINGMODEL_SINGLELAYERWATER
|
|
#define MATERIAL_SHADINGMODEL_SINGLELAYERWATER 0
|
|
#endif
|
|
|
|
//It's always 0 in mobile deferred lighting shaders
|
|
#ifndef FORWARDSHADING_USE_HQ_ENV_BRDF
|
|
#define FORWARDSHADING_USE_HQ_ENV_BRDF 0
|
|
#endif
|
|
|
|
//It's always 1 in mobile deferred lighting shaders
|
|
#ifndef MOBILE_DEFERRED_LIGHTING
|
|
#define MOBILE_DEFERRED_LIGHTING 0
|
|
#endif
|
|
|
|
#ifndef DEFERRED_SHADING_PATH
|
|
#define DEFERRED_SHADING_PATH 0
|
|
#endif
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Mobile Shading Models
|
|
------------------------------------------------------------------------------*/
|
|
|
|
struct FMobileDirectLighting
|
|
{
|
|
half3 Diffuse;
|
|
half3 Specular;
|
|
};
|
|
|
|
struct FMobileShadingModelContext
|
|
{
|
|
half Opacity;
|
|
half3 DiffuseColor;
|
|
half3 SpecularColor;
|
|
half3 EnvBrdf;
|
|
|
|
half NoV;
|
|
float3 DiffuseDir;
|
|
|
|
#if MATERIAL_SHADINGMODEL_SINGLELAYERWATER
|
|
half BaseMaterialCoverageOverWater;
|
|
half WaterVisibility;
|
|
float3 WaterDiffuseIndirectLuminance;
|
|
#endif
|
|
|
|
#if MOBILE_SHADINGMODEL_SUPPORT
|
|
half ClearCoat;
|
|
half ClearCoatRoughness;
|
|
|
|
// If we don't use this shading model the color should be black (don't generate shader code for unused data, don't do indirectlighting cache lighting with this color).
|
|
half3 SubsurfaceColor;
|
|
|
|
uint SubsurfaceProfileInt;
|
|
half Curvature;
|
|
|
|
half Lobe0Roughness;
|
|
half Lobe1Roughness;
|
|
half LobeMix;
|
|
#endif
|
|
};
|
|
|
|
half3 GetEnvBRDF(half3 SpecularColor, half Roughness, half NoV)
|
|
{
|
|
#if FORWARDSHADING_USE_HQ_ENV_BRDF || MOBILE_DEFERRED_LIGHTING
|
|
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
|
|
}
|
|
|
|
#if MOBILE_SHADINGMODEL_SUPPORT
|
|
half CalculateCurvature(half3 WorldNormal, float3 WorldPosition)
|
|
{
|
|
#if 0
|
|
half DeltaNormal = length(abs(DDX(WorldNormal)) + abs(DDY(WorldNormal)));
|
|
half DeltaPosition = length(abs(DDX(WorldPosition)) + abs(DDY(WorldPosition))) * BURLEY_CM_2_MM;
|
|
half CurvatureApprox = DeltaNormal / DeltaPosition;
|
|
#else
|
|
half3 dNdx = ddx((HALF3_TYPE)WorldNormal);
|
|
half3 dNdy = ddy((HALF3_TYPE)WorldNormal);
|
|
half x = dot(dNdx, dNdx);
|
|
half y = dot(dNdy, dNdy);
|
|
half CurvatureApprox = pow(max(x, y), ResolvedView.NormalCurvatureToRoughnessScaleBias.z);
|
|
#endif
|
|
return CurvatureApprox;
|
|
}
|
|
|
|
void GetProfileDualSpecular(uint SubsurfaceProfileInt, half Roughness, half Opacity, out half2 LobeRoughness, out half LobeMix)
|
|
{
|
|
half4 Data = GetSubsurfaceProfileTexture(SSSS_DUAL_SPECULAR_OFFSET, SubsurfaceProfileInt);
|
|
half2 MaterialRoughnessToLobeRoughness = Data.xy * SSSS_MAX_DUAL_SPECULAR_ROUGHNESS;
|
|
LobeMix = Data.z;
|
|
|
|
half RoughnessLerpFactor = saturate(Opacity * 10.0f);
|
|
MaterialRoughnessToLobeRoughness.x = lerp(1.0f, MaterialRoughnessToLobeRoughness.x, RoughnessLerpFactor);
|
|
MaterialRoughnessToLobeRoughness.y = lerp(1.0f, MaterialRoughnessToLobeRoughness.y, RoughnessLerpFactor);
|
|
|
|
LobeRoughness.x = max(saturate(Roughness * MaterialRoughnessToLobeRoughness.x), 0.02f);
|
|
LobeRoughness.y = saturate(Roughness * MaterialRoughnessToLobeRoughness.y);
|
|
}
|
|
|
|
half4 GetSSProfilePreIntegratedValue(uint SubsurfaceProfileInt, half NoL, half Curvature)
|
|
{
|
|
float3 UV = float3((NoL * .5 + .5), Curvature, SubsurfaceProfileInt);
|
|
|
|
return Texture2DArraySampleLevel(View.SSProfilesPreIntegratedTexture, View.SSProfilesPreIntegratedSampler, UV, 0);
|
|
}
|
|
#endif
|
|
|
|
void InitShadingModelContext(inout FMobileShadingModelContext ShadingModelContext, inout FGBufferData GBuffer, half3 CameraVector)
|
|
{
|
|
half NoV = max(dot(GBuffer.WorldNormal, CameraVector), 0.0f);
|
|
|
|
// This is to prevent Vis to get inf when both NoL and NoV are 0.
|
|
ShadingModelContext.NoV = saturate(abs(NoV) + 1e-5);
|
|
ShadingModelContext.DiffuseDir = GBuffer.WorldNormal;
|
|
|
|
#if NONMETAL
|
|
GBuffer.DiffuseColor = GBuffer.BaseColor;
|
|
GBuffer.SpecularColor = 0.04;
|
|
#else
|
|
GBuffer.DiffuseColor = GBuffer.BaseColor - GBuffer.BaseColor * GBuffer.Metallic; // 1 mad
|
|
half DielectricSpecular = 0.08 * GBuffer.Specular;
|
|
GBuffer.SpecularColor = (DielectricSpecular - DielectricSpecular * GBuffer.Metallic) + GBuffer.BaseColor * GBuffer.Metallic; // 2 mad
|
|
#endif
|
|
|
|
#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
|
|
|
|
ShadingModelContext.DiffuseColor = GBuffer.DiffuseColor;
|
|
ShadingModelContext.SpecularColor = GBuffer.SpecularColor;
|
|
|
|
#if MATERIAL_SHADINGMODEL_SINGLELAYERWATER
|
|
ShadingModelContext.BaseMaterialCoverageOverWater = ShadingModelContext.Opacity;
|
|
ShadingModelContext.WaterVisibility = 1.0 - ShadingModelContext.BaseMaterialCoverageOverWater;
|
|
// Fade out diffuse as this will be handled by the single scattering lighting. when over the water surface.
|
|
// We keep the SpecularColor for sun/water interactions
|
|
ShadingModelContext.WaterDiffuseIndirectLuminance = 0;
|
|
ShadingModelContext.DiffuseColor *= ShadingModelContext.BaseMaterialCoverageOverWater;
|
|
#endif
|
|
|
|
#if MOBILE_SHADINGMODEL_SUPPORT
|
|
if (GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT)
|
|
{
|
|
ShadingModelContext.ClearCoat = GBuffer.CustomData.x;
|
|
ShadingModelContext.ClearCoatRoughness = clamp(GBuffer.CustomData.y, 0.015625, 1.0);
|
|
|
|
// Approximation of refraction's effect on EnvBRDF
|
|
half RefractionScale = ((NoV * 0.5 + 0.5) * NoV - 1) * saturate(1.25 - 1.25 * GBuffer.Roughness) + 1;
|
|
|
|
half Specular = lerp(GBuffer.Specular, RefractionScale, ShadingModelContext.ClearCoat);
|
|
half DielectricSpecular = 0.08 * Specular;
|
|
ShadingModelContext.SpecularColor = (DielectricSpecular - DielectricSpecular * GBuffer.Metallic) + GBuffer.BaseColor * GBuffer.Metallic; // 2 mad
|
|
}
|
|
else if (GBuffer.ShadingModelID == SHADINGMODELID_SUBSURFACE || GBuffer.ShadingModelID == SHADINGMODELID_PREINTEGRATED_SKIN)
|
|
{
|
|
ShadingModelContext.SubsurfaceColor = ExtractSubsurfaceColor(GBuffer);
|
|
ShadingModelContext.Opacity = GBuffer.CustomData.a;
|
|
}
|
|
else if (GBuffer.ShadingModelID == SHADINGMODELID_SUBSURFACE_PROFILE)
|
|
{
|
|
ShadingModelContext.SubsurfaceProfileInt = ExtractSubsurfaceProfileInt(GBuffer);
|
|
|
|
ShadingModelContext.Curvature = GBuffer.CustomData.g;
|
|
ShadingModelContext.Opacity = GBuffer.CustomData.a;
|
|
|
|
half2 LobeRoughness;
|
|
GetProfileDualSpecular(ShadingModelContext.SubsurfaceProfileInt, GBuffer.Roughness,
|
|
ShadingModelContext.Opacity, LobeRoughness, ShadingModelContext.LobeMix);
|
|
|
|
ShadingModelContext.Lobe0Roughness = LobeRoughness.x;
|
|
ShadingModelContext.Lobe1Roughness = LobeRoughness.y;
|
|
}
|
|
else if (GBuffer.ShadingModelID == SHADINGMODELID_HAIR)
|
|
{
|
|
FHairTransmittanceData TransmittanceData = InitHairTransmittanceData(true);
|
|
float3 N = GBuffer.WorldNormal;
|
|
float3 V = CameraVector;
|
|
float3 L = normalize(V - N * dot(V, N));
|
|
ShadingModelContext.DiffuseDir = L;
|
|
ShadingModelContext.DiffuseColor = 2 * PI * HairShading(GBuffer, L, V, N, 1, TransmittanceData, 0, 0.2, uint2(0, 0));
|
|
}
|
|
#endif
|
|
|
|
#if FULLY_ROUGH
|
|
EnvBRDFApproxFullyRough(ShadingModelContext.DiffuseColor, ShadingModelContext.SpecularColor);
|
|
ShadingModelContext.EnvBrdf = 0.0f;
|
|
#else
|
|
ShadingModelContext.EnvBrdf = GetEnvBRDF(ShadingModelContext.SpecularColor, GBuffer.Roughness, NoV);
|
|
#endif
|
|
}
|
|
|
|
half Vis_SmithJointApprox_Mobile(half a, half NoV, half NoL)
|
|
{
|
|
float Vis_SmithV = NoL * (NoV * (1 - a) + a);
|
|
float Vis_SmithL = NoV * (NoL * (1 - a) + a);
|
|
// clamp the visibility term to 0~1
|
|
return saturate(0.5f * rcp(max(Vis_SmithV + Vis_SmithL, 0.0001f)));
|
|
}
|
|
|
|
// [Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"]
|
|
half3 F_Schlick_Mobile(half3 SpecularColor, half VoH)
|
|
{
|
|
half OneMinusVoH = 1 - VoH;
|
|
half Fc = OneMinusVoH * OneMinusVoH;
|
|
Fc = Fc * Fc;
|
|
Fc = Fc * OneMinusVoH;
|
|
//return Fc + (1 - Fc) * SpecularColor; // 1 add, 3 mad
|
|
|
|
// Anything less than 2% is physically impossible and is instead considered to be shadowing
|
|
return saturate(50.0 * SpecularColor.g) * Fc + (1 - Fc) * SpecularColor;
|
|
}
|
|
|
|
half3 MobileSpecularGGXInner(half D, half3 EnvBrdf, half3 SpecularColor, half Roughness, half NoV, half NoL, half VoH)
|
|
{
|
|
#if MOBILE_HIGH_QUALITY_BRDF
|
|
half Vis = Vis_SmithJointApprox_Mobile(Roughness * Roughness, NoV, NoL);
|
|
half3 F = F_Schlick_Mobile(SpecularColor, VoH);
|
|
#else
|
|
half Vis = (Roughness * 0.25 + 0.25);
|
|
half3 F = EnvBrdf;
|
|
#endif
|
|
|
|
return (D * Vis) * F;
|
|
}
|
|
|
|
half3 MobileSpecularGGX(half3 EnvBrdf, half3 SpecularColor, half Roughness, half NoV, half NoH, half NoL, half VoH)
|
|
{
|
|
half D = GGX_Mobile(Roughness, NoH);
|
|
|
|
return MobileSpecularGGXInner(D, EnvBrdf, SpecularColor, Roughness, NoV, NoL, VoH);
|
|
}
|
|
|
|
half3 MobileDualSpecularGGX(half AverageRoughness, half Lobe0Roughness, half Lobe1Roughness, half LobeMix, half3 EnvBrdf, half3 SpecularColor, half NoV, half NoH, half NoL, half VoH)
|
|
{
|
|
half D = lerp(GGX_Mobile(Lobe0Roughness, NoH), GGX_Mobile(Lobe1Roughness, NoH), LobeMix);
|
|
|
|
return MobileSpecularGGXInner(D, EnvBrdf, SpecularColor, AverageRoughness, NoV, NoL, VoH);
|
|
}
|
|
|
|
FMobileDirectLighting MobileDefaultLitBxDF(FMobileShadingModelContext ShadingModelContext, FGBufferData GBuffer, half NoL, half NoH, half VoH, half3 V, half3 L, half Shadow)
|
|
{
|
|
FMobileDirectLighting Lighting;
|
|
|
|
Lighting.Specular = Shadow * NoL * MobileSpecularGGX(ShadingModelContext.EnvBrdf, ShadingModelContext.SpecularColor, GBuffer.Roughness, ShadingModelContext.NoV, NoH, NoL, VoH);
|
|
Lighting.Diffuse = Shadow * NoL * ShadingModelContext.DiffuseColor;
|
|
|
|
return Lighting;
|
|
}
|
|
|
|
#if MOBILE_SHADINGMODEL_SUPPORT
|
|
FMobileDirectLighting MobileClearCoatBxDF(FMobileShadingModelContext ShadingModelContext, FGBufferData GBuffer, half NoL, half NoH, half VoH, half3 V, half3 L, half Shadow)
|
|
{
|
|
FMobileDirectLighting Lighting;
|
|
|
|
half ClearCoatRoughness = ShadingModelContext.ClearCoatRoughness;
|
|
half F0 = 0.04;
|
|
half Fc = Pow5(1 - VoH);
|
|
half F = Fc + (1 - Fc) * F0;
|
|
half LayerAttenuation = 1 - F;
|
|
LayerAttenuation *= LayerAttenuation;
|
|
|
|
// Vis_SmithJointApprox
|
|
half a = ClearCoatRoughness * ClearCoatRoughness;
|
|
float Vis = Vis_SmithJointApprox_Mobile(a, NoL, ShadingModelContext.NoV);
|
|
|
|
Lighting.Specular = NoL * ShadingModelContext.ClearCoat * F * Vis * GGX_Mobile(ClearCoatRoughness, NoH);
|
|
|
|
half Eta = 0.66666667f;
|
|
half RefractionBlendFactor = (0.63 - 0.22 * VoH) * VoH - 0.745;
|
|
half RefractionProjectionTerm = RefractionBlendFactor * NoH;
|
|
half BottomNoV = saturate(Eta * ShadingModelContext.NoV - RefractionProjectionTerm);
|
|
half BottomNoL = saturate(Eta * NoL - RefractionProjectionTerm);
|
|
|
|
half3 Transmission = 0.0;
|
|
if (BottomNoL > 0.0 && BottomNoV > 0.0)
|
|
{
|
|
// Normalized layer thickness documented for clarity
|
|
half ThinDistance = (rcp(BottomNoV) + rcp(BottomNoL));
|
|
half AbsorptionMix = GBuffer.Metallic;
|
|
|
|
Transmission = 1.0;
|
|
if (AbsorptionMix > 0.0)
|
|
{
|
|
// Base color represents reflected color viewed at 0 incidence angle, after being absorbed through the substrate.
|
|
// Because of this, extinction is normalized by traveling through layer thickness twice
|
|
half3 TransmissionColor = GBuffer.BaseColor;
|
|
half3 ExtinctionCoefficient = -log(TransmissionColor) * 0.5f;
|
|
half3 OpticalDepth = ExtinctionCoefficient * max(ThinDistance - 2.0, 0.0);
|
|
Transmission = saturate(exp(-OpticalDepth));
|
|
Transmission = lerp(1.0, Transmission, AbsorptionMix);
|
|
}
|
|
}
|
|
|
|
half3 CommonDiffuse = ShadingModelContext.DiffuseColor;
|
|
half3 DefaultDiffuse = NoL;
|
|
half3 RefractedDiffuse = (LayerAttenuation * BottomNoL) * Transmission;
|
|
Lighting.Diffuse = Shadow * CommonDiffuse * lerp(DefaultDiffuse, RefractedDiffuse, ShadingModelContext.ClearCoat);
|
|
|
|
half3 CommonSpecular = MobileSpecularGGX(ShadingModelContext.EnvBrdf, ShadingModelContext.SpecularColor, GBuffer.Roughness, ShadingModelContext.NoV, NoH, NoL, VoH);
|
|
half3 DefaultSpecular = NoL;
|
|
half3 RefractedSpecular = LayerAttenuation * Transmission * BottomNoL;
|
|
Lighting.Specular += CommonSpecular * lerp(DefaultSpecular, RefractedSpecular, ShadingModelContext.ClearCoat);
|
|
|
|
Lighting.Specular *= Shadow;
|
|
|
|
return Lighting;
|
|
}
|
|
|
|
FMobileDirectLighting MobileHairBxDF(FMobileShadingModelContext ShadingModelContext, FGBufferData GBuffer, half NoL, half NoH, half VoH, half3 V, half3 L, half Shadow)
|
|
{
|
|
FHairTransmittanceData HairTransmittance = InitHairTransmittanceData();
|
|
const float3 BsdfValue = HairShading(GBuffer, L, V, GBuffer.WorldNormal, Shadow, HairTransmittance, 1, 0, uint2(0, 0));
|
|
|
|
half3 Transmission = BsdfValue * PI; // multiply PI since the LightColor is divided by PI in C++;
|
|
|
|
FMobileDirectLighting Lighting;
|
|
Lighting.Diffuse = Transmission * Shadow;
|
|
Lighting.Specular = 0;
|
|
return Lighting;
|
|
}
|
|
|
|
FMobileDirectLighting MobileSubsurfaceBxDF(FMobileShadingModelContext ShadingModelContext, FGBufferData GBuffer, half NoL, half NoH, half VoH, half3 V, half3 L, half Shadow)
|
|
{
|
|
FMobileDirectLighting Lighting;
|
|
|
|
Lighting = MobileDefaultLitBxDF(ShadingModelContext, GBuffer, NoL, NoH, VoH, V, L, Shadow);
|
|
|
|
half InScatter = pow(saturate(dot(L, -V)), 12) * lerp(3, .1f, ShadingModelContext.Opacity);
|
|
|
|
half NormalContribution = saturate(NoH * ShadingModelContext.Opacity + 1 - ShadingModelContext.Opacity);
|
|
half BackScatter = GBuffer.GBufferAO * NormalContribution / (PI * 2);
|
|
|
|
// lerp to never exceed 1 (energy conserving)
|
|
half3 Transmission = lerp(BackScatter, 1, InScatter) * ShadingModelContext.SubsurfaceColor * PI; // multiply PI since the LightColor is divided by PI in C++
|
|
|
|
Lighting.Diffuse += Transmission * Shadow;
|
|
|
|
return Lighting;
|
|
}
|
|
|
|
FMobileDirectLighting MobilePreintegratedSkinBxDF(FMobileShadingModelContext ShadingModelContext, FGBufferData GBuffer, half NoL, half NoH, half VoH, half3 V, half3 L, half Shadow)
|
|
{
|
|
FMobileDirectLighting Lighting;
|
|
|
|
Lighting = MobileDefaultLitBxDF(ShadingModelContext, GBuffer, NoL, NoH, VoH, V, L, Shadow);
|
|
|
|
half3 PreintegratedBRDF = Texture2DSampleLevel(View.PreIntegratedBRDF, View.PreIntegratedBRDFSampler, float2(saturate(NoL * .5 + .5), 1 - ShadingModelContext.Opacity), 0).rgb;
|
|
half3 Transmission = PreintegratedBRDF * ShadingModelContext.SubsurfaceColor * PI; // multiply PI since the LightColor is divided by PI in C++
|
|
|
|
Lighting.Diffuse += Transmission * Shadow;
|
|
|
|
return Lighting;
|
|
}
|
|
|
|
FMobileDirectLighting MobileSubsurfaceProfileBxDF(FMobileShadingModelContext ShadingModelContext, FGBufferData GBuffer, half NoL, half NoH, half VoH, half3 V, half3 L, half Shadow)
|
|
{
|
|
FMobileDirectLighting Lighting;
|
|
|
|
half UnClampedNoL = dot(GBuffer.WorldNormal, L);
|
|
|
|
half ShadowFactor = 1 - sqrt(Shadow);
|
|
|
|
// Rotate the world normal based on the shadow value, it's just a experimental value
|
|
half UnClampedRotatedNoL = max(UnClampedNoL - max(2.0f * UnClampedNoL, 0.4f) * ShadowFactor, -1.0f);
|
|
|
|
half4 BurleyDiffuse = GetSSProfilePreIntegratedValue(ShadingModelContext.SubsurfaceProfileInt, UnClampedRotatedNoL, ShadingModelContext.Curvature);
|
|
|
|
Lighting.Diffuse = BurleyDiffuse.rgb * ShadingModelContext.DiffuseColor;
|
|
|
|
half AverageRoughness = lerp(ShadingModelContext.Lobe0Roughness, ShadingModelContext.Lobe1Roughness, ShadingModelContext.LobeMix);
|
|
|
|
Lighting.Specular = Shadow * NoL * MobileDualSpecularGGX(AverageRoughness, ShadingModelContext.Lobe0Roughness, ShadingModelContext.Lobe1Roughness, ShadingModelContext.LobeMix, ShadingModelContext.EnvBrdf, ShadingModelContext.SpecularColor, ShadingModelContext.NoV, NoH, NoL, VoH);
|
|
|
|
return Lighting;
|
|
}
|
|
#endif
|
|
|
|
FMobileDirectLighting MobileIntegrateBxDF(FMobileShadingModelContext ShadingModelContext, FGBufferData GBuffer, half NoL, half NoH, half VoH, half3 V, half3 L, half Shadow = 1.0f)
|
|
{
|
|
#if MOBILE_SHADINGMODEL_SUPPORT
|
|
if (GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT)
|
|
{
|
|
return MobileClearCoatBxDF(ShadingModelContext, GBuffer, NoL, NoH, VoH, V, L, Shadow);
|
|
}
|
|
else if (GBuffer.ShadingModelID == SHADINGMODELID_HAIR)
|
|
{
|
|
return MobileHairBxDF(ShadingModelContext, GBuffer, NoL, NoH, VoH, V, L, Shadow);
|
|
}
|
|
else if (GBuffer.ShadingModelID == SHADINGMODELID_SUBSURFACE)
|
|
{
|
|
return MobileSubsurfaceBxDF(ShadingModelContext, GBuffer, NoL, NoH, VoH, V, L, Shadow);
|
|
}
|
|
else if (GBuffer.ShadingModelID == SHADINGMODELID_PREINTEGRATED_SKIN)
|
|
{
|
|
return MobilePreintegratedSkinBxDF(ShadingModelContext, GBuffer, NoL, NoH, VoH, V, L, Shadow);
|
|
}
|
|
else if (GBuffer.ShadingModelID == SHADINGMODELID_SUBSURFACE_PROFILE)
|
|
{
|
|
return MobileSubsurfaceProfileBxDF(ShadingModelContext, GBuffer, NoL, NoH, VoH, V, L, Shadow);
|
|
}
|
|
#endif
|
|
|
|
return MobileDefaultLitBxDF(ShadingModelContext, GBuffer, NoL, NoH, VoH, V, L, Shadow);
|
|
} |