Fix blend mode options for LyShine's image component (#2377)
* Fix blend mode options for LyShine's image component * Fix Lighten blend mode * Fix errors from last merge Signed-off-by: abrmich <abrmich@amazon.com>
This commit is contained in:
@@ -38,7 +38,7 @@ namespace LyShine
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
PrimitiveListRenderNode::PrimitiveListRenderNode(const AZ::Data::Instance<AZ::RPI::Image>& texture,
|
||||
bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, int blendModeState)
|
||||
bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, const AZ::RHI::TargetBlendState& blendModeState)
|
||||
: RenderNode(RenderNodeType::PrimitiveList)
|
||||
, m_numTextures(1)
|
||||
, m_isTextureSRGB(isTextureSRGB)
|
||||
@@ -55,7 +55,7 @@ namespace LyShine
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
PrimitiveListRenderNode::PrimitiveListRenderNode(const AZ::Data::Instance<AZ::RPI::Image>& texture,
|
||||
const AZ::Data::Instance<AZ::RPI::Image>& maskTexture, bool isClampTextureMode, bool isTextureSRGB,
|
||||
bool preMultiplyAlpha, AlphaMaskType alphaMaskType, int blendModeState)
|
||||
bool preMultiplyAlpha, AlphaMaskType alphaMaskType, const AZ::RHI::TargetBlendState& blendModeState)
|
||||
: RenderNode(RenderNodeType::PrimitiveList)
|
||||
, m_numTextures(2)
|
||||
, m_isTextureSRGB(isTextureSRGB)
|
||||
@@ -102,9 +102,16 @@ namespace LyShine
|
||||
|
||||
const UiRenderer::UiShaderData& uiShaderData = uiRenderer->GetUiShaderData();
|
||||
|
||||
// Set render state
|
||||
dynamicDraw->SetStencilState(uiRenderer->GetBaseState().m_stencilState);
|
||||
dynamicDraw->SetTarget0BlendState(uiRenderer->GetBaseState().m_blendState);
|
||||
|
||||
// The blend factor and op is stored in m_blendModeState when the primitive is added to the graph.
|
||||
// That is also when the graph determines whether a new primitive list node is needed.
|
||||
// The rest of the blend properties are assigned during the render calls, so they get merged here
|
||||
// and all are passed to the dynamic draw context
|
||||
AZ::RHI::TargetBlendState targetBlendState = m_blendModeState;
|
||||
targetBlendState.m_enable = uiRenderer->GetBaseState().m_blendStateEnabled;
|
||||
targetBlendState.m_writeMask = uiRenderer->GetBaseState().m_blendStateWriteMask;
|
||||
dynamicDraw->SetTarget0BlendState(targetBlendState);
|
||||
|
||||
dynamicDraw->SetShaderVariant(uiRenderer->GetCurrentShaderVariant());
|
||||
|
||||
@@ -354,13 +361,13 @@ namespace LyShine
|
||||
|
||||
// if either of the draw flags are checked then we may want to draw the renderable component(s)
|
||||
// on this element, otherwise use the color mask to stop them rendering
|
||||
curBaseState.m_blendState.m_enable = false;
|
||||
curBaseState.m_blendState.m_writeMask = 0x0;
|
||||
curBaseState.m_blendStateEnabled = false;
|
||||
curBaseState.m_blendStateWriteMask = 0x0;
|
||||
if ((m_drawBehind && firstPass) ||
|
||||
(m_drawInFront && !firstPass))
|
||||
{
|
||||
curBaseState.m_blendState.m_enable = true;
|
||||
curBaseState.m_blendState.m_writeMask = 0xF;
|
||||
curBaseState.m_blendStateEnabled = true;
|
||||
curBaseState.m_blendStateWriteMask = 0xF;
|
||||
}
|
||||
|
||||
if (m_isMaskingEnabled)
|
||||
@@ -507,19 +514,10 @@ namespace LyShine
|
||||
|
||||
if (m_dynamicDraw)
|
||||
{
|
||||
UiRenderer::BaseState priorBaseState = uiRenderer->GetBaseState();
|
||||
|
||||
UiRenderer::BaseState curBaseState = priorBaseState;
|
||||
curBaseState.m_blendState.m_blendAlphaSource = AZ::RHI::BlendFactor::One;
|
||||
curBaseState.m_blendState.m_blendAlphaDest = AZ::RHI::BlendFactor::AlphaSource1Inverse;
|
||||
uiRenderer->SetBaseState(curBaseState);
|
||||
|
||||
for (RenderNode* renderNode : m_childRenderNodes)
|
||||
{
|
||||
renderNode->Render(uiRenderer, m_modelViewProjMat, m_dynamicDraw);
|
||||
}
|
||||
|
||||
uiRenderer->SetBaseState(priorBaseState);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -722,7 +720,7 @@ namespace LyShine
|
||||
// The shader can be outputing premultiplied alpha EITHER if the input texture is premultiplied alpha OR if the
|
||||
// shader is doing the premultiply of the output color
|
||||
bool isShaderOutputPremultAlpha = isPreMultiplyAlpha || isTexturePremultipliedAlpha;
|
||||
int blendModeState = GetBlendModeState(blendMode, isShaderOutputPremultAlpha);
|
||||
AZ::RHI::TargetBlendState blendModeState = GetBlendModeState(blendMode, isShaderOutputPremultAlpha);
|
||||
|
||||
PrimitiveListRenderNode* renderNodeToAddTo = nullptr;
|
||||
if (!renderNodeList->empty())
|
||||
@@ -801,7 +799,7 @@ namespace LyShine
|
||||
// The shader can be outputing premultiplied alpha EITHER if the input texture is premultiplied alpha OR if the
|
||||
// shader is doing the premultiply of the output color
|
||||
bool isShaderOutputPremultAlpha = isPreMultiplyAlpha || isTexturePremultipliedAlpha;
|
||||
int blendModeState = GetBlendModeState(blendMode, isShaderOutputPremultAlpha);
|
||||
AZ::RHI::TargetBlendState blendModeState = GetBlendModeState(blendMode, isShaderOutputPremultAlpha);
|
||||
AlphaMaskType alphaMaskType = isShaderOutputPremultAlpha ? AlphaMaskType::ModulateAlphaAndColor : AlphaMaskType::ModulateAlpha;
|
||||
|
||||
PrimitiveListRenderNode* renderNodeToAddTo = nullptr;
|
||||
@@ -947,9 +945,12 @@ namespace LyShine
|
||||
{
|
||||
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = uiRenderer->GetDynamicDrawContext();
|
||||
|
||||
// Disable stencil and enable blend/color write
|
||||
// Reset stencil and blend mode to defaults (disable stencil and enable blend/color write)
|
||||
dynamicDraw->SetStencilState(uiRenderer->GetBaseState().m_stencilState);
|
||||
dynamicDraw->SetTarget0BlendState(uiRenderer->GetBaseState().m_blendState);
|
||||
AZ::RHI::TargetBlendState defaultBlendModeState = GetBlendModeState(LyShine::BlendMode::Normal, false);
|
||||
defaultBlendModeState.m_enable = uiRenderer->GetBaseState().m_blendStateEnabled;
|
||||
defaultBlendModeState.m_writeMask = uiRenderer->GetBaseState().m_blendStateWriteMask;
|
||||
dynamicDraw->SetTarget0BlendState(defaultBlendModeState);
|
||||
|
||||
// First render the render targets, they are sorted so that more deeply nested ones are rendered first.
|
||||
// They only need to be rendered the first time that a render graph is rendered after it has been built.
|
||||
@@ -1169,7 +1170,7 @@ namespace LyShine
|
||||
|
||||
if (prevPrimListNode)
|
||||
{
|
||||
if (prevPrimListNode->GetBlendModeState() != primListRenderNode->GetBlendModeState())
|
||||
if (!(prevPrimListNode->GetBlendModeState() == primListRenderNode->GetBlendModeState()))
|
||||
{
|
||||
++info.m_numNodesDueToBlendMode;
|
||||
}
|
||||
@@ -1346,8 +1347,9 @@ namespace LyShine
|
||||
}
|
||||
|
||||
// Write heading to logfile for this render node
|
||||
logLine = AZStd::string::format("%sPrimitive render node (Blend mode=%d, SRGB=%d). NumPrims=%d, NumTris=%d. Using textures:\r\n",
|
||||
indent.c_str(), primListRenderNode->GetBlendModeState(),
|
||||
AZ::RHI::TargetBlendState blendMode = primListRenderNode->GetBlendModeState();
|
||||
logLine = AZStd::string::format("%sPrimitive render node (Blend mode=%s, SRGB=%d). NumPrims=%d, NumTris=%d. Using textures:\r\n",
|
||||
indent.c_str(), blendMode.m_enable ? "enabled" : "disabled",
|
||||
static_cast<int>(primListRenderNode->GetIsTextureSRGB()),
|
||||
numPrimitives, numTriangles);
|
||||
AZ::IO::LocalFileIO::GetInstance()->Write(fileHandle, logLine.c_str(), logLine.size());
|
||||
@@ -1415,8 +1417,9 @@ namespace LyShine
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int RenderGraph::GetBlendModeState(LyShine::BlendMode blendMode, bool isShaderOutputPremultAlpha) const
|
||||
{
|
||||
AZ::RHI::TargetBlendState RenderGraph::GetBlendModeState(LyShine::BlendMode blendMode, [[maybe_unused]] bool isShaderOutputPremultAlpha) const
|
||||
{
|
||||
// LYSHINE_ATOM_TODO - remove "premultiplyAlpha" parameter and clean up related comments as I think it's no longer needed
|
||||
// Our blend modes are complicated by the fact we want to be able to render to a render target and then
|
||||
// render from that render target texture to the back buffer and get the same result as if we rendered
|
||||
// directly to the back buffer. This should be true even if the render target texture does not end up
|
||||
@@ -1443,72 +1446,47 @@ namespace LyShine
|
||||
// properly might require shader changes also. For the moment using the blend modes Screen, Darken, Lighten
|
||||
// is not encouraged, especially when rendering to a render target.
|
||||
|
||||
int flags = GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA; // the default
|
||||
AZ::RHI::TargetBlendState blendState;
|
||||
blendState.m_blendAlphaSource = AZ::RHI::BlendFactor::One;
|
||||
blendState.m_blendAlphaDest = AZ::RHI::BlendFactor::AlphaSourceInverse;
|
||||
|
||||
switch (blendMode)
|
||||
{
|
||||
case LyShine::BlendMode::Normal:
|
||||
// This is the default mode that does an alpha blend by interpolating based on src alpha
|
||||
if (isShaderOutputPremultAlpha)
|
||||
{
|
||||
flags = GS_BLSRC_ONE | GS_BLDST_ONEMINUSSRCALPHA;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags = GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA;
|
||||
}
|
||||
blendState.m_blendSource = AZ::RHI::BlendFactor::AlphaSource;
|
||||
blendState.m_blendDest = AZ::RHI::BlendFactor::AlphaSourceInverse;
|
||||
break;
|
||||
case LyShine::BlendMode::Add:
|
||||
// This works well, the amount of the src color added is controlled by src alpha
|
||||
if (isShaderOutputPremultAlpha)
|
||||
{
|
||||
flags = GS_BLSRC_ONE | GS_BLDST_ONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags = GS_BLSRC_SRCALPHA | GS_BLDST_ONE;
|
||||
}
|
||||
blendState.m_blendSource = AZ::RHI::BlendFactor::AlphaSource;
|
||||
blendState.m_blendDest = AZ::RHI::BlendFactor::One;
|
||||
break;
|
||||
case LyShine::BlendMode::Screen:
|
||||
// This is a poor approximation of the PhotoShop Screen mode but trying to take some account of src alpha
|
||||
// In Photoshop this would be 1 - ( (1-SrcColor) * (1-DstColor) )
|
||||
// So we should use a blend op of multiply but the IRenderer interface doesn't support that. We get some multiply
|
||||
// from GS_BLDST_ONEMINUSSRCCOL which multiplies the DstColor by (1-SrcColor)
|
||||
if (isShaderOutputPremultAlpha)
|
||||
{
|
||||
flags = GS_BLSRC_ONE | GS_BLDST_ONEMINUSSRCCOL;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags = GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCCOL;
|
||||
}
|
||||
blendState.m_blendSource = AZ::RHI::BlendFactor::AlphaSource;
|
||||
blendState.m_blendDest = AZ::RHI::BlendFactor::ColorSourceInverse;
|
||||
break;
|
||||
case LyShine::BlendMode::Darken:
|
||||
// This is a poor approximation of the PhotoShop Darken mode but trying to take some account of src alpha
|
||||
// In Photoshop Darken means min(SrcColor, DstColor)
|
||||
if (isShaderOutputPremultAlpha)
|
||||
{
|
||||
flags = GS_BLOP_MIN | GS_BLSRC_ONE | GS_BLDST_ONE | GS_BLALPHA_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags = GS_BLOP_MIN | GS_BLSRC_ONEMINUSSRCALPHA | GS_BLDST_ONE;
|
||||
}
|
||||
blendState.m_blendSource = AZ::RHI::BlendFactor::AlphaSourceInverse;
|
||||
blendState.m_blendDest = AZ::RHI::BlendFactor::One;
|
||||
blendState.m_blendOp = AZ::RHI::BlendOp::Minimum;
|
||||
break;
|
||||
case LyShine::BlendMode::Lighten:
|
||||
// This is a pretty good an approximation of the PhotoShop Lighten mode but trying to take some account of src alpha
|
||||
// In PhotoShop Lighten means max(SrcColor, DstColor)
|
||||
if (isShaderOutputPremultAlpha)
|
||||
{
|
||||
flags = GS_BLOP_MAX | GS_BLSRC_ONE| GS_BLDST_ONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags = GS_BLOP_MAX | GS_BLSRC_SRCALPHA | GS_BLDST_ONE;
|
||||
}
|
||||
blendState.m_blendSource = AZ::RHI::BlendFactor::AlphaSource;
|
||||
blendState.m_blendDest = AZ::RHI::BlendFactor::One;
|
||||
blendState.m_blendOp = AZ::RHI::BlendOp::Maximum;
|
||||
break;
|
||||
}
|
||||
|
||||
return flags;
|
||||
return blendState;
|
||||
}
|
||||
|
||||
void RenderGraph::SetRttPassesEnabled(UiRenderer* uiRenderer, bool enabled)
|
||||
|
||||
@@ -71,9 +71,9 @@ namespace LyShine
|
||||
// We use a pool allocator to keep these allocations fast.
|
||||
AZ_CLASS_ALLOCATOR(PrimitiveListRenderNode, AZ::PoolAllocator, 0);
|
||||
|
||||
PrimitiveListRenderNode(const AZ::Data::Instance<AZ::RPI::Image>& texture, bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, int blendModeState);
|
||||
PrimitiveListRenderNode(const AZ::Data::Instance<AZ::RPI::Image>& texture, bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, const AZ::RHI::TargetBlendState& blendModeState);
|
||||
PrimitiveListRenderNode(const AZ::Data::Instance<AZ::RPI::Image>& texture, const AZ::Data::Instance<AZ::RPI::Image>& maskTexture,
|
||||
bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, AlphaMaskType alphaMaskType, int blendModeState);
|
||||
bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, AlphaMaskType alphaMaskType, const AZ::RHI::TargetBlendState& blendModeState);
|
||||
~PrimitiveListRenderNode() override;
|
||||
void Render(UiRenderer* uiRenderer
|
||||
, const AZ::Matrix4x4& modelViewProjMat
|
||||
@@ -88,7 +88,7 @@ namespace LyShine
|
||||
bool GetTextureIsClampMode(int texIndex) const { return m_textures[texIndex].m_isClampTextureMode; }
|
||||
|
||||
bool GetIsTextureSRGB() const { return m_isTextureSRGB; }
|
||||
int GetBlendModeState() const { return m_blendModeState; }
|
||||
AZ::RHI::TargetBlendState GetBlendModeState() const { return m_blendModeState; }
|
||||
bool GetIsPremultiplyAlpha() const { return m_preMultiplyAlpha; }
|
||||
AlphaMaskType GetAlphaMaskType() const { return m_alphaMaskType; }
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace LyShine
|
||||
bool m_isTextureSRGB;
|
||||
bool m_preMultiplyAlpha;
|
||||
AlphaMaskType m_alphaMaskType;
|
||||
int m_blendModeState;
|
||||
AZ::RHI::TargetBlendState m_blendModeState;
|
||||
int m_totalNumVertices;
|
||||
int m_totalNumIndices;
|
||||
|
||||
@@ -340,7 +340,7 @@ namespace LyShine
|
||||
protected: // member functions
|
||||
|
||||
//! Given a blend mode and whether the shader will be outputing premultiplied alpha, return state flags
|
||||
int GetBlendModeState(LyShine::BlendMode blendMode, bool isShaderOutputPremultAlpha) const;
|
||||
AZ::RHI::TargetBlendState GetBlendModeState(LyShine::BlendMode blendMode, bool isShaderOutputPremultAlpha) const;
|
||||
|
||||
void SetRttPassesEnabled(UiRenderer* uiRenderer, bool enabled);
|
||||
|
||||
|
||||
@@ -53,14 +53,8 @@ public: // types
|
||||
void ResetToDefault()
|
||||
{
|
||||
// Enable blend/color write
|
||||
m_blendState.m_enable = true;
|
||||
m_blendState.m_writeMask = 0xF;
|
||||
m_blendState.m_blendSource = AZ::RHI::BlendFactor::AlphaSource;
|
||||
m_blendState.m_blendDest = AZ::RHI::BlendFactor::AlphaSourceInverse;
|
||||
m_blendState.m_blendOp = AZ::RHI::BlendOp::Add;
|
||||
m_blendState.m_blendAlphaSource = AZ::RHI::BlendFactor::One;
|
||||
m_blendState.m_blendAlphaDest = AZ::RHI::BlendFactor::Zero;
|
||||
m_blendState.m_blendAlphaOp = AZ::RHI::BlendOp::Add;
|
||||
m_blendStateEnabled = true;
|
||||
m_blendStateWriteMask = 0xF;
|
||||
|
||||
// Disable stencil
|
||||
m_stencilState = AZ::RHI::StencilState();
|
||||
@@ -70,7 +64,8 @@ public: // types
|
||||
m_modulateAlpha = false;
|
||||
}
|
||||
|
||||
AZ::RHI::TargetBlendState m_blendState;
|
||||
uint32_t m_blendStateEnabled = true;
|
||||
uint32_t m_blendStateWriteMask = 0xF;
|
||||
AZ::RHI::StencilState m_stencilState;
|
||||
bool m_useAlphaTest = false;
|
||||
bool m_modulateAlpha = false;
|
||||
|
||||
Reference in New Issue
Block a user