From 48bc79fb68d0fedd367ee8e0abfe504272c6743f Mon Sep 17 00:00:00 2001 From: Eric Mehl Date: Wed, 22 Nov 2023 17:16:34 -0500 Subject: [PATCH] LightPositionTool : Handle multiple selected lights (WIP) --- .../LightPositionToolTest.py | 56 +++++++++++++++++++ src/GafferSceneUI/LightPositionTool.cpp | 22 +++++++- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/python/GafferSceneUITest/LightPositionToolTest.py b/python/GafferSceneUITest/LightPositionToolTest.py index ce7ad806831..eeb40c5f9ce 100644 --- a/python/GafferSceneUITest/LightPositionToolTest.py +++ b/python/GafferSceneUITest/LightPositionToolTest.py @@ -44,6 +44,7 @@ import Gaffer import GafferUITest +import GafferScene import GafferSceneUI import GafferSceneTest @@ -99,6 +100,61 @@ def testPosition( self ) : for j in range( 0, 3 ) : self.assertAlmostEqual( o[j] % 360, math.degrees( rotationO[j] ) % 360, places = 3 ) + def testMultiple( self ) : + + script = Gaffer.ScriptNode() + + script["group"] = GafferScene.Group() + + i = 0 + positions = [ imath.V3f( 1, 1, 0 ), imath.V3f( 1, -1, 0 ), imath.V3f( -1, -1, 0 ), imath.V3f( -1, 1, 0 ) ] + for p in positions : + n = "light" + str( i ) + script[n] = GafferSceneTest.TestLight() + script[n]["name"].setValue( n ) + script[n]["transform"]["translate"].setValue( p ) + + script["group"]["in"][i].setInput( script[n]["out"] ) + + i += 1 + + view = GafferSceneUI.SceneView() + view["in"].setInput( script["group"]["out"] ) + GafferSceneUI.ContextAlgo.setSelectedPaths( + view.getContext(), + IECore.PathMatcher( [ "/group/light{}".format( i ) for i in range( 0, 4 ) ] ) + ) + + tool = GafferSceneUI.LightPositionTool( view ) + tool["active"].setValue( True ) + + tool.handlesTransform() # Trigger `updateHandles()` to update our centroid + + shadowPivot = imath.V3f( 0, 1, 0 ) + shadowPoint = imath.V3f( 0, 0, -1 ) + tool.position( shadowPivot, shadowPoint ) + + transform = imath.M44f().rotate( IECore.degreesToRadians( imath.V3f( -45, 0, 0 ) ) ) + transform.translate( self.__shadowSource( imath.V3f( 0 ), shadowPivot, shadowPoint ) ) + + print( self.__shadowSource( imath.V3f( 0 ), shadowPivot, shadowPoint ) ) + + i = 0 + for p in positions : + newP = script[n]["transform"]["translate"].getValue() + newR = script[n]["transform"]["rotate"].getValue() + + self.assertAlmostEqual( newR.x, -45.0, places = 4 ) + self.assertAlmostEqual( newR.y, 0.0, places = 4 ) + self.assertAlmostEqual( newR.z, 0.0, places = 4 ) + + desiredP = p * transform + for j in range( 0, 3 ) : + with self.subTest( "Point {}, {} Axis".format( p, {0: "X", 1: "Y", 2: "Z"}.get( j ) ), j=j ) : + self.assertAlmostEqual( newP[j], desiredP[j], places = 4 ) + + i += 1 + def testUndo( self ) : script = Gaffer.ScriptNode() diff --git a/src/GafferSceneUI/LightPositionTool.cpp b/src/GafferSceneUI/LightPositionTool.cpp index 833ac5ff450..18d5fcb1937 100644 --- a/src/GafferSceneUI/LightPositionTool.cpp +++ b/src/GafferSceneUI/LightPositionTool.cpp @@ -104,7 +104,14 @@ void LightPositionTool::position( const V3f &shadowPivot, const V3f &shadowPoint shadowPivot ; - const M44f centroidTransform = rotationMatrix( m_worldCentroid - shadowPivot, newCentroid - shadowPivot ); + const M44f centroidPivotFrame = m_centroidOrientation.toMatrix44().translate( m_worldCentroid ); + + const V3f newDir = ( shadowPivot - newCentroid ).normalized(); + const V3f newDirX = newDir.cross( V3f( 0, 1, 0 ) ).normalized(); + const V3f newDirY = newDir.cross( newDirX ).normalized(); + const M44f newFrame = computeLocalFrame( -newCentroid, newDirX, newDirY ); + + const M44f centroidTransform = centroidPivotFrame * newFrame.inverse(); UndoScope undoScope( selection().back().editTarget()->ancestor() ); @@ -175,7 +182,18 @@ void LightPositionTool::selectionChanged( const TransformTool &tool ) return; } - m_worldCentroid = V3f( 0 ) * selection().back().orientedTransform( Orientation::World ); + int count = 0; + for( const auto &s : selection() ) + { + m_worldCentroid += V3f( 0 ) * s.orientedTransform( Orientation::World ); + count ++; + } + + m_worldCentroid /= count; + + /// \todo Here we're just taking the orientation from the last selected object. + /// Is there a better way? + m_centroidOrientation = extractQuat( selection().back().orientedTransform( Orientation::World ) ); } }