From 2b109cb6fd9f3fcb4ee192a70899d05ecd451a72 Mon Sep 17 00:00:00 2001 From: John Haddon Date: Tue, 19 Dec 2023 14:17:17 +0000 Subject: [PATCH 1/2] Backdrop : Improve ordering of nested backdrops We now automatically draw larger backdrops behind smaller ones, so that nested backdrops "just work". An additional `depth` plug allows the user to override this in rare cases where they want a smaller backdrop to appear beneath a larger one. --- Changes.md | 4 ++ include/Gaffer/Backdrop.h | 3 ++ python/GafferUI/BackdropUI.py | 19 ++++++++++ src/Gaffer/Backdrop.cpp | 11 ++++++ src/GafferUI/BackdropNodeGadget.cpp | 59 ++++++++++++++++++++++++++++- 5 files changed, 94 insertions(+), 2 deletions(-) diff --git a/Changes.md b/Changes.md index 835b339cec6..09f3f106311 100644 --- a/Changes.md +++ b/Changes.md @@ -31,6 +31,9 @@ Improvements - Added "Custom" option, to allow strings to be entered manually. - Added right-click context menu. - Switch : Added `connectedInputs` output plug. +- Backdrop : Improved drawing order for nested backdrops : + - Larger backdrops are automatically drawn behind smaller ones, so that nested backdrops will always appear on top. + - Added a `depth` plug to assign a manual drawing depth for the rare cases where the automatic depth is unwanted. Fixes ----- @@ -75,6 +78,7 @@ Breaking Changes ---------------- - Render : Changed `render:includedPurposes` default to `"default", "render"`. +- Backdrop : Changed default drawing order. Use the new `depth` plug to override the order if necessary. - ValuePlug : Removed deprecated `getObjectValue()` overload. - Preferences : Removed `cache` plug. - TaskNode : diff --git a/include/Gaffer/Backdrop.h b/include/Gaffer/Backdrop.h index 3a6bae79ef7..f34cfedac79 100644 --- a/include/Gaffer/Backdrop.h +++ b/include/Gaffer/Backdrop.h @@ -65,6 +65,9 @@ class GAFFER_API Backdrop : public Node StringPlug *descriptionPlug(); const StringPlug *descriptionPlug() const; + IntPlug *depthPlug(); + const IntPlug *depthPlug() const; + private : static size_t g_firstPlugIndex; diff --git a/python/GafferUI/BackdropUI.py b/python/GafferUI/BackdropUI.py index cc7c15f5fe2..633e47e73dd 100644 --- a/python/GafferUI/BackdropUI.py +++ b/python/GafferUI/BackdropUI.py @@ -126,6 +126,25 @@ def nodeMenuCreateCommand( menu ) : ], + "depth" : [ + + "description", + """ + Determines the drawing order of overlapping backdrops. + + > Note : Larger backdrops are _automatically_ drawn behind smaller ones, + > so it is only necessary to manually assign a depth in rare cases where + > this is not desirable. + """, + + "plugValueWidget:type", "GafferUI.PresetsPlugValueWidget", + "preset:Back", -1, + "preset:Middle", 0, + "preset:Front", 1, + + + ], + } ) diff --git a/src/Gaffer/Backdrop.cpp b/src/Gaffer/Backdrop.cpp index ea94bfe4e11..2b7d4e9266b 100644 --- a/src/Gaffer/Backdrop.cpp +++ b/src/Gaffer/Backdrop.cpp @@ -51,6 +51,7 @@ Backdrop::Backdrop( const std::string &name ) addChild( new StringPlug( "title", Plug::In, "Title" ) ); addChild( new FloatPlug( "scale", Plug::In, 1.0f, 1.0f ) ); addChild( new StringPlug( "description" ) ); + addChild( new IntPlug( "depth", Plug::In, 0, -1, 1 ) ); } Backdrop::~Backdrop() @@ -86,3 +87,13 @@ const Gaffer::StringPlug *Backdrop::descriptionPlug() const { return getChild( g_firstPlugIndex + 2 ); } + +IntPlug *Backdrop::depthPlug() +{ + return getChild( g_firstPlugIndex + 3 ); +} + +const IntPlug *Backdrop::depthPlug() const +{ + return getChild( g_firstPlugIndex + 3 ); +} diff --git a/src/GafferUI/BackdropNodeGadget.cpp b/src/GafferUI/BackdropNodeGadget.cpp index 5d979bcb987..946c76e8807 100644 --- a/src/GafferUI/BackdropNodeGadget.cpp +++ b/src/GafferUI/BackdropNodeGadget.cpp @@ -89,6 +89,53 @@ void titleAndDescriptionFromPlugs( const StringPlug *titlePlug, const StringPlug } } +// Remaps `x` into the range `outMin, outMax`. The initial portion +// of the mapping - for `x < m` - is linear and uses the first proportion +// `q` of the output range. After that the result approaches `outMax` +// asymptotically. +float remap( float x, float m, float q, float outMin, float outMax ) +{ + if( x < m ) + { + return outMin + q * ( x / m ) * ( outMax - outMin ); + } + else + { + return outMax - ( outMax - outMin ) * ( 1.0 - 2.0 * q + q * q ) / ( 1.0 - 2.0 * q + q * (x / m) ); + } +} + +float depth( const Backdrop *backdrop, const Box2f &bound, const V2f &clipping ) +{ + // We let the user assign a fixed depth from a narrow set of integer + // options. We use this to carve out a range within the clipping planes. + + float nodeDepth = 0; + try + { + nodeDepth = backdrop->depthPlug()->getValue(); + } + catch( ... ) + { + } + const float nodeDepthMin = backdrop->depthPlug()->minValue(); + const float nodeDepthMax = backdrop->depthPlug()->maxValue(); + const float rangeSize = ( clipping[1] - clipping[0] ) / ( 1.0 + nodeDepthMax - nodeDepthMin ); + const float rangeStart = clipping[0] + ( nodeDepthMax - nodeDepth ) * rangeSize; + const float rangeEnd = rangeStart + rangeSize; + + // We then choose a depth within that range based on the area of + // the backdrop, with larger backdrops being given larger depths. + // In most cases this means that backdrops automatically order + // themselves, and the user only needs to assign a depth manually + // in unusual cases where they want a smaller backdrop to appear + // behind a larger one. + + const float area = bound.size().x * bound.size().y; + const float maxLikelyArea = 1000 * 1000; + return -remap( area, maxLikelyArea, 0.75, rangeStart, rangeEnd ); +} + const float g_margin = 3.0f; const float g_titleBarHeight = 1.0f; const float g_titleBarMargin = 1.0f; @@ -271,13 +318,19 @@ void BackdropNodeGadget::renderLayer( Layer layer, const Style *style, RenderRea const Backdrop *backdrop = static_cast( node() ); const float scale = backdrop->scalePlug()->getValue(); + const float translateZ = depth( backdrop, bound, ancestor()->getCamera()->getClippingPlanes() ); bound.min /= scale; bound.max /= scale; glPushMatrix(); + glPushAttrib( GL_DEPTH_BUFFER_BIT ); + + glEnable( GL_DEPTH_TEST ); + glDepthFunc( GL_LEQUAL ); - glScalef( scale, scale, scale ); + glScalef( scale, scale, 1.0f ); + glTranslatef( 0, 0, translateZ ); const Box3f titleCharacterBound = style->characterBound( Style::HeadingText ); const float titleBaseline = bound.max.y - g_margin - titleCharacterBound.max.y; @@ -352,6 +405,7 @@ void BackdropNodeGadget::renderLayer( Layer layer, const Style *style, RenderRea } } + glPopAttrib(); glPopMatrix(); } @@ -384,7 +438,8 @@ void BackdropNodeGadget::plugDirtied( const Gaffer::Plug *plug ) if( plug == backdrop->titlePlug() || plug == backdrop->scalePlug() || - plug == backdrop->descriptionPlug() + plug == backdrop->descriptionPlug() || + plug == backdrop->depthPlug() ) { dirty( DirtyType::Render ); From d42c572a67f871c76b34fcbb514a9fa7aa68103f Mon Sep 17 00:00:00 2001 From: John Haddon Date: Wed, 20 Dec 2023 09:54:47 +0000 Subject: [PATCH 2/2] StandardStyle : Discard fragments with zero texture alpha We were already trying to discard fragments with zero alpha so that they don't affect selection hits. But we were doing that before taking the texture alpha into account. Although the original motivation was selection hits, discarding zero alpha also avoids depth buffer writes, which is important now that Backdrops use depth buffering to control the order of nesting. --- src/GafferUI/StandardStyle.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/GafferUI/StandardStyle.cpp b/src/GafferUI/StandardStyle.cpp index f2970096b79..7e1d74ade7a 100644 --- a/src/GafferUI/StandardStyle.cpp +++ b/src/GafferUI/StandardStyle.cpp @@ -1499,11 +1499,6 @@ static const std::string &fragmentSource() " OUTCOLOR.a *= ieFilteredPulse( 0.2, 0.8, gl_TexCoord[0].x );" " }" - " if( OUTCOLOR.a == 0.0 )" - " {" - " discard;" - " }" - /// \todo Deal with all colourspace nonsense outside of the shader. Ideally the shader would accept only linear" /// textures and output only linear data." @@ -1524,6 +1519,11 @@ static const std::string &fragmentSource() " OUTCOLOR = vec4( OUTCOLOR.rgb, OUTCOLOR.a * texture2D( texture, gl_TexCoord[0].xy ).a );" " }\n" + " if( OUTCOLOR.a == 0.0 )" + " {" + " discard;" + " }\n" + "#if __VERSION__ >= 330\n" " ieCoreGLNameOut = ieCoreGLNameIn;\n" "#endif\n"