// Copyright Epic Games, Inc. All Rights Reserved. #include "DecalRenderingCommon.h" #include "RHIStaticStates.h" #include "RenderUtils.h" #include "DataDrivenShaderPlatformInfo.h" #include "Substrate/Substrate.h" #include "MaterialShared.h" #include "StaticMeshBatch.h" static_assert(DecalRendering::DecalRenderTargetMode_NumBits == ((int32)EDecalRenderTargetMode::Num - 1)); namespace DecalRendering { inline bool IsOpaqueBlendMode(const FDecalBlendDesc& In) { return IsOpaqueBlendMode((EBlendMode)In.BlendMode); } inline bool IsOpaqueOrMaskedBlendMode(const FDecalBlendDesc& In) { return IsOpaqueOrMaskedBlendMode((EBlendMode)In.BlendMode); } inline bool IsMaskedBlendMode(const FDecalBlendDesc& In) { return IsMaskedBlendMode((EBlendMode)In.BlendMode); } inline bool IsTranslucentOnlyBlendMode(const FDecalBlendDesc& In) { return IsTranslucentOnlyBlendMode((EBlendMode)In.BlendMode); } inline bool IsTranslucentBlendMode(const FDecalBlendDesc& In) { return IsTranslucentBlendMode((EBlendMode)In.BlendMode); } inline bool IsAlphaHoldoutBlendMode(const FDecalBlendDesc& In) { return IsAlphaHoldoutBlendMode((EBlendMode)In.BlendMode); } inline bool IsModulateBlendMode(const FDecalBlendDesc& In) { return IsModulateBlendMode((EBlendMode)In.BlendMode); } inline bool IsAlphaCompositeBlendMode(const FDecalBlendDesc& In) { return IsAlphaCompositeBlendMode((EBlendMode)In.BlendMode); } /** Finalize the initialization of FDecalBlendDesc after BlendMode and bWrite flags have all been set. */ void FinalizeBlendDesc(EShaderPlatform Platform, FDecalBlendDesc& Desc) { const bool bIsSubstrateEnabled = Substrate::IsSubstrateEnabled(); const bool bIsMobilePlatform = IsMobilePlatform(Platform); const bool bIsMobileDeferredPlatform = bIsMobilePlatform && IsMobileDeferredShadingEnabled(Platform); const bool bIsDBufferPlatform = IsUsingDBuffers(Platform); const bool bIsDBufferMaskPlatform = bIsDBufferPlatform && FDataDrivenShaderPlatformInfo::GetSupportsPerPixelDBufferMask(Platform); Desc.bWriteDBufferMask = bIsDBufferMaskPlatform; // Enforce platform blend mode limitations. if (!IsTranslucentOnlyBlendMode(Desc) && !IsAlphaCompositeBlendMode(Desc) && !IsModulateBlendMode(Desc)) { Desc.BlendMode = BLEND_Translucent; } if (bIsDBufferPlatform && IsModulateBlendMode(Desc)) { Desc.BlendMode = BLEND_Translucent; } // Enforce platform output limitations. if (bIsMobilePlatform && !bIsMobileDeferredPlatform && !bIsDBufferPlatform) { Desc.bWriteRoughnessSpecularMetallic = false; } if (bIsMobilePlatform && !bIsDBufferPlatform) { // Note that we disable writing normals for mobile AND mobile deferred. // Mobile deferred has octahedral encoding for normals and so doesn't support decal normal blending. Desc.bWriteNormal = false; } if (bIsMobilePlatform) { Desc.bWriteAmbientOcclusion = false; } // Enforce blend modes output limitations. if (IsAlphaCompositeBlendMode(Desc)) { Desc.bWriteNormal = false; } // Calculate main decal render stage. We set only one (or none) of these for any decal. if ((bIsMobileDeferredPlatform && !bIsDBufferPlatform) && (Desc.bWriteEmissive || Desc.bWriteBaseColor || Desc.bWriteNormal || Desc.bWriteRoughnessSpecularMetallic)) { Desc.RenderStageMask |= 1 << (uint32)EDecalRenderStage::MobileBeforeLighting; } else if ((bIsMobilePlatform && !bIsDBufferPlatform) && (Desc.bWriteEmissive || Desc.bWriteBaseColor)) { Desc.RenderStageMask |= 1 << (uint32)EDecalRenderStage::Mobile; } else if (bIsDBufferPlatform && (Desc.bWriteBaseColor || Desc.bWriteNormal || Desc.bWriteRoughnessSpecularMetallic)) { Desc.RenderStageMask |= 1 << (uint32)EDecalRenderStage::BeforeBasePass; } else if (Desc.bWriteEmissive || Desc.bWriteBaseColor || Desc.bWriteNormal || Desc.bWriteRoughnessSpecularMetallic) { Desc.RenderStageMask |= 1 << (uint32)EDecalRenderStage::BeforeLighting; } // Calculate additional decal render stages. if (Desc.bWriteEmissive && bIsDBufferPlatform) { Desc.RenderStageMask |= 1 << (uint32)EDecalRenderStage::Emissive; } if (Desc.bWriteAmbientOcclusion) { Desc.RenderStageMask |= 1 << (uint32)EDecalRenderStage::AmbientOcclusion; } } FDecalBlendDesc ComputeDecalBlendDesc(EShaderPlatform Platform, const FMaterial& Material) { FDecalBlendDesc Desc; if (Substrate::IsSubstrateEnabled()) { check(Material.IsSubstrateMaterial()); const bool bUseDiffuseAlbedoAndF0 = Material.HasMaterialPropertyConnected(EMaterialProperty::MP_DiffuseColor) || // This is used for Substrate Slab using (DiffuseAlbedo | F0) parameterization Material.HasMaterialPropertyConnected(EMaterialProperty::MP_SpecularColor); // This is used for Substrate Slab using (DiffuseAlbedo | F0) parameterization Desc.BlendMode = Material.GetBlendMode(); Desc.bWriteBaseColor = Material.HasMaterialPropertyConnected(EMaterialProperty::MP_BaseColor) || bUseDiffuseAlbedoAndF0; Desc.bWriteNormal = Material.HasMaterialPropertyConnected(EMaterialProperty::MP_Normal); Desc.bWriteRoughnessSpecularMetallic = bUseDiffuseAlbedoAndF0 || Material.HasMaterialPropertyConnected(EMaterialProperty::MP_Metallic) || Material.HasMaterialPropertyConnected(EMaterialProperty::MP_Specular) || Material.HasMaterialPropertyConnected(EMaterialProperty::MP_Roughness); Desc.bWriteEmissive= Material.HasMaterialPropertyConnected(EMaterialProperty::MP_EmissiveColor); Desc.bWriteAmbientOcclusion = Material.HasMaterialPropertyConnected(EMaterialProperty::MP_AmbientOcclusion); } else { Desc.BlendMode = Material.GetBlendMode(); Desc.bWriteBaseColor = Material.HasBaseColorConnected(); Desc.bWriteNormal = Material.HasNormalConnected(); Desc.bWriteRoughnessSpecularMetallic = Material.HasRoughnessConnected() || Material.HasSpecularConnected() || Material.HasMetallicConnected(); Desc.bWriteEmissive = Material.HasEmissiveColorConnected(); Desc.bWriteAmbientOcclusion = Material.HasAmbientOcclusionConnected(); } FinalizeBlendDesc(Platform, Desc); return Desc; } FDecalBlendDesc ComputeDecalBlendDesc(EShaderPlatform Platform, FMaterialShaderParameters const& MaterialShaderParameters) { FDecalBlendDesc Desc; if (Substrate::IsSubstrateEnabled()) { const bool bUseDiffuseAlbedoAndF0 = MaterialShaderParameters.bHasDiffuseAlbedoConnected || MaterialShaderParameters.bHasF0Connected; Desc.BlendMode = MaterialShaderParameters.BlendMode; Desc.bWriteBaseColor = MaterialShaderParameters.bHasBaseColorConnected || bUseDiffuseAlbedoAndF0; Desc.bWriteNormal = MaterialShaderParameters.bHasNormalConnected; Desc.bWriteRoughnessSpecularMetallic = bUseDiffuseAlbedoAndF0 || MaterialShaderParameters.bHasRoughnessConnected || MaterialShaderParameters.bHasSpecularConnected || MaterialShaderParameters.bHasMetallicConnected; Desc.bWriteEmissive = MaterialShaderParameters.bHasEmissiveColorConnected; Desc.bWriteAmbientOcclusion = MaterialShaderParameters.bHasAmbientOcclusionConnected; } else { Desc.BlendMode = MaterialShaderParameters.BlendMode; Desc.bWriteBaseColor = MaterialShaderParameters.bHasBaseColorConnected; Desc.bWriteNormal = MaterialShaderParameters.bHasNormalConnected; Desc.bWriteRoughnessSpecularMetallic = MaterialShaderParameters.bHasRoughnessConnected || MaterialShaderParameters.bHasSpecularConnected || MaterialShaderParameters.bHasMetallicConnected; Desc.bWriteEmissive = MaterialShaderParameters.bHasEmissiveColorConnected; Desc.bWriteAmbientOcclusion = MaterialShaderParameters.bHasAmbientOcclusionConnected; } FinalizeBlendDesc(Platform, Desc); return Desc; } bool IsCompatibleWithRenderStage(FDecalBlendDesc DecalBlendDesc, EDecalRenderStage DecalRenderStage) { return (DecalBlendDesc.RenderStageMask & (1 << (uint32)DecalRenderStage)) != 0; } EDecalRenderStage GetBaseRenderStage(FDecalBlendDesc DecalBlendDesc) { if (DecalBlendDesc.RenderStageMask & (1 << (uint32)EDecalRenderStage::BeforeBasePass)) { return EDecalRenderStage::BeforeBasePass; } if (DecalBlendDesc.RenderStageMask & (1 << (uint32)EDecalRenderStage::BeforeLighting)) { return EDecalRenderStage::BeforeLighting; } if (DecalBlendDesc.RenderStageMask & (1 << (uint32)EDecalRenderStage::Mobile)) { return EDecalRenderStage::Mobile; } if (DecalBlendDesc.RenderStageMask & (1 << (uint32)EDecalRenderStage::MobileBeforeLighting)) { return EDecalRenderStage::MobileBeforeLighting; } return EDecalRenderStage::None; } uint8 GetDecalRenderTargetModeMask(const FMaterial& Material, ERHIFeatureLevel::Type FeatureLevel) { uint8 Mask = 0; const EShaderPlatform ShaderPlatform = GetFeatureLevelShaderPlatform(FeatureLevel); const FDecalBlendDesc DecalBlendDesc = ComputeDecalBlendDesc(ShaderPlatform, Material); for (int32 DecalRenderStageNum = 0; DecalRenderStageNum < (int32)EDecalRenderStage::Num; ++DecalRenderStageNum) { EDecalRenderStage DecalRenderStage = (EDecalRenderStage)DecalRenderStageNum; if (IsCompatibleWithRenderStage(DecalBlendDesc, DecalRenderStage)) { EDecalRenderTargetMode DecalRenderTargetMode = GetRenderTargetMode(DecalBlendDesc, DecalRenderStage); Mask |= (1 << (uint32)DecalRenderTargetMode); } } return Mask; } bool IsCompatibleWithRenderTargetMode(uint8 DecalRenderTargetModeMask, EDecalRenderTargetMode DecalRenderTargetMode) { return (DecalRenderTargetModeMask & (1 << (uint32)DecalRenderTargetMode)) != 0; } EMeshPass::Type GetMeshPassType(EDecalRenderTargetMode RenderTargetMode) { switch (RenderTargetMode) { case EDecalRenderTargetMode::None: return EMeshPass::Num; case EDecalRenderTargetMode::DBuffer: return EMeshPass::MeshDecal_DBuffer; case EDecalRenderTargetMode::SceneColorAndGBuffer: return EMeshPass::MeshDecal_SceneColorAndGBuffer; case EDecalRenderTargetMode::SceneColorAndGBufferNoNormal: return EMeshPass::MeshDecal_SceneColorAndGBufferNoNormal; case EDecalRenderTargetMode::SceneColor: return EMeshPass::MeshDecal_SceneColor; case EDecalRenderTargetMode::AmbientOcclusion: return EMeshPass::MeshDecal_AmbientOcclusion; } return EMeshPass::Num; } EDecalRenderStage GetRenderStage(EDecalRenderTargetMode RenderTargetMode, EShadingPath ShadingPath) { switch (RenderTargetMode) { case EDecalRenderTargetMode::None: return EDecalRenderStage::None; case EDecalRenderTargetMode::DBuffer: return EDecalRenderStage::BeforeBasePass; case EDecalRenderTargetMode::SceneColorAndGBuffer: return (ShadingPath == EShadingPath::Deferred) ? EDecalRenderStage::BeforeLighting : EDecalRenderStage::MobileBeforeLighting; case EDecalRenderTargetMode::SceneColorAndGBufferNoNormal: return EDecalRenderStage::BeforeLighting; case EDecalRenderTargetMode::SceneColor: return (ShadingPath == EShadingPath::Deferred) ? EDecalRenderStage::Emissive : EDecalRenderStage::Mobile; case EDecalRenderTargetMode::AmbientOcclusion: return EDecalRenderStage::AmbientOcclusion; } return EDecalRenderStage::None; } EDecalRenderTargetMode GetRenderTargetMode(FDecalBlendDesc DecalBlendDesc, EDecalRenderStage DecalRenderStage) { switch(DecalRenderStage) { case EDecalRenderStage::BeforeBasePass: return EDecalRenderTargetMode::DBuffer; case EDecalRenderStage::BeforeLighting: return DecalBlendDesc.bWriteNormal ? EDecalRenderTargetMode::SceneColorAndGBuffer : EDecalRenderTargetMode::SceneColorAndGBufferNoNormal; case EDecalRenderStage::Mobile: return EDecalRenderTargetMode::SceneColor; case EDecalRenderStage::MobileBeforeLighting: return EDecalRenderTargetMode::SceneColorAndGBuffer; case EDecalRenderStage::Emissive: return EDecalRenderTargetMode::SceneColor; case EDecalRenderStage::AmbientOcclusion: return EDecalRenderTargetMode::AmbientOcclusion; } return EDecalRenderTargetMode::None; } uint32 GetRenderTargetCount(FDecalBlendDesc DecalBlendDesc, EDecalRenderTargetMode RenderTargetMode) { switch (RenderTargetMode) { case EDecalRenderTargetMode::DBuffer: return DecalBlendDesc.bWriteDBufferMask ? 4 : 3; case EDecalRenderTargetMode::SceneColorAndGBuffer: return 4; case EDecalRenderTargetMode::SceneColorAndGBufferNoNormal: return 3; case EDecalRenderTargetMode::SceneColor: return 1; case EDecalRenderTargetMode::AmbientOcclusion: return 1; } return 0; } uint32 GetRenderTargetWriteMask(FDecalBlendDesc DecalBlendDesc, EDecalRenderStage DecalRenderStage, EDecalRenderTargetMode RenderTargetMode) { if (RenderTargetMode == EDecalRenderTargetMode::DBuffer) { return (DecalBlendDesc.bWriteBaseColor ? 1 : 0) + (DecalBlendDesc.bWriteNormal ? 2 : 0) + (DecalBlendDesc.bWriteRoughnessSpecularMetallic ? 4 : 0) + (DecalBlendDesc.bWriteDBufferMask ? 8 : 0); } else if (RenderTargetMode == EDecalRenderTargetMode::SceneColorAndGBuffer) { return (DecalBlendDesc.bWriteEmissive ? 1 : 0) + (DecalBlendDesc.bWriteNormal ? 2 : 0) + (DecalBlendDesc.bWriteRoughnessSpecularMetallic ? 4 : 0) + (DecalBlendDesc.bWriteBaseColor ? 8 : 0); } else if (RenderTargetMode == EDecalRenderTargetMode::SceneColorAndGBufferNoNormal) { return (DecalBlendDesc.bWriteEmissive ? 1 : 0) + (DecalBlendDesc.bWriteRoughnessSpecularMetallic ? 2 : 0) + (DecalBlendDesc.bWriteBaseColor ? 4 : 0); } else if (RenderTargetMode == EDecalRenderTargetMode::SceneColor) { if (DecalRenderStage == EDecalRenderStage::Mobile) { return ((DecalBlendDesc.bWriteEmissive || DecalBlendDesc.bWriteBaseColor) ? 1 : 0); } return (DecalBlendDesc.bWriteEmissive ? 1 : 0); } else if (RenderTargetMode == EDecalRenderTargetMode::AmbientOcclusion) { return (DecalBlendDesc.bWriteAmbientOcclusion ? 1 : 0); } // Enable all render targets by default. return (1 << GetRenderTargetCount(DecalBlendDesc, RenderTargetMode)) - 1; } FRHIBlendState* GetDecalBlendState_DBuffer(FDecalBlendDesc DecalBlendDesc, EDecalRenderStage DecalRenderStage) { // Ignore DBuffer mask bit and always set that MRT active. const uint32 Mask = GetRenderTargetWriteMask(DecalBlendDesc, DecalRenderStage, EDecalRenderTargetMode::DBuffer) & 0x7; if (IsTranslucentOnlyBlendMode(DecalBlendDesc)) { switch (Mask) { case 1: return TStaticBlendState< CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, // BaseColor CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One // DBuffer mask >::GetRHI(); case 2: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // BaseColor CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One // DBuffer mask >::GetRHI(); case 3: return TStaticBlendState< CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, // BaseColor CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One // DBuffer mask >::GetRHI(); case 4: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // BaseColor CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, // Metallic, Specular, Roughness CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One // DBuffer mask >::GetRHI(); case 5: return TStaticBlendState< CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, // BaseColor CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, // Metallic, Specular, Roughness CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One // DBuffer mask >::GetRHI(); case 6: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // BaseColor CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, // Normal CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, // Metallic, Specular, Roughness CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One // DBuffer mask >::GetRHI(); case 7: return TStaticBlendState< CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, // BaseColor CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, // Normal CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, // Metallic, Specular, Roughness CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One // DBuffer mask >::GetRHI(); } } else if (IsAlphaCompositeBlendMode(DecalBlendDesc)) { ensure((Mask & 2) == 0); // AlphaComposite shouldn't write normal. switch (Mask) { case 1: return TStaticBlendState< CW_RGBA, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, // BaseColor CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One // DBuffer mask >::GetRHI(); case 4: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // BaseColor CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_RGBA, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, // Metallic, Specular, Roughness CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One // DBuffer mask >::GetRHI(); case 5: return TStaticBlendState< CW_RGBA, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, // BaseColor CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_RGBA, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, // Metallic, Specular, Roughness CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One // DBuffer mask >::GetRHI(); } } ensure(0); return TStaticBlendState<>::GetRHI(); } FRHIBlendState* GetDecalBlendState_SceneColorAndGBuffer(FDecalBlendDesc DecalBlendDesc, EDecalRenderStage DecalRenderStage) { const uint32 Mask = GetRenderTargetWriteMask(DecalBlendDesc, DecalRenderStage, EDecalRenderTargetMode::SceneColorAndGBuffer); if (IsTranslucentOnlyBlendMode(DecalBlendDesc)) { switch (Mask) { case 1: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 2: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 3: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 4: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 5: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 6: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 7: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 8: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 9: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 10: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 11: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 12: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 13: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 14: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 15: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); } } else if (IsAlphaCompositeBlendMode(DecalBlendDesc)) { ensure((Mask & 2) == 0); // AlphaComposite shouldn't write normal. switch (Mask) { case 1: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 4: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 5: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 8: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 9: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 12: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 13: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); } } else if (IsModulateBlendMode(DecalBlendDesc)) { switch (Mask) { case 1: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 2: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 3: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 4: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 5: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 6: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 7: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 8: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_DestColor, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 9: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_DestColor, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 10: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_DestColor, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 11: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_DestColor, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 12: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_DestColor, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 13: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_DestColor, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 14: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_DestColor, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 15: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_DestColor, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); } } ensure(0); return TStaticBlendState<>::GetRHI(); } FRHIBlendState* GetDecalBlendState_SceneColorAndGBufferNoNormal(FDecalBlendDesc DecalBlendDesc, EDecalRenderStage DecalRenderStage) { const uint32 Mask = GetRenderTargetWriteMask(DecalBlendDesc, DecalRenderStage, EDecalRenderTargetMode::SceneColorAndGBufferNoNormal); if (IsTranslucentOnlyBlendMode(DecalBlendDesc)) { switch (Mask) { case 1: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 2: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 3: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 4: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 5: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 6: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 7: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); } } else if (IsAlphaCompositeBlendMode(DecalBlendDesc)) { switch (Mask) { case 1: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 2: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 3: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 4: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 5: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 6: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 7: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); } } else if (IsModulateBlendMode(DecalBlendDesc)) { switch (Mask) { case 1: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 2: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 3: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 4: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_DestColor, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 5: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_DestColor, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 6: return TStaticBlendState< CW_NONE, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_DestColor, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); case 7: return TStaticBlendState< CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness CW_RGB, BO_Add, BF_DestColor, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); } } ensure(0); return TStaticBlendState<>::GetRHI(); } FRHIBlendState* GetDecalBlendState_SceneColor(FDecalBlendDesc DecalBlendDesc, EDecalRenderStage DecalRenderStage) { if (DecalRenderStage == EDecalRenderStage::Mobile) { if (IsTranslucentOnlyBlendMode(DecalBlendDesc)) { if (DecalBlendDesc.bWriteEmissive) { // Treat blend as emissive return TStaticBlendState::GetRHI(); } else { // Treat blend as non-emissive return TStaticBlendState::GetRHI(); } } else if (IsAlphaCompositeBlendMode(DecalBlendDesc)) { return TStaticBlendState::GetRHI(); } else if (IsModulateBlendMode(DecalBlendDesc)) { return TStaticBlendState::GetRHI(); } } else { return TStaticBlendState::GetRHI(); } ensure(0); return TStaticBlendState<>::GetRHI(); } FRHIBlendState* GetDecalBlendState_AmbientOcclusion(FDecalBlendDesc DecalBlendDesc, EDecalRenderStage DecalRenderStage) { // Modulate with AO target. return TStaticBlendState::GetRHI(); } FRHIBlendState* GetDecalBlendState(FDecalBlendDesc DecalBlendDesc, EDecalRenderStage DecalRenderStage, EDecalRenderTargetMode RenderTargetMode) { // As we force the opacity in the shader we don't always _need_ to set different blend states per MRT. // But we want to give the driver as much information as possible about where output isn't required. // An alternative is to call SetRenderTarget per state change. But that is likely be slower (would need testing on various platforms to confirm that). switch(RenderTargetMode) { case EDecalRenderTargetMode::DBuffer: return GetDecalBlendState_DBuffer(DecalBlendDesc, DecalRenderStage); case EDecalRenderTargetMode::SceneColorAndGBuffer: return GetDecalBlendState_SceneColorAndGBuffer(DecalBlendDesc, DecalRenderStage); case EDecalRenderTargetMode::SceneColorAndGBufferNoNormal: return GetDecalBlendState_SceneColorAndGBufferNoNormal(DecalBlendDesc, DecalRenderStage); case EDecalRenderTargetMode::SceneColor: return GetDecalBlendState_SceneColor(DecalBlendDesc, DecalRenderStage); case EDecalRenderTargetMode::AmbientOcclusion: return GetDecalBlendState_AmbientOcclusion(DecalBlendDesc, DecalRenderStage); } return TStaticBlendState<>::GetRHI(); } EDecalRasterizerState GetDecalRasterizerState(bool bInsideDecal, bool bIsInverted, bool ViewReverseCulling) { bool bClockwise = bInsideDecal; if (ViewReverseCulling) { bClockwise = !bClockwise; } if (bIsInverted) { bClockwise = !bClockwise; } return bClockwise ? EDecalRasterizerState::CW : EDecalRasterizerState::CCW; } FRHIRasterizerState* GetDecalRasterizerState(EDecalRasterizerState DecalRasterizerState) { switch (DecalRasterizerState) { case EDecalRasterizerState::CW: return TStaticRasterizerState::GetRHI(); case EDecalRasterizerState::CCW: return TStaticRasterizerState::GetRHI(); } check(0); return nullptr; } void ModifyCompilationEnvironment(EShaderPlatform Platform, FDecalBlendDesc DecalBlendDesc, EDecalRenderStage DecalRenderStage, FShaderCompilerEnvironment& OutEnvironment) { DecalRenderStage = DecalRenderStage != EDecalRenderStage::None ? DecalRenderStage : GetBaseRenderStage(DecalBlendDesc); check(DecalRenderStage != EDecalRenderStage::None); const EDecalRenderTargetMode RenderTargetMode = GetRenderTargetMode(DecalBlendDesc, DecalRenderStage); check(RenderTargetMode != EDecalRenderTargetMode::None); const uint32 RenderTargetCount = GetRenderTargetCount(DecalBlendDesc, RenderTargetMode); const uint32 RenderTargetWriteMask = GetRenderTargetWriteMask(DecalBlendDesc, DecalRenderStage, RenderTargetMode); OutEnvironment.SetDefine(TEXT("IS_DECAL"), 1); OutEnvironment.SetDefine(TEXT("IS_DBUFFER_DECAL"), DecalRenderStage == EDecalRenderStage::BeforeBasePass ? 1 : 0); OutEnvironment.SetDefine(TEXT("DECAL_RENDERSTAGE"), (uint32)DecalRenderStage); OutEnvironment.SetDefine(TEXT("DECAL_RENDERTARGETMODE"), (uint32)RenderTargetMode); OutEnvironment.SetDefine(TEXT("DECAL_RENDERTARGET_COUNT"), RenderTargetCount); OutEnvironment.SetDefineAndCompileArgument(TEXT("DECAL_OUT_MRT0"), (RenderTargetWriteMask & 1) != 0 ? true : false); OutEnvironment.SetDefineAndCompileArgument(TEXT("DECAL_OUT_MRT1"), (RenderTargetWriteMask & 2) != 0 ? true : false); OutEnvironment.SetDefineAndCompileArgument(TEXT("DECAL_OUT_MRT2"), (RenderTargetWriteMask & 4) != 0 ? true : false); OutEnvironment.SetDefineAndCompileArgument(TEXT("DECAL_OUT_MRT3"), (RenderTargetWriteMask & 8) != 0 ? true : false); OutEnvironment.SetDefine(TEXT("DECAL_RENDERSTAGE_BEFOREBASEPASS"), (uint32)EDecalRenderStage::BeforeBasePass); OutEnvironment.SetDefine(TEXT("DECAL_RENDERSTAGE_BEFORELIGHTING"), (uint32)EDecalRenderStage::BeforeLighting); OutEnvironment.SetDefine(TEXT("DECAL_RENDERSTAGE_MOBILE"), (uint32)EDecalRenderStage::Mobile); OutEnvironment.SetDefine(TEXT("DECAL_RENDERSTAGE_MOBILEBEFORELIGHTING"), (uint32)EDecalRenderStage::MobileBeforeLighting); OutEnvironment.SetDefine(TEXT("DECAL_RENDERSTAGE_EMISSIVE"), (uint32)EDecalRenderStage::Emissive); OutEnvironment.SetDefine(TEXT("DECAL_RENDERSTAGE_AO"), (uint32)EDecalRenderStage::AmbientOcclusion); OutEnvironment.SetDefine(TEXT("DECAL_RENDERTARGETMODE_DBUFFER"), (uint32)EDecalRenderTargetMode::DBuffer); OutEnvironment.SetDefine(TEXT("DECAL_RENDERTARGETMODE_GBUFFER"), (uint32)EDecalRenderTargetMode::SceneColorAndGBuffer); OutEnvironment.SetDefine(TEXT("DECAL_RENDERTARGETMODE_GBUFFER_NONORMAL"), (uint32)EDecalRenderTargetMode::SceneColorAndGBufferNoNormal); OutEnvironment.SetDefine(TEXT("DECAL_RENDERTARGETMODE_SCENECOLOR"), (uint32)EDecalRenderTargetMode::SceneColor); OutEnvironment.SetDefine(TEXT("DECAL_RENDERTARGETMODE_AO"), (uint32)EDecalRenderTargetMode::AmbientOcclusion); // Decals needs to both read Substrate data (deferred path) and write (inline path) OutEnvironment.SetDefine(TEXT("SUBSTRATE_INLINE_SHADING"), 1); OutEnvironment.SetDefine(TEXT("SUBSTRATE_DEFERRED_SHADING"), 1); if (IsMobilePlatform(Platform)) { // On mobile decals are rendered in a "depth read" sub-pass const bool bMobileForceDepthRead = MobileUsesFullDepthPrepass(Platform); OutEnvironment.SetDefine(TEXT("IS_MOBILE_DEPTHREAD_SUBPASS"), bMobileForceDepthRead ? 0u : 1u); } } }