Files
UnrealEngine/Engine/Shaders/Private/MobileBasePassPixelShader.usf
2025-05-18 13:04:45 +08:00

1366 lines
56 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
MobileBasePassPixelShader.usf: Base pass pixel shader used with forward shading
=============================================================================*/
#if !MATERIAL_LWC_ENABLED
#define UE_DF_FORCE_FP32_OPS 1
#endif
#include "Common.ush"
// Reroute MobileSceneTextures uniform buffer references to the base pass uniform buffer
#define MobileSceneTextures MobileBasePass.SceneTextures
#define EyeAdaptationStruct MobileBasePass
#define ForwardLightStruct MobileBasePass.Forward
#define ReflectionStruct MobileBasePass.ReflectionsParameters
#define SubstrateStruct MobileBasePass.Substrate
#ifndef MOBILE_QL_FORCE_DISABLE_PREINTEGRATEDGF
#define MOBILE_QL_FORCE_DISABLE_PREINTEGRATEDGF 0
#endif
#if SUBSTRATE_ENABLED && MERGED_LOCAL_LIGHTS_MOBILE == 2
#define ALLOW_LOCAL_LIGHT_DISTANCE_ATTENUATION 1
#endif
#define UseBasePassSkylightDiffuse (1)
#define UseBasePassSkylightSpecular (MobileBasePass.ReflectionsParameters.SkyLightParameters.y)
#define MOBILE_USE_PREINTEGRATED_GF (MATERIAL_USE_PREINTEGRATED_GF && !MOBILE_QL_FORCE_DISABLE_PREINTEGRATEDGF)
//use preintegrated GF lut for simple IBL
#if MOBILE_USE_PREINTEGRATED_GF
#define PreIntegratedGF MobileBasePass.PreIntegratedGFTexture
#define PreIntegratedGFSampler MobileBasePass.PreIntegratedGFSampler
#endif
#define APPLY_AO 0
#if (MATERIALBLENDING_MASKED || MATERIALBLENDING_SOLID)
#if ENABLE_AMBIENT_OCCLUSION && !MATERIAL_SHADINGMODEL_UNLIT
#undef APPLY_AO
#define APPLY_AO 1
#endif
#endif
#if APPLY_AO
#define AmbientOcclusionTexture MobileBasePass.AmbientOcclusionTexture
#define AmbientOcclusionSampler MobileBasePass.AmbientOcclusionSampler
#define AmbientOcclusionStaticFraction MobileBasePass.AmbientOcclusionStaticFraction
#endif
#if MATERIAL_SHADINGMODEL_SINGLELAYERWATER
#ifdef SINGLE_LAYER_WATER_SHADING_QUALITY
#undef SINGLE_LAYER_WATER_SHADING_QUALITY
#endif
// Value must match SINGLE_LAYER_WATER_SHADING_QUALITY_MOBILE_WITH_DEPTH_BUFFER in SingleLayerWaterCommon.ush!
#define SINGLE_LAYER_WATER_SHADING_QUALITY 2
#endif
// Enable Substrate. This define & include need to be defined before certains includes (i.e., DBufferDecalShared which uses them internally)
#if !MATERIAL_IS_SUBSTRATE && SUBSTRATE_ENABLED
#undef SUBSTRATE_ENABLED
#define SUBSTRATE_ENABLED 0
#endif
#ifndef PROJECT_MOBILE_ENABLE_MOVABLE_SPOTLIGHT_SHADOWS
#define PROJECT_MOBILE_ENABLE_MOVABLE_SPOTLIGHT_SHADOWS 0
#endif
#ifndef MOBILE_QL_FORCE_FULLY_ROUGH
#define MOBILE_QL_FORCE_FULLY_ROUGH 0
#endif
#ifndef MOBILE_QL_FORCE_NONMETAL
#define MOBILE_QL_FORCE_NONMETAL 0
#endif
#ifndef MOBILE_QL_DISABLE_MATERIAL_NORMAL
#define MOBILE_QL_DISABLE_MATERIAL_NORMAL 0
#endif
#define FULLY_ROUGH (MATERIAL_FULLY_ROUGH || MOBILE_QL_FORCE_FULLY_ROUGH)
#define NONMETAL (MATERIAL_NONMETAL || MOBILE_QL_FORCE_NONMETAL)
#define FORCE_VERTEX_NORMAL (MOBILE_QL_DISABLE_MATERIAL_NORMAL)
#define SUPPORT_SPOTLIGHTS_SHADOW (MATERIALBLENDING_SOLID || MATERIALBLENDING_MASKED) && PROJECT_MOBILE_ENABLE_MOVABLE_SPOTLIGHT_SHADOWS
// Sky does not write to depth and must not overwrite GBuffer
#define MOBILE_USE_GBUFFER (MOBILE_DEFERRED_SHADING && ((MATERIALBLENDING_SOLID || MATERIALBLENDING_MASKED) && !MATERIAL_SHADINGMODEL_SINGLELAYERWATER && !MATERIAL_IS_SKY))
#if MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT || SUBSTRATE_BLENDING_TRANSLUCENT_COLOREDTRANSMITTANCE
#define MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE 1
#else
#define MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE 0
#undef MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE_DUAL_SRC_BLENDING
#undef MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE_PROGRAMMABLE_BLENDING
#undef MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE_SINGLE_SRC_BLENDING
#define MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE_DUAL_SRC_BLENDING 0
#define MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE_PROGRAMMABLE_BLENDING 0
#define MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE_SINGLE_SRC_BLENDING 0
#endif
// SceneDepthAux always enabled for IOS, on other platforms only enabled when in forward and MobileHDR=true
// Sky does not write to depth
#define HAS_SCENE_DEPTH_AUX_OUTPUT (USE_SCENE_DEPTH_AUX && (MATERIALBLENDING_SOLID || MATERIALBLENDING_MASKED) && !MATERIAL_SHADINGMODEL_SINGLELAYERWATER && !MATERIAL_IS_SKY)
#if MOBILE_USE_GBUFFER && MOBILE_EXTENDED_GBUFFER
#define SV_TargetDepthAux SV_Target5
#elif MOBILE_USE_GBUFFER
#define SV_TargetDepthAux SV_Target4
#else
#define SV_TargetDepthAux SV_Target1
#endif
#define TRANSLUCENCY_NON_DIRECTIONAL (MATERIALBLENDING_ANY_TRANSLUCENT && (TRANSLUCENCY_LIGHTING_VOLUMETRIC_NONDIRECTIONAL || TRANSLUCENCY_LIGHTING_VOLUMETRIC_PERVERTEX_NONDIRECTIONAL) && !MATERIAL_SHADINGMODEL_SINGLELAYERWATER)
#define TRANSLUCENCY_SH_LIGHTING (MATERIAL_SHADINGMODEL_DEFAULT_LIT || MATERIAL_SHADINGMODEL_SUBSURFACE) && (MATERIALBLENDING_TRANSLUCENT || MATERIALBLENDING_ADDITIVE) && !TRANSLUCENCY_LIGHTING_SURFACE_FORWARDSHADING && !MATERIAL_SHADINGMODEL_SINGLELAYERWATER
#include "SHCommon.ush"
#include "/Engine/Generated/Material.ush"
#include "MobileBasePassCommon.ush"
#include "/Engine/Generated/VertexFactory.ush"
#include "LightmapCommon.ush"
#define ENABLE_NDOTL_INTEGRATION 1
#include "MobileLightingCommon.ush"
#include "ShadingModelsMaterial.ush"
#include "ThinTranslucentCommon.ush"
#if MATERIAL_SHADINGMODEL_SINGLELAYERWATER
#include "SingleLayerWaterShading.ush"
#endif
// SUBSTRATE_TODO: Shared with BasePassPixelShader.usf
#define MATERIAL_SUBSTRATE_OPAQUE_PRECOMPUTED_LIGHTING (MATERIAL_IS_SUBSTRATE && SUBSTRATE_ENABLED && SUBSTRATE_OPAQUE_DEFERRED)
#if SUBSTRATE_TRANSLUCENT_FORWARD || SUBSTRATE_FORWARD_SHADING || MATERIAL_SUBSTRATE_OPAQUE_PRECOMPUTED_LIGHTING || SUBSTRATE_MATERIAL_EXPORT_EXECUTED
#include "/Engine/Private/Substrate/SubstrateEvaluation.ush"
#endif
#if SUBSTRATE_TRANSLUCENT_FORWARD || SUBSTRATE_FORWARD_SHADING
#include "/Engine/Private/Substrate/SubstrateMobileForwardLighting.ush"
#endif
#if MATERIAL_SUBSTRATE_OPAQUE_PRECOMPUTED_LIGHTING || SUBSTRATE_MATERIAL_EXPORT_EXECUTED || SUBTRATE_GBUFFER_FORMAT==0
#include "/Engine/Private/Substrate/SubstrateExport.ush"
#endif
#if MATERIAL_SHADINGMODEL_HAIR
#ifndef USE_HAIR_COMPLEX_TRANSMITTANCE
#define USE_HAIR_COMPLEX_TRANSMITTANCE 0
#endif
#include "HairStrands/HairStrandsEnvironmentLightingCommon.ush"
#endif
half3 FrameBufferBlendOp(half4 Source)
{
half4 Dest = half4 (0,0,0,0);
#if MATERIALBLENDING_SOLID
return Source.rgb;
#elif MATERIALBLENDING_MASKED
return Source.rgb;
// AlphaComposite will set both MATERIALBLENDING_TRANSLUCENT and MATERIALBLENDING_ALPHACOMPOSITE defines
// so ensure MATERIALBLENDING_ALPHACOMPOSITE gets first in line
#elif MATERIALBLENDING_ALPHACOMPOSITE
return Source.rgb + (Dest.rgb*(1.0 - Source.a));
// AlphaHoldout will set both MATERIALBLENDING_TRANSLUCENT and MATERIALBLENDING_ALPHAHOLDOUT defines
// so ensure MATERIALBLENDING_ALPHAHOLDOUT gets first in line
#elif MATERIALBLENDING_ALPHAHOLDOUT
return (Dest.rgb*(1.0 - Source.a));
#elif MATERIALBLENDING_TRANSLUCENT
return (Source.rgb*Source.a) + (Dest.rgb*(1.0 - Source.a));
#elif MATERIALBLENDING_ADDITIVE
return Source.rgb + Dest.rgb;
#elif MATERIALBLENDING_MODULATE
return Source.rgb * Dest.rgb;
#endif
}
#if MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE_PROGRAMMABLE_BLENDING
#if VULKAN_PROFILE
#define FramebufferFetchColor0 VulkanSubpassFetch0
#elif METAL_ES3_1_PROFILE && !MAC
#define FramebufferFetchColor0 SubpassFetchRGBA_0
#elif COMPILER_GLSL_ES3_1
#define FramebufferFetchColor0 FramebufferFetchES2
#else
#error Platform unsupported for programmable blending
#endif
#endif // MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE_PROGRAMMABLE_BLENDING
void ApplyPixelDepthOffsetForMobileBasePass(inout FMaterialPixelParameters MaterialParameters, FPixelMaterialInputs PixelMaterialInputs, out float OutDepth)
{
float PixelDepthOffset = ApplyPixelDepthOffsetToMaterialParameters(MaterialParameters, PixelMaterialInputs, OutDepth);
}
#define USES_PIXEL_DISCARD ((MATERIALBLENDING_MASKED || USE_DITHERED_LOD_TRANSITION) && !EARLY_Z_PASS_ONLY_MATERIAL_MASKING)
// Force early depth_stencil for materials that use VT feedback and don't use pixel discard or modify the pixel depth
#if (MATERIAL_VIRTUALTEXTURE_FEEDBACK || LIGHTMAP_VT_ENABLED) && !(OUTPUT_PIXEL_DEPTH_OFFSET || USES_PIXEL_DISCARD)
#define PIXELSHADER_EARLYDEPTHSTENCIL EARLYDEPTHSTENCIL
#else
#define PIXELSHADER_EARLYDEPTHSTENCIL
#endif
void GetSkyLighting(half3 SkyLightColor, half3 WorldNormal, bool bEvaluateBackface, out half3 OutSkyDiffuseLighting, out half3 OutSkySubsurfaceLighting, out half3 OutWaterDiffuseIndirectLuminance)
{
OutSkyDiffuseLighting = 0;
OutSkySubsurfaceLighting = 0;
OutWaterDiffuseIndirectLuminance = 0;
#if ENABLE_SKY_LIGHT
{
half3 SkyDiffuse = GetSkySHDiffuseSimple(WorldNormal);
OutSkyDiffuseLighting = SkyDiffuse * SkyLightColor;
#if MATERIAL_SHADINGMODEL_SINGLELAYERWATER
OutWaterDiffuseIndirectLuminance += OutSkyDiffuseLighting;
#endif
#if SHADINGMODEL_REQUIRES_BACKFACE_LIGHTING
if (bEvaluateBackface)
{
OutSkySubsurfaceLighting = GetSkySHDiffuseSimple(-WorldNormal) * SkyLightColor;
}
#endif
}
#endif
}
void GetPrecomputedIndirectLightingAndSkyLight(VTPageTableResult LightmapVTPageTableResult, FVertexFactoryInterpolantsVSToPS Interpolants, bool bEvaluateBackface, half3 DiffuseDir, half3 SkyLightColor, out half3 OutDiffuseIndirectLighting, out half3 OutSubsurfaceIndirectLighting, out half OutIndirectIrradiance, out half3 OutWaterDiffuseIndirectLuminance)
{
//To keep IndirectLightingCache conherence with PC, initialize the OutIndirectIrradiance to zero.
OutIndirectIrradiance = 0;
OutDiffuseIndirectLighting = 0;
OutSubsurfaceIndirectLighting = 0;
// Indirect Diffuse
#if LQ_TEXTURE_LIGHTMAP
float2 LightmapUV0, LightmapUV1;
uint LightmapDataIndex;
GetLightMapCoordinates(Interpolants, LightmapUV0, LightmapUV1, LightmapDataIndex);
GetLightMapColorLQ(LightmapVTPageTableResult, LightmapUV0, LightmapUV1, LightmapDataIndex, DiffuseDir, bEvaluateBackface, OutDiffuseIndirectLighting, OutSubsurfaceIndirectLighting);
#elif CACHED_POINT_INDIRECT_LIGHTING
#if MATERIALBLENDING_MASKED || MATERIALBLENDING_SOLID
// Take the normal into account for opaque
FThreeBandSHVectorRGB PointIndirectLighting;
PointIndirectLighting.R.V0 = IndirectLightingCache.IndirectLightingSHCoefficients0[0];
PointIndirectLighting.R.V1 = IndirectLightingCache.IndirectLightingSHCoefficients1[0];
PointIndirectLighting.R.V2 = IndirectLightingCache.IndirectLightingSHCoefficients2[0];
PointIndirectLighting.G.V0 = IndirectLightingCache.IndirectLightingSHCoefficients0[1];
PointIndirectLighting.G.V1 = IndirectLightingCache.IndirectLightingSHCoefficients1[1];
PointIndirectLighting.G.V2 = IndirectLightingCache.IndirectLightingSHCoefficients2[1];
PointIndirectLighting.B.V0 = IndirectLightingCache.IndirectLightingSHCoefficients0[2];
PointIndirectLighting.B.V1 = IndirectLightingCache.IndirectLightingSHCoefficients1[2];
PointIndirectLighting.B.V2 = IndirectLightingCache.IndirectLightingSHCoefficients2[2];
FThreeBandSHVector DiffuseTransferSH = CalcDiffuseTransferSH3(DiffuseDir, 1);
// Compute diffuse lighting which takes the normal into account
OutDiffuseIndirectLighting += max(half3(0, 0, 0), DotSH3(PointIndirectLighting, DiffuseTransferSH));
#if SHADINGMODEL_REQUIRES_BACKFACE_LIGHTING
if (bEvaluateBackface)
{
FThreeBandSHVector SubsurfaceTransferSH = CalcDiffuseTransferSH3(-DiffuseDir, 1);
OutSubsurfaceIndirectLighting += max(half3(0, 0, 0), DotSH3(PointIndirectLighting, SubsurfaceTransferSH));
}
#endif
#else
// Non-directional for translucency
// Ambient terms packed in xyz
// Already divided by PI and SH ambient on CPU
OutDiffuseIndirectLighting += IndirectLightingCache.IndirectLightingSHSingleCoefficient.rgb;
#if SHADINGMODEL_REQUIRES_BACKFACE_LIGHTING
if (bEvaluateBackface)
{
OutSubsurfaceIndirectLighting += IndirectLightingCache.IndirectLightingSHSingleCoefficient.rgb;
}
#endif
#endif
#endif
// Apply indirect lighting scale while we have only accumulated lightmaps
OutDiffuseIndirectLighting *= View.PrecomputedIndirectLightingColorScale;
OutSubsurfaceIndirectLighting *= View.PrecomputedIndirectLightingColorScale;
half3 SkyDiffuseLighting;
half3 SkySubsurfaceLighting;
GetSkyLighting(SkyLightColor, DiffuseDir, bEvaluateBackface, SkyDiffuseLighting, SkySubsurfaceLighting, OutWaterDiffuseIndirectLuminance);
OutDiffuseIndirectLighting += SkyDiffuseLighting;
OutSubsurfaceIndirectLighting += SkySubsurfaceLighting;
#if LQ_TEXTURE_LIGHTMAP || CACHED_POINT_INDIRECT_LIGHTING
OutIndirectIrradiance = Luminance(OutDiffuseIndirectLighting);
#endif
}
PIXELSHADER_EARLYDEPTHSTENCIL
void Main(
FVertexFactoryInterpolantsVSToPS Interpolants
, FMobileBasePassInterpolantsVSToPS BasePassInterpolants
, FStereoPSInput StereoInput
, in float4 SvPosition : SV_Position
OPTIONAL_IsFrontFace
#if MOBILE_USE_GBUFFER
#if USE_GLES_FBF_DEFERRED
, out HALF4_TYPE OutProxy : SV_Target0
#elif MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE_PROGRAMMABLE_BLENDING
, out HALF4_TYPE OutProgrammableBlending : SV_Target0
#else
, out HALF4_TYPE OutColor : SV_Target0
#endif
, out HALF4_TYPE OutGBufferA : SV_Target1
, out HALF4_TYPE OutGBufferB : SV_Target2
, out HALF4_TYPE OutGBufferC : SV_Target3
#if MOBILE_EXTENDED_GBUFFER
, out HALF4_TYPE OutGBufferD : SV_Target4
#endif
#else
#if MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE_DUAL_SRC_BLENDING
, out HALF4_TYPE OutColor DUAL_SOURCE_BLENDING_SLOT(0) : SV_Target0
, out HALF4_TYPE OutColor1 DUAL_SOURCE_BLENDING_SLOT(1) : SV_Target1
#elif MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE_PROGRAMMABLE_BLENDING
, out HALF4_TYPE OutProgrammableBlending : SV_Target0
#else
, out HALF4_TYPE OutColor : SV_Target0
#endif
#endif
#if HAS_SCENE_DEPTH_AUX_OUTPUT
, out float OutSceneDepthAux : SV_TargetDepthAux
#endif
#if OUTPUT_PIXEL_DEPTH_OFFSET
, out float OutDepth : SV_Depth
#endif
)
{
#if MOBILE_USE_GBUFFER
#if USE_GLES_FBF_DEFERRED && !MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE_PROGRAMMABLE_BLENDING
half4 OutColor;
#endif
#if !MOBILE_EXTENDED_GBUFFER
half4 OutGBufferD;
#endif
#endif
#if MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE_PROGRAMMABLE_BLENDING
half4 OutColor;
half4 OutColor1;
#endif
StereoSetupPS(StereoInput);
const uint EyeIndex = GetEyeIndex(StereoInput);
#if USE_GLOBAL_CLIP_PLANE && !PLATFORM_SUPPORTS_CLIP_DISTANCE
clip(BasePassInterpolants.OutClipDistance);
#endif
#if PACK_INTERPOLANTS
float4 PackedInterpolants[NUM_VF_PACKED_INTERPOLANTS];
VertexFactoryUnpackInterpolants(Interpolants, PackedInterpolants);
#endif
FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(Interpolants, SvPosition);
FPixelMaterialInputs PixelMaterialInputs;
{
#if MOBILE_MULTI_VIEW
MaterialParameters.ViewId = EyeIndex;
#endif
float4 ScreenPosition = SvPositionToResolvedScreenPosition(SvPosition);
float3 WorldPosition = BasePassInterpolants.PixelPosition.xyz;
float3 WorldPositionExcludingWPO = BasePassInterpolants.PixelPosition.xyz;
#if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS
WorldPositionExcludingWPO = BasePassInterpolants.PixelPositionExcludingWPO;
#endif
CalcMaterialParametersEx(MaterialParameters, PixelMaterialInputs, SvPosition, ScreenPosition, bIsFrontFace, WorldPosition, WorldPositionExcludingWPO);
#if FORCE_VERTEX_NORMAL
// Quality level override of material's normal calculation, can be used to avoid normal map reads etc.
MaterialParameters.WorldNormal = MaterialParameters.TangentToWorld[2];
MaterialParameters.ReflectionVector = ReflectionAboutCustomWorldNormal(MaterialParameters, MaterialParameters.WorldNormal, false);
#endif
}
#if OUTPUT_PIXEL_DEPTH_OFFSET
ApplyPixelDepthOffsetForMobileBasePass(MaterialParameters, PixelMaterialInputs, OutDepth);
#endif
#if !EARLY_Z_PASS_ONLY_MATERIAL_MASKING
//Clip if the blend mode requires it.
GetMaterialCoverageAndClipping(MaterialParameters, PixelMaterialInputs);
#endif
half MaterialAO = GetMaterialAmbientOcclusion(PixelMaterialInputs);
#if APPLY_AO
{
half4 GatheredAmbientOcclusion = Texture2DSample(AmbientOcclusionTexture, AmbientOcclusionSampler, SvPositionToBufferUV(SvPosition));
MaterialAO *= lerp(1.0, GatheredAmbientOcclusion.r, AmbientOcclusionStaticFraction);
}
#endif
half Opacity = GetMaterialOpacity(PixelMaterialInputs);
#if !SUBSTRATE_ENABLED
// Store the results in local variables and reuse instead of calling the functions multiple times.
half3 BaseColor = max(GetMaterialBaseColorRaw(PixelMaterialInputs), 0.0); // UE-226780 Instead of using GetMaterialBaseColor which does saturate, use max() to avoid driver issue on Adreno V@05xx
half Metallic = GetMaterialMetallic(PixelMaterialInputs);
half Specular = GetMaterialSpecular(PixelMaterialInputs);
// 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.
//
// Note that we also clamp to 1.0 to match the deferred renderer on PC where the roughness is
// stored in an 8-bit value and thus automatically clamped at 1.0.
half Roughness = max(0.015625f, GetMaterialRoughness(PixelMaterialInputs));
half Anisotropy = GetMaterialAnisotropy(PixelMaterialInputs);
uint ShadingModelID = GetMaterialShadingModel(PixelMaterialInputs);
// 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).
float3 SubsurfaceColor = 0;
// 0..1, SubsurfaceProfileId = int(x * 255)
float SubsurfaceProfile = 0;
#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 (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
#endif // !SUBSTRATE_ENABLED
#if SUBSTRATE_ENABLED
// Initialise a Substrate header with normal in registers
FSubstrateData SubstrateData = PixelMaterialInputs.GetFrontSubstrateData();
FSubstratePixelHeader SubstratePixelHeader = MaterialParameters.GetFrontSubstrateHeader();
#if !SUBSTRATE_OPTIMIZED_UNLIT
SubstratePixelHeader.IrradianceAO.MaterialAO = MaterialAO;
SubstratePixelHeader.SetCastContactShadow(GetPrimitiveData(MaterialParameters).Flags & PRIMITIVE_SCENE_DATA_FLAG_HAS_CAST_CONTACT_SHADOW);
SubstratePixelHeader.SetDynamicIndirectShadowCasterRepresentation(GetPrimitiveData(MaterialParameters).Flags & PRIMITIVE_SCENE_DATA_FLAG_HAS_CAPSULE_REPRESENTATION);
#endif
#endif
#if SUBSTRATE_ENABLED && SUBSTRATE_INLINE_SINGLELAYERWATER
SubstratePixelHeader.SetMaterialMode(HEADER_MATERIALMODE_SLWATER);
// Override GBuffer data with Substrate SLW water BSDF to run forward shadfing code.
// SUBSTRATE_TODO: run the shading through a Substrate path? (by adding a special BSDF?)
SubstratePixelHeader.SubstrateTree.BSDFs[0].SubstrateSanitizeBSDF();
FSubstrateBSDF SLWBSDF = SubstratePixelHeader.SubstrateTree.BSDFs[0];
half3 BaseColor = SLW_BASECOLOR(SLWBSDF);
half Metallic = SLW_METALLIC(SLWBSDF);
half Specular = SLW_SPECULAR(SLWBSDF);
half Roughness = SLW_ROUGHNESS(SLWBSDF);
Opacity = SLW_TOPMATERIALOPACITY(SLWBSDF);
MaterialParameters.WorldNormal = normalize(SubstratePixelHeader.SharedLocalBases.Normals[BSDF_GETSHAREDLOCALBASISID(SLWBSDF)]);
half Anisotropy = 0.0f;
uint ShadingModelID = MATERIAL_SHADINGMODEL_SINGLELAYERWATER;
float3 SubsurfaceColor = 0;
float SubsurfaceProfile = 0;
#endif
#if USE_DBUFFER && !MATERIALBLENDING_ANY_TRANSLUCENT && !MATERIAL_SHADINGMODEL_SINGLELAYERWATER
BRANCH
if ((GetPrimitiveData(MaterialParameters).Flags & PRIMITIVE_SCENE_DATA_FLAG_DECAL_RECEIVER) != 0 && View.ShowDecalsMask > 0)
{
#if MATERIALDECALRESPONSEMASK
// Apply decals from the DBuffer.
uint ValidDBufferTargetMask = GetDBufferTargetMask(uint2(SvPosition.xy)) & MATERIALDECALRESPONSEMASK;
BRANCH
if (ValidDBufferTargetMask)
{
float2 BufferUV = SvPositionToBufferUV(SvPosition);
#if SUBSTRATE_ENABLED
#if SUBSTRATE_INLINE_SHADING && !SUBSTRATE_OPTIMIZED_UNLIT
const FSubstrateDBuffer SubstrateBufferData = SubstrateGetDBufferData(BufferUV, ValidDBufferTargetMask, EyeIndex);
ApplyDBufferData(SubstrateBufferData, SubstratePixelHeader, SubstrateData);
#endif
#else
FDBufferData DBufferData = GetDBufferData(BufferUV, ValidDBufferTargetMask, EyeIndex);
ApplyDBufferData(DBufferData, MaterialParameters.WorldNormal, SubsurfaceColor, Roughness, BaseColor, Metallic, Specular);
#endif // SUBSTRATE_ENABLED
MaterialParameters.ReflectionVector = ReflectionAboutCustomWorldNormal(MaterialParameters, MaterialParameters.WorldNormal, false);
}
#endif
}
#endif
#if !SUBSTRATE_ENABLED || SUBSTRATE_INLINE_SINGLELAYERWATER
const half BaseMaterialCoverageOverWater = Opacity;
const half WaterVisibility = 1.0 - 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
half3 WaterDiffuseIndirectLuminance = 0;
FGBufferData GBuffer = (FGBufferData)0;
GBuffer.GBufferAO = MaterialAO;
GBuffer.Depth = MaterialParameters.ScreenPosition.w;
SetGBufferForShadingModel(
GBuffer,
MaterialParameters,
PixelMaterialInputs,
Opacity,
BaseColor,
Metallic,
Specular,
Roughness,
Anisotropy,
SubsurfaceColor,
SubsurfaceProfile,
0.0f,
ShadingModelID
);
GBuffer.StoredBaseColor = GBuffer.BaseColor;
GBuffer.StoredMetallic = GBuffer.Metallic;
GBuffer.StoredSpecular = GBuffer.Specular;
#if MATERIAL_SHADINGMODEL_EYE
if( GBuffer.ShadingModelID == SHADINGMODELID_EYE )
{
GBuffer.Metallic = 0.0;
#if IRIS_NORMAL
GBuffer.Specular = 0.25;
#endif
}
#endif
#if MOBILE_QL_FORCE_NONMETAL
GBuffer.DiffuseColor = GBuffer.BaseColor;
GBuffer.SpecularColor = DielectricSpecularToF0(GBuffer.SpecularColor);
#else
GBuffer.SpecularColor = ComputeF0(GBuffer.Specular, GBuffer.BaseColor, GBuffer.Metallic);
GBuffer.DiffuseColor = GBuffer.BaseColor - GBuffer.BaseColor * GBuffer.Metallic;
#endif
#if FULLY_ROUGH
EnvBRDFApproxFullyRough(GBuffer.DiffuseColor, GBuffer.SpecularColor);
#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
#if MATERIAL_NORMAL_CURVATURE_TO_ROUGHNESS
// Curvature-to-roughness uses derivatives of the WorldVertexNormal, which is incompatible with centroid interpolation because
// the samples are not uniformly distributed. Therefore we use WorldVertexNormal_Center which is guaranteed to be center interpolated.
#if USE_WORLDVERTEXNORMAL_CENTER_INTERPOLATION
float GeometricAARoughness = NormalCurvatureToRoughness(MaterialParameters.WorldVertexNormal_Center);
#else
float GeometricAARoughness = NormalCurvatureToRoughness(MaterialParameters.TangentToWorld[2].xyz);
#endif
GBuffer.Roughness = max(GBuffer.Roughness, GeometricAARoughness);
#if MATERIAL_SHADINGMODEL_CLEAR_COAT
if (GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT)
{
GBuffer.CustomData.y = max(GBuffer.CustomData.y, GeometricAARoughness);
}
#endif
#endif
half3 InputBentNormal = MaterialParameters.WorldNormal;
// Clear Coat Bottom Normal
#if MATERIAL_SHADINGMODEL_CLEAR_COAT
BRANCH if (GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT && CLEAR_COAT_BOTTOM_NORMAL)
{
const float2 oct1 = ((float2(GBuffer.CustomData.a, GBuffer.CustomData.z) * 4) - (512.0 / 255.0)) + UnitVectorToOctahedron(GBuffer.WorldNormal);
InputBentNormal = OctahedronToUnitVector(oct1);
}
#endif
const FShadingOcclusion ShadingOcclusion = ApplyBentNormal(MaterialParameters.CameraVector, InputBentNormal, GetWorldBentNormalZero(MaterialParameters), GBuffer.Roughness, GBuffer.GBufferAO);
GBuffer.GBufferAO = AOMultiBounce(Luminance(GBuffer.SpecularColor), ShadingOcclusion.SpecOcclusion).g;
#endif // !SUBSTRATE_ENABLED || SUBSTRATE_INLINE_SINGLELAYERWATER
VTPageTableResult LightmapVTPageTableResult = (VTPageTableResult)0.0f;
#if LIGHTMAP_VT_ENABLED
{
float2 LightmapUV0, LightmapUV1;
uint LightmapDataIndex;
GetLightMapCoordinates(Interpolants, LightmapUV0, LightmapUV1, LightmapDataIndex);
LightmapVTPageTableResult = LightmapGetVTSampleInfo(LightmapUV0, LightmapDataIndex, SvPosition.xy);
}
#endif
#if LIGHTMAP_VT_ENABLED
// This must occur after CalcMaterialParameters(), which is required to initialize the VT feedback mechanism
// Lightmap request is always the first VT sample in the shader
StoreVirtualTextureFeedback(MaterialParameters.VirtualTextureFeedback, 0, LightmapVTPageTableResult.PackedRequest, LightmapVTPageTableResult.PendingMips);
#endif
#if SUBSTRATE_ENABLED && !SUBSTRATE_INLINE_SINGLELAYERWATER
float3 Color = 0;
float3 DualBlendSurfaceLuminancePostCoverage = 0.0f;
float3 DualBlendSurfaceTransmittancePreCoverage = 1.0f;
float DualBlendSurfaceCoverage = 1.0f;
#if !SUBSTRATE_OPTIMIZED_UNLIT
// Static shadow mask
#if GBUFFER_HAS_PRECSHADOWFACTOR
{
// Encode shadow mask only if the shadow mask is entirely non-zero and non-one
#if WRITES_PRECSHADOWFACTOR_ZERO
SubstratePixelHeader.SetHasPrecShadowMask(false);
SubstratePixelHeader.SetZeroPrecShadowMask(true);
#else
#if ALLOW_STATIC_LIGHTING
const bool bAllZero = all(GBuffer.PrecomputedShadowFactors == 0);
const bool bAllOne = all(GBuffer.PrecomputedShadowFactors == 1);
if (!bAllZero && !bAllOne)
{
SubstratePixelHeader.SetHasPrecShadowMask(true);
}
else if (bAllZero)
{
SubstratePixelHeader.SetHasPrecShadowMask(false);
SubstratePixelHeader.SetZeroPrecShadowMask(true);
}
else if (bAllOne)
#endif
{
SubstratePixelHeader.SetHasPrecShadowMask(false);
SubstratePixelHeader.SetZeroPrecShadowMask(false);
}
#endif
}
#endif
#if SUBSTRATE_INLINE_SHADING
// We must normalize each normal and tangent to avoid non normalised vectors due to per vertex interpolation or texture filtering,
// for the deferred (our packing relies on normalized normal) and forward (normals are going to be used as-is from registers) paths.
#if SUBSTRATE_FORCE_SINGLE_BSDF
uint i = 0;
if (SubstratePixelHeader.SharedLocalBases.Count > 0)
#else
UNROLL
for (uint i = 0; i < SubstratePixelHeader.SharedLocalBases.Count; ++i)
#endif // SUBSTRATE_FORCE_SINGLE_BSDF
{
SubstratePixelHeader.SharedLocalBases.Normals[i] = normalize(SubstratePixelHeader.SharedLocalBases.Normals[i]);
if (SubstrateGetSharedLocalBasisType(SubstratePixelHeader.SharedLocalBases.Types, i) == SUBSTRATE_BASIS_TYPE_TANGENT)
{
SubstratePixelHeader.SharedLocalBases.Tangents[i] = normalize(SubstratePixelHeader.SharedLocalBases.Tangents[i]);
}
}
#endif // SUBSTRATE_INLINE_SHADING
FLightAccumulator DirectLighting = (FLightAccumulator)0;
half3 CameraVector = -MaterialParameters.CameraVector;
float2 ScreenUV = ScreenPositionToBufferUV(MaterialParameters.ScreenPosition);
#if MATERIAL_SUBSTRATE_OPAQUE_PRECOMPUTED_LIGHTING
#if SUBSTRATE_INLINE_SINGLELAYERWATER==0
// Need to reset color to make sure Substrate material are only lit using Substrate lighting passes.
// Except for water doing some specialised and simplified lighting during the base pass
Color = 0;
#endif
{
SubstratePixelHeader.IrradianceAO = InitIrradianceAndOcclusion();
SubstratePixelHeader.IrradianceAO.MaterialAO = MaterialAO; // This is the material AO, it will be converted to multibounce AO using ShadingOcclusion.SpecOcclusion in the PackSubstrateOut function, also accounting for bent normal.
SubstratePixelHeader.IrradianceAO.IndirectIrradiance = 0; // SUBSTRATE_TODO
SubstratePixelHeader.IrradianceAO.DiffuseIndirectSampleOcclusion = 0; // SUBSTRATE_TODO GetDiffuseIndirectSampleOcclusion(SubstratePixelHeader.SharedLocalBases, MaterialParameters.CameraVector, SvPosition.xy, SubstratePixelHeader.IrradianceAO.MaterialAO);
}
// We only rely on this GBuffer structure for the write out to legacy render target such as velocity or precomputed shadow factors
FGBufferData GBuffer = (FGBufferData)0;
GBuffer.PrecomputedShadowFactors = GetPrimaryPrecomputedShadowMask(LightmapVTPageTableResult, Interpolants, MaterialParameters);
#if OUTPUT_PIXEL_DEPTH_OFFSET && SUBSTRATE_INLINE_SINGLELAYERWATER==0 && 0 // We use the legacy GBuffer format for now, so this is disabled.
// When in deferred, opaque materials with pixel depth offset must execute a custom depth test in order to avoid conflicting UAV writes.
// This is however not done for single layer water as the depth will never match. Note: that can lead overlapping SLW polys to cause flicker on screen.
if (ManualDepthTestEqual(SvPosition, OutDepth))
#endif
{
uint2 PixelPos = uint2(SvPosition.xy);
FSubstrateSubsurfaceData SSSData = (FSubstrateSubsurfaceData)0;
FSubstrateTopLayerData TopLayerData = (FSubstrateTopLayerData)0;
FSubstrateOpaqueRoughRefractionData OpaqueRoughRefractionData = (FSubstrateOpaqueRoughRefractionData)0;
FSubstrateIntegrationSettings Settings = InitSubstrateIntegrationSettings(FULLY_ROUGH, SubstrateStruct.bRoughDiffuse, SubstrateStruct.PeelLayersAboveDepth, SubstrateStruct.bRoughnessTracking);
#if SUBSTRATE_ADVANCED_DEBUG_ENABLED
Settings.SliceStoringDebugSubstrateTreeData = all(uint2(float2(View.CursorPosition) * View.ViewResolutionFraction) == PixelPos) ? SubstrateStruct.SliceStoringDebugSubstrateTreeDataWithoutMRT : Settings.SliceStoringDebugSubstrateTreeData;
#endif
const float3 SurfaceWorldNormal = MaterialParameters.TangentToWorld[2].xyz;
FExportResult Export = SubstrateMaterialExportOut(
Settings,
SubstratePixelHeader,
SubstrateData,
SurfaceWorldNormal,
MaterialParameters.WorldPosition_CamRelative,
#if SHADING_PATH_MOBILE && MATERIAL_SUBSURFACE_PROFILE_USE_CURVATURE
GetMaterialCustomData0(PixelMaterialInputs)
#else
0.0f
#endif
);
GBuffer.GBufferAO = MaterialAO;
GBuffer.Depth = MaterialParameters.ScreenPosition.w;
// Patch material parameter to not have to change the function for now
MaterialParameters.WorldNormal = Export.WorldNormal;
MaterialParameters.WorldTangent = Export.WorldTangent;
#if USE_WORLDVERTEXNORMAL_CENTER_INTERPOLATION
MaterialParameters.WorldVertexNormal_Center = Export.WorldNormal; // SUBSTRATE_TODO: how to evluate it for center?
#endif
MaterialParameters.TangentToWorld[2].xyz = Export.WorldTangent;
SetGBufferForShadingModel(
GBuffer,
MaterialParameters,
PixelMaterialInputs,
Export.Coverage, // Opacity
Export.BaseColor,
Export.Metallic,
Export.Specular,
Export.Roughness,
Export.Anisotropy,
Export.SubsurfaceColor,
Export.SubsurfaceProfileID,
0.0f, // Dither
Export.ShadingModelID
);
// Set custom data from Substrate export after SetGBufferForShadingModel since it access MaterialParameters to set specific data not available with Substrate
GBuffer.CustomData = Export.CustomData;
GBuffer.StoredBaseColor = GBuffer.BaseColor;
GBuffer.StoredMetallic = GBuffer.Metallic;
GBuffer.StoredSpecular = GBuffer.Specular;
#if MATERIAL_SHADINGMODEL_EYE
if( GBuffer.ShadingModelID == SHADINGMODELID_EYE )
{
GBuffer.Metallic = 0.0;
#if IRIS_NORMAL
GBuffer.Specular = 0.25;
#endif
}
#endif
#if MOBILE_QL_FORCE_NONMETAL
GBuffer.DiffuseColor = GBuffer.BaseColor;
GBuffer.SpecularColor = DielectricSpecularToF0(GBuffer.SpecularColor);
#else
GBuffer.SpecularColor = ComputeF0(GBuffer.Specular, GBuffer.BaseColor, GBuffer.Metallic);
GBuffer.DiffuseColor = GBuffer.BaseColor - GBuffer.BaseColor * GBuffer.Metallic;
#endif
#if FULLY_ROUGH
EnvBRDFApproxFullyRough(GBuffer.DiffuseColor, GBuffer.SpecularColor);
#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
#if MATERIAL_NORMAL_CURVATURE_TO_ROUGHNESS
// Curvature-to-roughness uses derivatives of the WorldVertexNormal, which is incompatible with centroid interpolation because
// the samples are not uniformly distributed. Therefore we use WorldVertexNormal_Center which is guaranteed to be center interpolated.
#if USE_WORLDVERTEXNORMAL_CENTER_INTERPOLATION
float GeometricAARoughness = NormalCurvatureToRoughness(MaterialParameters.WorldVertexNormal_Center);
#else
float GeometricAARoughness = NormalCurvatureToRoughness(MaterialParameters.TangentToWorld[2].xyz);
#endif
GBuffer.Roughness = max(GBuffer.Roughness, GeometricAARoughness);
#if MATERIAL_SHADINGMODEL_CLEAR_COAT
if (GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT)
{
GBuffer.CustomData.y = max(GBuffer.CustomData.y, GeometricAARoughness);
}
#endif
#endif
half3 InputBentNormal = MaterialParameters.WorldNormal;
// Clear Coat Bottom Normal
#if MATERIAL_SHADINGMODEL_CLEAR_COAT
BRANCH if (GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT && CLEAR_COAT_BOTTOM_NORMAL)
{
const float2 oct1 = ((float2(GBuffer.CustomData.a, GBuffer.CustomData.z) * 4) - (512.0 / 255.0)) + UnitVectorToOctahedron(GBuffer.WorldNormal);
InputBentNormal = OctahedronToUnitVector(oct1);
}
#endif
const float3 WorldBentNormal0 = GetWorldBentNormalZero(MaterialParameters);
const FShadingOcclusion ShadingOcclusion = ApplyBentNormal(MaterialParameters.CameraVector, InputBentNormal, WorldBentNormal0, GBuffer.Roughness, GBuffer.GBufferAO);
GBuffer.GBufferAO = AOMultiBounce(Luminance(GBuffer.SpecularColor), ShadingOcclusion.SpecOcclusion).g;
half3 SubsurfaceColor = 0;// SUBSTRATE_TODO
half3 WaterDiffuseIndirectLuminance = 0;
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
#if MATERIAL_SHADINGMODEL_CLOTH
if (GBuffer.ShadingModelID == SHADINGMODELID_CLOTH)
{
DiffuseColorForIndirect += SubsurfaceColor * saturate(GetMaterialCustomData0(PixelMaterialInputs));
}
#endif
#if MATERIAL_SHADINGMODEL_HAIR
if (GBuffer.ShadingModelID == SHADINGMODELID_HAIR)
{
const half3 N = MaterialParameters.WorldNormal;
const half3 V = MaterialParameters.CameraVector;
DiffuseColorForIndirect = EvaluateEnvHair(GBuffer, V, N, DiffuseDir);
}
#endif
//half NoL = max(0, dot(GBuffer.WorldNormal, MobileDirectionalLight.DirectionalLightDirectionAndShadowTransition.xyz));
const bool bEvaluateBackface = GetShadingModelRequiresBackfaceLighting(GBuffer.ShadingModelID);
GetPrecomputedIndirectLightingAndSkyLight(LightmapVTPageTableResult, Interpolants, bEvaluateBackface, DiffuseDir, ResolvedView.SkyLightColor.rgb, DiffuseIndirectLighting, SubsurfaceIndirectLighting, IndirectIrradiance, WaterDiffuseIndirectLuminance);
// 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);
#if MATERIAL_SHADINGMODEL_SINGLELAYERWATER
// Fade out diffuse as this will be handled by the single scattering lighting in water material.
// We do this after the just above GetPrecomputedIndirectLightingAndSkyLight to keep ambiant lighting avialable.
// We also keep the SpecularColor for sun/water interactions.
GBuffer.DiffuseColor *= BaseMaterialCoverageOverWater;
DiffuseColor *= BaseMaterialCoverageOverWater;
DiffuseColorForIndirect *= BaseMaterialCoverageOverWater;
#endif
// This is deferred, should od the same for Substrate GBuffer
FLightAccumulator DirectLighting = (FLightAccumulator)0;
LightAccumulator_AddSplit(DirectLighting, DiffuseColor, 0.0f, DiffuseColor, 1.0f, false);
GBuffer.IndirectIrradiance = IndirectIrradiance * Export.IndirectIrradianceScale;
MobileEncodeGBuffer(GBuffer, OutGBufferA, OutGBufferB, OutGBufferC, OutGBufferD);
Color = DirectLighting.TotalLight;
}
#endif // MATERIAL_SUBSTRATE_OPAQUE_PRECOMPUTED_LIGHTING
#if (SUBSTRATE_TRANSLUCENT_FORWARD || SUBSTRATE_FORWARD_SHADING) && !MATERIAL_SUBSTRATE_OPAQUE_PRECOMPUTED_LIGHTING
#define SUBSTRATE_DEBUG_ENABLE_LIGHTING 1
#if SUBSTRATE_DEBUG_ENABLE_LIGHTING
if (SubstratePixelHeader.ClosureCount > 0)
{
#if FULLY_ROUGH
const bool bForceFullyRough = true;
#else
const bool bForceFullyRough = View.RenderingReflectionCaptureMask > 0; // Can mobile capture reflection probe? Is this needed for mobile?
#endif
FSubstrateIntegrationSettings Settings = InitSubstrateIntegrationSettings(bForceFullyRough, SubstrateStruct.bRoughDiffuse, SubstrateStruct.PeelLayersAboveDepth, Substrate.bRoughnessTracking);
// TODO: needed? Remove?
float3 VolumetricLightmapBrickTextureUVs = 0;
const float SceneDepth = MaterialParameters.ScreenPosition.w;;
Color = SubstrateMobileForwardLighting(
EyeIndex,
SvPosition,
Settings,
BasePassInterpolants,
Interpolants,
LightmapVTPageTableResult,
VolumetricLightmapBrickTextureUVs,
MaterialParameters,
SceneDepth,
ScreenUV,
SubstratePixelHeader,
SubstrateData,
DualBlendSurfaceTransmittancePreCoverage,
DualBlendSurfaceCoverage);
#if SUBSTRATE_TRANSLUCENT_MATERIAL
DualBlendSurfaceLuminancePostCoverage = Color;
Color = 0.0f;
Opacity = 1.0f; // nullify following operation
#elif SUBSTRATE_FORWARD_SHADING
// Color unchanged for opaque materials
Opacity = 1.0f;
#else
#error Unhandled Substrate forward shading mode
#endif
}
#endif // SUBSTRATE_DEBUG_ENABLE_LIGHTING
#endif // SUBSTRATE_TRANSLUCENT_FORWARD || SUBSTRATE_FORWARD_SHADING
#else // SUBSTRATE_OPTIMIZED_UNLIT
// Unlit BSDF goes through the SubstrateTree to support weighting operations. Technically, layering and mixing could also be supported.
float3 UnlitSurfaceNormal = 0.0f;
SubstratePixelHeader.SubstrateUpdateTreeUnlit(
uint2(SvPosition.xy),
MaterialParameters.CameraVector,
SubstrateData,
DualBlendSurfaceLuminancePostCoverage,
DualBlendSurfaceCoverage,
DualBlendSurfaceTransmittancePreCoverage,
UnlitSurfaceNormal);
Color = 0.0f;
Opacity = 1.0f;
#endif // SUBSTRATE_OPTIMIZED_UNLIT
half4 Fogging = half4(0, 0, 0, 1);
#if USE_VERTEX_FOG
{
#if PACK_INTERPOLANTS
Fogging = PackedInterpolants[0];
#else
Fogging = BasePassInterpolants.VertexFog;
#endif
}
#endif
// Compute final value
{
#if SUBSTRATE_OPAQUE_MATERIAL && SUBSTRATE_OPTIMIZED_UNLIT
OutColor = float4(DualBlendSurfaceLuminancePostCoverage, 1);
#elif SUBSTRATE_OPAQUE_MATERIAL
OutColor = float4(Color, 1);
#endif
#if SUBSTRATE_TRANSLUCENT_MATERIAL
#if SUBSTRATE_USE_PREMULTALPHA_OVERRIDE // AlphaComposite - Premultiplied alpha blending
DualBlendSurfaceTransmittancePreCoverage= 0.0;
DualBlendSurfaceCoverage = GetMaterialOpacity(PixelMaterialInputs);
#endif
// Add fog luminance according to surfacecoverage and reduce surface luminance according to fog coverage.
float3 AdjustedDualBlendAdd = DualBlendSurfaceCoverage * Fogging.rgb + Fogging.a * DualBlendSurfaceLuminancePostCoverage;
// Fade the surface color transmittance out to 1 according to the surface coverage, and take into account the fog coverage to the surface.
float3 AdjustedDualBlendMul = lerp(1.0f, Fogging.a * DualBlendSurfaceTransmittancePreCoverage, DualBlendSurfaceCoverage);
#if SUBSTRATE_BLENDING_COLOREDTRANSMITTANCEONLY
// RETURN_COLOR not needed with modulative blending
half3 FoggedColor = lerp(float3(1, 1, 1), DualBlendSurfaceTransmittancePreCoverage, Fogging.aaa* DualBlendSurfaceCoverage);
OutColor = half4(FoggedColor, 1.0f);
#elif SUBSTRATE_BLENDING_ALPHAHOLDOUT
half AdjustedAlpha = saturate(1 - dot(AdjustedDualBlendMul, half3(1.0f, 1.0f, 1.0f) / 3.0f));
OutColor = half4(0.0f.xxx, AdjustedAlpha);
#elif MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE && MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE_DUAL_SRC_BLENDING
OutColor = half4(AdjustedDualBlendAdd, 0.0);
OutColor1 = half4(AdjustedDualBlendMul, 1.0);
#else
// Pre multipled alpha blending
half AdjustedAlpha = saturate(1 - dot(AdjustedDualBlendMul, half3(1.0f, 1.0f, 1.0f) / 3.0f));
#if SUBSTRATE_USES_CONVERSION_FROM_LEGACY && MATERIALBLENDING_ADDITIVE
AdjustedAlpha = 0.0f;
#endif
// Pre multipled alpha blending
OutColor = half4(AdjustedDualBlendAdd, AdjustedAlpha);
#endif
#endif // SUBSTRATE_TRANSLUCENT_MATERIAL
}
#else // SUBSTRATE_ENABLED
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
#if MATERIAL_SHADINGMODEL_CLOTH
if (GBuffer.ShadingModelID == SHADINGMODELID_CLOTH)
{
DiffuseColorForIndirect += SubsurfaceColor * saturate(GetMaterialCustomData0(PixelMaterialInputs));
}
#endif
#if MATERIAL_SHADINGMODEL_HAIR
if (GBuffer.ShadingModelID == SHADINGMODELID_HAIR)
{
const half3 N = MaterialParameters.WorldNormal;
const half3 V = MaterialParameters.CameraVector;
DiffuseColorForIndirect = EvaluateEnvHair(GBuffer, V, N, DiffuseDir);
}
#endif
half NoL = max(0, dot(GBuffer.WorldNormal, MobileDirectionalLight.DirectionalLightDirectionAndShadowTransition.xyz));
const bool bEvaluateBackface = GetShadingModelRequiresBackfaceLighting(GBuffer.ShadingModelID);
GetPrecomputedIndirectLightingAndSkyLight(LightmapVTPageTableResult, Interpolants, bEvaluateBackface, DiffuseDir, ResolvedView.SkyLightColor.rgb, DiffuseIndirectLighting, SubsurfaceIndirectLighting, IndirectIrradiance, WaterDiffuseIndirectLuminance);
// 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);
#if MATERIAL_SHADINGMODEL_SINGLELAYERWATER
// Fade out diffuse as this will be handled by the single scattering lighting in water material.
// We do this after the just above GetPrecomputedIndirectLightingAndSkyLight to keep ambiant lighting avialable.
// We also keep the SpecularColor for sun/water interactions.
GBuffer.DiffuseColor *= BaseMaterialCoverageOverWater;
DiffuseColor *= BaseMaterialCoverageOverWater;
DiffuseColorForIndirect *= BaseMaterialCoverageOverWater;
#endif
FLightAccumulator DirectLighting = (FLightAccumulator)0;
LightAccumulator_AddSplit(DirectLighting, DiffuseColor, 0.0f, DiffuseColor, 1.0f, false);
GBuffer.PrecomputedShadowFactors = GetPrimaryPrecomputedShadowMask(LightmapVTPageTableResult, Interpolants, MaterialParameters);
#if MOBILE_USE_GBUFFER
GBuffer.IndirectIrradiance = IndirectIrradiance;
MobileEncodeGBuffer(GBuffer, OutGBufferA, OutGBufferB, OutGBufferC, OutGBufferD);
#else
half3 CameraVector = -MaterialParameters.CameraVector;
half4 DynamicShadowFactors = 1.0f;
float DirectionalLightShadow = 1.0f;
// Directional light
#if !MATERIAL_SHADINGMODEL_UNLIT
AccumulateDirectionalLighting(GBuffer, MaterialParameters.WorldPosition_CamRelative, CameraVector, MaterialParameters.ScreenPosition, SvPosition, DynamicShadowFactors, DirectionalLightShadow, DirectLighting, EyeIndex);
#endif
float2 LocalPosition = SvPosition.xy - ResolvedView.ViewRectMin.xy;
uint GridIndex = ComputeLightGridCellIndex(uint2(LocalPosition.x, LocalPosition.y), SvPosition.w, EyeIndex);
#if MATERIALBLENDING_MASKED || MATERIALBLENDING_SOLID || TRANSLUCENCY_LIGHTING_SURFACE_FORWARDSHADING || TRANSLUCENCY_LIGHTING_SURFACE_LIGHTINGVOLUME || MATERIAL_SHADINGMODEL_SINGLELAYERWATER
// Reflection IBL
AccumulateReflection(GBuffer
, SvPosition
, CameraVector
, MaterialParameters.WorldPosition_CamRelative
, MaterialParameters.ReflectionVector
, IndirectIrradiance
, GridIndex
, DirectLighting);
#endif
// Local lights
#if MERGED_LOCAL_LIGHTS_MOBILE == 1
{
FDeferredLightData MergedLightData = (FDeferredLightData)0;
half3 LocalLightA = MobileSceneTextures.LocalLightTextureA.Load(int3(SvPosition.xy, 0)).xyz;
half4 LocalLightB = MobileSceneTextures.LocalLightTextureB.Load(int3(SvPosition.xy, 0));
MergedLightData.SourceRadius = 0;
MergedLightData.SourceLength = 0;
MergedLightData.Tangent = 0;
MergedLightData.SoftSourceRadius= 0;
MergedLightData.SpecularScale = LocalLightB.a;
MergedLightData.DiffuseScale = 1.f; // Diffuse scale is not handled with merged light
MergedLightData.bSpotLight = false;
MergedLightData.bRectLight = false;
MergedLightData.Color = LocalLightA.rgb;
MergedLightData.bRadialLight = false;
half4 LightAttenuation = half4(1, 1, 1, 1);
float SurfaceShadow = 0;
MergedLightData.Direction = OctahedronToUnitVector(Pack888To1212(LocalLightB.rgb) * 2 - 1);
FLightAccumulator NewLighting = AccumulateDynamicLighting(MaterialParameters.WorldPosition_CamRelative, CameraVector, GBuffer, 1, MergedLightData, LightAttenuation, 0, uint2(0, 0), SurfaceShadow);
DirectLighting = LightAccumulator_Add(DirectLighting, NewLighting);
}
#elif MERGED_LOCAL_LIGHTS_MOBILE == 2
{
const FCulledLightsGridHeader CulledLightGridHeader = GetCulledLightsGridHeader(GridIndex);
float3 MergedLightColor = uint3(0.f, 0.f , 0.f);
float3 MergedLightL = float3(0,0,0);
float MergedSpecularScale = 0.f;
float MergedTotalWeight = 0;
MergeLocalLights(CulledLightGridHeader, MaterialParameters.WorldPosition_CamRelative, EyeIndex, false, MergedLightColor, MergedLightL, MergedSpecularScale, MergedTotalWeight, GBuffer.WorldNormal);
if(MergedTotalWeight > 0.f)
{
MergedLightL = MergedLightL / MergedTotalWeight;
MergedSpecularScale = MergedSpecularScale / MergedTotalWeight;
FDeferredLightData MergedLightData = (FDeferredLightData)0;
MergedLightData.SourceRadius = 0;
MergedLightData.SourceLength = 0;
MergedLightData.Tangent = 0;
MergedLightData.SoftSourceRadius= 0;
MergedLightData.SpecularScale = MergedSpecularScale;
MergedLightData.DiffuseScale = 1.f; // Diffuse scale is not handled with merged light
MergedLightData.bSpotLight = false;
MergedLightData.bRectLight = false;
MergedLightData.Color = MergedLightColor;
MergedLightData.bRadialLight = false;
half4 LightAttenuation = half4(1, 1, 1, 1);
float SurfaceShadow = 0;
MergedLightData.Direction = MergedLightL;
FLightAccumulator NewLighting = AccumulateDynamicLighting(MaterialParameters.WorldPosition_CamRelative, CameraVector, GBuffer, 1, MergedLightData, LightAttenuation, 0, uint2(0, 0), SurfaceShadow);
DirectLighting = LightAccumulator_Add(DirectLighting, NewLighting);
}
}
#elif (!MATERIAL_SHADINGMODEL_SINGLELAYERWATER && ENABLE_CLUSTERED_LIGHTS)
{
const FCulledLightsGridHeader CulledLightGridHeader = GetCulledLightsGridHeader(GridIndex);
half4 LocalLightDynamicShadowFactors = 1.0f;
#if USE_SHADOWMASKTEXTURE
LocalLightDynamicShadowFactors = DynamicShadowFactors;
#endif
uint LightingChannelMask = GetPrimitive_LightingChannelMask(MaterialParameters.PrimitiveId);
AccumulateLightGridLocalLighting(CulledLightGridHeader, GBuffer, MaterialParameters.WorldPosition_CamRelative, CameraVector, EyeIndex, 0, LocalLightDynamicShadowFactors, LightingChannelMask, DirectLighting);
}
#endif
#if MATERIAL_SHADINGMODEL_SINGLELAYERWATER
{
const bool bSeparateMainDirLightLuminance = false;
float3 SeparatedWaterMainDirLightLuminance = float3(0, 0, 0);
const bool CameraIsUnderWater = false; // Fade out the material contribution over to water contribution according to material opacity.
float3 SunIlluminance = ResolvedView.DirectionalLightColor.rgb * PI; // times PI because it is divided by PI on CPU (=luminance) and we want illuminance here.
float3 WaterDiffuseIndirectIlluminance = WaterDiffuseIndirectLuminance * PI; // DiffuseIndirectLighting is luminance. So we need to multiply by PI to get illuminance.
#if MOBILE_EMULATION
SunIlluminance = lerp(SunIlluminance, 0.0f, View.UnlitViewmodeMask);
WaterDiffuseIndirectIlluminance = lerp(WaterDiffuseIndirectIlluminance, PI, View.UnlitViewmodeMask);
#endif
half3 N = GBuffer.WorldNormal;
half3 V = MaterialParameters.CameraVector;
half NoV = saturate(abs(dot(N, V)) + 1e-5);
const float3 EnvBrdf = GetEnvBRDF(GBuffer.SpecularColor, GBuffer.Roughness, NoV);
const float4 NullDistortionParams = 1.0f;
WaterVolumeLightingOutput WaterLighting = EvaluateWaterVolumeLighting(
MaterialParameters, PixelMaterialInputs, ResolvedView,
DirectionalLightShadow, GBuffer.Specular, NullDistortionParams,
SunIlluminance, WaterDiffuseIndirectIlluminance, EnvBrdf,
CameraIsUnderWater, WaterVisibility, EyeIndex,
bSeparateMainDirLightLuminance, SeparatedWaterMainDirLightLuminance);
// Accumulate luminance and occlude the background according to transmittance to view and mean transmittance to lights.
LightAccumulator_AddSplit(DirectLighting, WaterLighting.Luminance, 0.0f, WaterLighting.Luminance, 1.0f, false);
Opacity = 1.0 - ((1.0 - Opacity) * dot(WaterLighting.WaterToSceneToLightTransmittance, float3(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)));
#if MOBILE_EMULATION
DiffuseColorForIndirect += WaterLighting.Luminance;
#endif
}
#endif // MATERIAL_SHADINGMODEL_SINGLELAYERWATER
#endif// DEFERRED_SHADING_PATH
#endif // SUBSTRATE_ENABLED
#if !SUBSTRATE_ENABLED || SUBSTRATE_INLINE_SINGLELAYERWATER
#if !MATERIAL_SHADINGMODEL_UNLIT
half3 Color = DirectLighting.TotalLight;
#else
half3 Color = 0.0f;
#endif
half4 VertexFog = half4(0, 0, 0, 1);
#if USE_VERTEX_FOG
#if PACK_INTERPOLANTS
VertexFog = PackedInterpolants[0];
#else
VertexFog = BasePassInterpolants.VertexFog;
#endif
#endif
// NEEDS_BASEPASS_PIXEL_FOGGING is not allowed on mobile for the sake of performance.
#if !MATERIAL_SHADINGMODEL_UNLIT && MOBILE_EMULATION
Color = lerp(Color, DiffuseColorForIndirect, ResolvedView.UnlitViewmodeMask);
#endif
half3 Emissive = GetMaterialEmissive(PixelMaterialInputs);
Color += Emissive;
#if MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT && !SUBSTRATE_ENABLED
half3 DualBlendSurfaceLuminancePostCoverage = 0.0f;
half3 DualBlendSurfaceTransmittancePreCoverage = 1.0f;
half DualBlendSurfaceCoverage = 1.0f;
{
AccumulateThinTranslucentModel(
DualBlendSurfaceLuminancePostCoverage,
DualBlendSurfaceTransmittancePreCoverage,
DualBlendSurfaceCoverage,
MaterialParameters,
GBuffer,
DirectLighting.TotalLightDiffuse,
DirectLighting.TotalLightSpecular,
Emissive,
Opacity);
Color = 0;
Opacity = 1.0f;
}
#endif // MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT
// MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT must come first because it also has MATERIALBLENDING_TRANSLUCENT defined
#if MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE
// Add fog luminance according to surfacecoverage and reduce surface luminance according to fog coverage.
half3 AdjustedDualBlendAdd = DualBlendSurfaceCoverage * VertexFog.rgb + VertexFog.a * DualBlendSurfaceLuminancePostCoverage;
// Fade the surface color transmittance out to 1 according to the surface coverage, and take into account the fog coverage to the surface.
half3 AdjustedDualBlendMul = lerp(1.0f, VertexFog.a * DualBlendSurfaceTransmittancePreCoverage, DualBlendSurfaceCoverage);
#if MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE_SINGLE_SRC_BLENDING
// In the fallback case, use standard alpha blending(grey scale transmittance)
half AdjustedAlpha = saturate(1 - dot(AdjustedDualBlendMul, half3(1.0f, 1.0f, 1.0f) / 3.0f));
OutColor = half4(AdjustedDualBlendAdd, AdjustedAlpha);
#else
OutColor = half4(AdjustedDualBlendAdd, 0.0);
OutColor1 = half4(AdjustedDualBlendMul, 1.0);
#endif
// On mobile, water (an opaque material) is rendered as trnaslucent with forced premultiplied alpha blending (see MobileBasePass::SetTranslucentRenderState)
#elif MATERIALBLENDING_ALPHACOMPOSITE || MATERIAL_SHADINGMODEL_SINGLELAYERWATER
OutColor = half4(Color * VertexFog.a + VertexFog.rgb * Opacity, Opacity);
#elif MATERIALBLENDING_ALPHAHOLDOUT
// not implemented for holdout
OutColor = half4(Color * VertexFog.a + VertexFog.rgb * Opacity, Opacity);
#elif MATERIALBLENDING_TRANSLUCENT
OutColor = half4(Color * VertexFog.a + VertexFog.rgb, Opacity);
#elif MATERIALBLENDING_ADDITIVE
OutColor = half4(Color * (VertexFog.a * Opacity.x), 0.0f);
#elif MATERIALBLENDING_MODULATE
half3 FoggedColor = lerp(half3(1, 1, 1), Color, VertexFog.aaa * VertexFog.aaa);
OutColor = half4(FoggedColor, Opacity);
#else
OutColor.rgb = Color * VertexFog.a + VertexFog.rgb;
#if !MATERIAL_USE_ALPHA_TO_COVERAGE
// Planar reflections and scene captures use scene color alpha to keep track of where content has been rendered, for compositing into a different scene later
OutColor.a = 0.0;
#else
half MaterialOpacityClip = GetMaterialOpacityMaskClipValue();
float Mask = GetMaterialMask(PixelMaterialInputs) / (1.0 - MaterialOpacityClip);
OutColor.a = uint((Mask + 0.25f) * 4.0f) / 4.0f;
#endif
#endif
#endif // SUBSTRATE_ENABLED
#if HAS_SCENE_DEPTH_AUX_OUTPUT
OutSceneDepthAux = SvPosition.z;
#endif
#if !MATERIALBLENDING_MODULATE
#if MATERIAL_IS_SKY
// Dynamic capture exposure is 1 as of today.
const float ViewPreExposure = View.RealTimeReflectionCapture > 0.0f ? View.RealTimeReflectionCapturePreExposure : View.PreExposure;
#else
const float ViewPreExposure = View.PreExposure;
#endif
OutColor.rgb *= ViewPreExposure;
#endif
#if MATERIAL_IS_SKY
if (MobileBasePass.bApplyHalfResLocalFogToSkyMeshes)
{
// Apply the half resolution texture to the sky dome mesh when needed.
const float2 ResolutionRatioCorrection = (ResolvedView.ViewSizeAndInvSize.xy * MobileBasePass.LFV.HalfResTextureSizeAndInvSize.zw * 0.5);
const float2 HalfResSourceTexCoord = float2(SvPosition.xy - ResolvedView.ViewRectMin.xy) * ResolvedView.ViewSizeAndInvSize.zw * ResolutionRatioCorrection;
float4 LFVContribution = Texture2DSampleLevel(MobileBasePass.HalfResLocalFogVolumeViewTexture, MobileBasePass.HalfResLocalFogVolumeViewSampler, HalfResSourceTexCoord, 0.0f);
OutColor.rgb = OutColor.rgb * LFVContribution.aaa + LFVContribution.rgb;
}
#endif
#if MATERIAL_IS_SKY || (!MATERIAL_SHADINGMODEL_UNLIT && !MOBILE_USE_GBUFFER)
// clamp lit color to avoid overflows
OutColor.rgb = SafeGetOutColor(OutColor.rgb);
#endif
#if USE_EDITOR_COMPOSITING && (MOBILE_EMULATION)
// Editor primitive depth testing
OutColor.a = 1.0;
#if MATERIALBLENDING_MASKED
// some material might have an opacity value
OutColor.a = GetMaterialMaskInputRaw(PixelMaterialInputs);
#endif
clip(OutColor.a - GetMaterialOpacityMaskClipValue());
#else
#if OUTPUT_GAMMA_SPACE
OutColor.rgb = sqrt(OutColor.rgb);
#endif
#endif
#if MATERIAL_VIRTUALTEXTURE_FEEDBACK || LIGHTMAP_VT_ENABLED
FinalizeVirtualTextureFeedback(
MaterialParameters.VirtualTextureFeedback,
MaterialParameters.SvPosition,
View.VTFeedbackBuffer
);
#endif
#if MOBILE_USE_GBUFFER && USE_GLES_FBF_DEFERRED
OutProxy.rgb = OutColor.rgb;
#elif MOBILE_TRANSLUCENT_COLOR_TRANSMITTANCE_PROGRAMMABLE_BLENDING
OutProgrammableBlending = OutColor1 * FramebufferFetchColor0() + OutColor;
#endif
}