Files
UnrealEngine/Engine/Source/Runtime/Renderer/Private/DecalRenderingCommon.cpp
2025-05-18 13:04:45 +08:00

1009 lines
49 KiB
C++

// 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<CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, CW_NONE>::GetRHI();
}
else
{
// Treat blend as non-emissive
return TStaticBlendState<CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, CW_NONE>::GetRHI();
}
}
else if (IsAlphaCompositeBlendMode(DecalBlendDesc))
{
return TStaticBlendState<CW_RGB, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, CW_NONE>::GetRHI();
}
else if (IsModulateBlendMode(DecalBlendDesc))
{
return TStaticBlendState<CW_RGB, BO_Add, BF_DestColor, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, CW_NONE>::GetRHI();
}
}
else
{
return TStaticBlendState<CW_RGB, BO_Add, BF_SourceAlpha, BF_One>::GetRHI();
}
ensure(0);
return TStaticBlendState<>::GetRHI();
}
FRHIBlendState* GetDecalBlendState_AmbientOcclusion(FDecalBlendDesc DecalBlendDesc, EDecalRenderStage DecalRenderStage)
{
// Modulate with AO target.
return TStaticBlendState<CW_RED, BO_Add, BF_DestColor, BF_Zero>::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<FM_Solid, CM_CW>::GetRHI();
case EDecalRasterizerState::CCW:
return TStaticRasterizerState<FM_Solid, CM_CCW>::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);
}
}
}