Skip to content

Commit

Permalink
Add support for camera guides
Browse files Browse the repository at this point in the history
Added preliminary support for camera guides (action safe, title safe and rule of thirds).
  • Loading branch information
BrianHanke committed Nov 7, 2024
1 parent c5d6d2e commit d1a7492
Show file tree
Hide file tree
Showing 3 changed files with 238 additions and 3 deletions.
1 change: 1 addition & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
Improvements
------------

- Added support for camera guides (action safe, title safe and rule of thirds).
- Instancer :
- Added `inactiveIds` plug for selecting primitive variables to disable some instances.
- Added support for 64 bit integer ids (matching what is loaded from USD).
Expand Down
86 changes: 86 additions & 0 deletions python/GafferSceneUI/SceneViewUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,64 @@ def __menuDefinition( self ) :
}
)

# BHGC START

m.append( "/GuidesDivider", { "divider" : True } )

titleSafeEnabled = self.getPlug()["titleSafeEnabled"].getValue()
actionSafeEnabled = self.getPlug()["actionSafeEnabled"].getValue()
customGridEnabled = self.getPlug()["customGridEnabled"].getValue()

# possible way to iterate over all guides instead of doing them one by one:

# cameraGuides = self.getPlug()["guidesEnabled"].getValue()

# allGuides = [ "Title Safe", "Action Safe", "Rule of Thirds" ]
# for guide in allGuides :
# newGuides = IECore.StringVectorData( [
# g for g in allGuides
# if
# ( g == guide )
# ] )
# m.append(
# "/Guides/{}".format( guide ),
# {
# "checkBox" : cameraGuidesEnabled,
# #"active" : cameraGuidesEnabled,
# #"command" : functools.partial( self.getPlug()["cameraGuides"]["value"].setValue, newGuides ),
# "command" : functools.partial( Gaffer.WeakMethod( self.__enableGuides ), "" )
# }
# )

# doing them one by one for now (not sure if the "active" thing is needed):

m.append(
"/Guides/Action Safe",
{
"checkBox" : actionSafeEnabled,
# "active" : actionSafeEnabled,
"command" : functools.partial( Gaffer.WeakMethod( self.__enableActionSafe ), "" )
}
)
m.append(
"/Guides/Title Safe",
{
"checkBox" : titleSafeEnabled,
# "active" : titleSafeEnabled,
"command" : functools.partial( Gaffer.WeakMethod( self.__enableTitleSafe ), "" )
}
)
m.append(
"/Guides/Rule of Thirds",
{
"checkBox" : customGridEnabled,
# "active" : customGridEnabled,
"command" : functools.partial( Gaffer.WeakMethod( self.__enableCustomGrid ), "" )
}
)

# BHGC END

m.append( "/BrowseDivider", { "divider" : True } )

m.append(
Expand Down Expand Up @@ -836,6 +894,34 @@ def __lookThrough( self, path, *unused ) :
self.getPlug()["lookThroughEnabled"].setValue( True )
self.getPlug()["lookThroughCamera"].setValue( path )

# BHGC START

# separate functions for each guide, should probably combine these
# is there a better way to toggle than checking if off or on first?

def __enableTitleSafe( self, *unused ) :

if( self.getPlug()["titleSafeEnabled"].getValue() ) :
self.getPlug()["titleSafeEnabled"].setValue( False )
else :
self.getPlug()["titleSafeEnabled"].setValue( True )

def __enableActionSafe( self, *unused ) :

if( self.getPlug()["actionSafeEnabled"].getValue() ) :
self.getPlug()["actionSafeEnabled"].setValue( False )
else :
self.getPlug()["actionSafeEnabled"].setValue( True )

def __enableCustomGrid( self, *unused ) :

if( self.getPlug()["customGridEnabled"].getValue() ) :
self.getPlug()["customGridEnabled"].setValue( False )
else :
self.getPlug()["customGridEnabled"].setValue( True )

# BHGC END

def __browse( self ) :

w = GafferSceneUI.ScenePathPlugValueWidget(
Expand Down
154 changes: 151 additions & 3 deletions src/GafferSceneUI/SceneView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1081,6 +1081,43 @@ class CameraOverlay : public GafferUI::Gadget
dirty( DirtyType::Render );
}

// BHGC START

// separate functions/variables for each guide, should probably combine all this
// i just copied the resolution/aperture gate syntax, not sure if this is ideal

void actionSafeEnabled( const bool &actionSafeEnabled )
{
if( actionSafeEnabled == m_actionSafeEnabled )
{
return;
}
m_actionSafeEnabled = actionSafeEnabled;
dirty( DirtyType::Render );
}

void titleSafeEnabled( const bool &titleSafeEnabled )
{
if( titleSafeEnabled == m_titleSafeEnabled )
{
return;
}
m_titleSafeEnabled = titleSafeEnabled;
dirty( DirtyType::Render );
}

void customGridEnabled( const bool &customGridEnabled )
{
if( customGridEnabled == m_customGridEnabled )
{
return;
}
m_customGridEnabled = customGridEnabled;
dirty( DirtyType::Render );
}

// BHGC END

const std::string &getIcon() const
{
return m_icon;
Expand Down Expand Up @@ -1140,8 +1177,66 @@ class CameraOverlay : public GafferUI::Gadget
{
glEnable( GL_LINE_SMOOTH );
glLineWidth( 1.5f );
glColor4f( 0, 0.25, 0, 1.0f );

// BHGC START

// stipple looks good, but it doesn't work becuase the customGrid edges overlap

// glEnable( GL_LINE_STIPPLE );
// glLineStipple(1, 0x00FF);

V2f gateDiff = V2f( m_resolutionGate.max - m_resolutionGate.min );

V2f titlePercent = gateDiff * V2f( std::sqrt( 0.8 ) );
V2f actionPercent = gateDiff * V2f( std::sqrt( 0.9 ) );

titlePercent = ( gateDiff - titlePercent ) / 2;
actionPercent = ( gateDiff - actionPercent ) / 2;

if( m_titleSafeEnabled )
{
Box2f titleSafe = Box2f( ( m_resolutionGate.min + titlePercent ), ( m_resolutionGate.max - titlePercent ) );

style->renderRectangle( titleSafe );
}

if( m_actionSafeEnabled )
{
Box2f actionSafe = Box2f( ( m_resolutionGate.min + actionPercent ), ( m_resolutionGate.max - actionPercent ) );

style->renderRectangle( actionSafe );
}

// custom grid divisions, 3x3 is rule of thirds

int div_h = 3;
int div_v = 3;

if( m_customGridEnabled )
{
V2f fraction = V2f( gateDiff / V2f( div_h, div_v ) );
vector<Box2f> customGrid;
customGrid.reserve( div_h * div_v ); // I read that this is galaxy brain C++, maybe not needed, haha

for( int v = 0; v < div_v; v++ )
{
for( int h = 0; h < div_h; h++ )
{
customGrid.push_back( Box2f( m_resolutionGate.min + ( fraction * V2f( h, v ) ), m_resolutionGate.min + ( fraction * V2f( h, v ) ) + fraction ) );
}
}

for( const auto &i : customGrid )
{
style->renderRectangle( i );
}
}

// glDisable( GL_LINE_STIPPLE );

// BHGC END

glColor4f( 0.5, 0.5, 0.5, 0.5 );
style->renderRectangle( Box2f(
V2f(
lerp( m_resolutionGate.min.x, m_resolutionGate.max.x, m_cropWindow.min.x ),
Expand All @@ -1153,7 +1248,7 @@ class CameraOverlay : public GafferUI::Gadget
)
) );

glColor4f( 0, 0.25, 0, 1.0f );
//glColor4f( 0, 0.25, 0, 1.0f );
style->renderRectangle( m_resolutionGate );

if( m_overscan[0] != 0.0f || m_overscan[1] != 0.0f || m_overscan[2] != 0.0f || m_overscan[3] != 0.0f )
Expand Down Expand Up @@ -1228,6 +1323,14 @@ class CameraOverlay : public GafferUI::Gadget
std::string m_caption;
std::string m_icon;

// BHGC START

bool m_actionSafeEnabled;
bool m_titleSafeEnabled;
bool m_customGridEnabled;

// BHGC END

};

IE_CORE_DECLAREPTR( CameraOverlay )
Expand Down Expand Up @@ -1382,6 +1485,16 @@ class SceneView::Camera : public Signals::Trackable
)
);

// BHGC START

// create plugs for each guide, combine these three into one?

plug->addChild( new BoolPlug( "actionSafeEnabled", Plug::In, false, Plug::Default & ~Plug::AcceptsInputs ) );
plug->addChild( new BoolPlug( "titleSafeEnabled", Plug::In, false, Plug::Default & ~Plug::AcceptsInputs ) );
plug->addChild( new BoolPlug( "customGridEnabled", Plug::In, false, Plug::Default & ~Plug::AcceptsInputs ) );

// BHGC END

view->addChild( plug );

// Set up our nodes.
Expand Down Expand Up @@ -1526,6 +1639,25 @@ class SceneView::Camera : public Signals::Trackable
return plug()->getChild<V2fPlug>( 6 );
}

// BHGC START

const Gaffer::BoolPlug *titleSafeEnabledPlug() const
{
return plug()->getChild<BoolPlug>( "titleSafeEnabled" );
}

const Gaffer::BoolPlug *actionSafeEnabledPlug() const
{
return plug()->getChild<BoolPlug>( "actionSafeEnabled" );
}

const Gaffer::BoolPlug *customGridEnabledPlug() const
{
return plug()->getChild<BoolPlug>( "customGridEnabled" );
}

// BHGC END

SceneGadget *sceneGadget()
{
return static_cast<SceneGadget *>( m_view->viewportGadget()->getPrimaryChild() );
Expand Down Expand Up @@ -1569,14 +1701,19 @@ class SceneView::Camera : public Signals::Trackable
return;
}

// BHGC - added the guides here, i assume that's needed in order to redraw things when they're turned on and off?

if(
plug == scenePlug()->childNamesPlug() ||
plug == scenePlug()->globalsPlug() ||
plug == scenePlug()->objectPlug() ||
plug == scenePlug()->transformPlug() ||
plug == lookThroughEnabledPlug() ||
plug == lookThroughCameraPlug() ||
plug == freeCameraPlug()
plug == freeCameraPlug() ||
plug == actionSafeEnabledPlug() || // BHGC
plug == titleSafeEnabledPlug() || // BHGC
plug == customGridEnabledPlug() // BHGC
)
{
m_lookThroughCameraDirty = m_viewportCameraDirty = true;
Expand Down Expand Up @@ -1867,6 +2004,17 @@ class SceneView::Camera : public Signals::Trackable
( apertureGate.min - viewportScreenWindow.min ) / viewportScreenWindow.size() * viewport,
( apertureGate.max - viewportScreenWindow.min ) / viewportScreenWindow.size() * viewport
) );

// BHGC START

// draw the guides, combine these three into one?

m_overlay->actionSafeEnabled( m_view->cameraPlug()->getChild<BoolPlug>( "actionSafeEnabled" )->getValue() );
m_overlay->titleSafeEnabled( m_view->cameraPlug()->getChild<BoolPlug>( "titleSafeEnabled" )->getValue() );
m_overlay->customGridEnabled( m_view->cameraPlug()->getChild<BoolPlug>( "customGridEnabled" )->getValue() );

// BHGC END

m_overlay->setVisible( true );

// Now set up a camera that can see all of the aperture and resolution gates.
Expand Down

0 comments on commit d1a7492

Please sign in to comment.