// 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 }