Skip to content

Commit 645382c

Browse files
authored
Merge pull request #1367 from yannci/sceneShapeTimePlugTraversal
SceneShape: Fix reading of time samples for expanded link locations
2 parents c065240 + 6aaad9f commit 645382c

File tree

5 files changed

+145
-19
lines changed

5 files changed

+145
-19
lines changed

Changes

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
10.4.x.x (relative to 10.4.9.1)
22
========
33

4+
Fixes
5+
---
6+
7+
- IECoreMaya.SceneShape : Fixed reading of time samples for expanded link locations
8+
- Traverse the time plug connections to check for a maya global time connection
49

510
10.4.9.1 (relative to 10.4.9.0)
611
========

src/IECoreMaya/SceneShape.cpp

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,18 @@
4545
#include "maya/MFnDagNode.h"
4646
#include "maya/MTime.h"
4747
#include "maya/MEvaluationNode.h"
48+
#include "maya/MItDependencyGraph.h"
49+
4850

4951
using namespace IECore;
5052
using namespace IECoreScene;
5153
using namespace IECoreMaya;
5254

55+
namespace
56+
{
57+
const MString g_mayaGlobalTimeNodeName( "time1" );
58+
}
59+
5360
MTypeId SceneShape::id = SceneShapeId;
5461
MObject SceneShape::aSceneFilePlug;
5562
MObject SceneShape::aSceneRootPlug;
@@ -256,7 +263,7 @@ ConstObjectPtr SceneShape::readSceneShapeLink( const MDagPath &p )
256263
SceneShape *sceneShape = findScene( p, true, &dagPath );
257264
if ( !sceneShape )
258265
{
259-
throw Exception("readSceneShapeLink: Could not find SceneShape!");
266+
throw Exception( "readSceneShapeLink: Could not find SceneShape!" );
260267
}
261268

262269
const SceneInterface *scene = sceneShape->getSceneInterface().get();
@@ -270,26 +277,36 @@ ConstObjectPtr SceneShape::readSceneShapeLink( const MDagPath &p )
270277
MPlug timePlug = fnChildDag.findPlug( aTime, false, &st );
271278
if( !st )
272279
{
273-
throw Exception( "Could not find 'time' plug in SceneShape!");
280+
throw Exception( "Could not find 'time' plug in SceneShape!" );
274281
}
275282

276-
// if time plug is connected to maya global time, then we assume there's no time remapping between the Maya scene and the loaded scene.
277-
MPlugArray array;
278-
timePlug.connectedTo( array, true, false, &st );
279-
if( !st )
283+
MItDependencyGraph it = MItDependencyGraph( timePlug, MFn::kInvalid, MItDependencyGraph::kUpstream, MItDependencyGraph::kDepthFirst, MItDependencyGraph::kPlugLevel );
284+
for ( ; !it.isDone() ; it.next() )
280285
{
281-
throw Exception( "Could not find 'time' plug connections in SceneShape!");
282-
}
286+
MPlug currPlug = it.thisPlug( &st );
287+
CHECK_MSTATUS(st);
288+
MFnDependencyNode nodeFn( currPlug.node(), &st );
289+
CHECK_MSTATUS(st);
283290

284-
for ( unsigned int i = 0; i < array.length(); i++ )
285-
{
286-
if ( array[i].name() == "time1.outTime" )
291+
if ( nodeFn.name() == g_mayaGlobalTimeNodeName )
287292
{
288-
/// connected to time, so no time remapping between maya scene and loaded scene.
293+
/// The plug is connected to maya global time, so no time remapping is happening
289294
return LinkedScene::linkAttributeData( scene );
290295
}
296+
297+
unsigned int nodeId = nodeFn.typeId().id();
298+
bool isSceneShape = nodeId == SceneShapeId || nodeId == SceneShapeProxyId;
299+
if ( !isSceneShape )
300+
{
301+
/// The time plug is not connected to global maya time or a scene shape (expanded hierarchy),
302+
/// so we assume some kind of time manipulation (a maya add node to offset the value or similiar)
303+
MTime time;
304+
timePlug.getValue( time );
305+
return LinkedScene::linkAttributeData( scene, time.as( MTime::kSeconds ) );
306+
}
291307
}
292-
/// couldn't find connection to maya time, so this node is mapping the time some other way.
308+
309+
/// The time plug doesn't have any connection at all (time hold)
293310
MTime time;
294311
timePlug.getValue( time );
295312
return LinkedScene::linkAttributeData( scene, time.as( MTime::kSeconds ) );

test/IECoreMaya/LiveSceneTest.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -556,9 +556,7 @@ def testSceneShapeCustomReaders( self ):
556556
self.assertFalse( spheresScene.hasAttribute( IECoreScene.LinkedScene.linkAttribute ) )
557557
leafScene = spheresScene.child("A").child("a")
558558
self.assertTrue( leafScene.hasAttribute( IECoreScene.LinkedScene.linkAttribute ) )
559-
# When expanding, we connect the child time attributes to their scene shape parent time attribute to propagate time remapping. When checking for time remapping, the scene shape
560-
# currently only checks the direct connection, so we have here time in the link attributes. Will have to look out for performance issues.
561-
self.assertEqual( leafScene.readAttribute( IECoreScene.LinkedScene.linkAttribute, 0 ), IECore.CompoundData( { "fileName":IECore.StringData('test/IECore/data/sccFiles/animatedSpheres.scc'), "root":IECore.InternedStringVectorData([ 'A', 'a' ]), 'time':IECore.DoubleData( 0 ) } ) )
559+
self.assertEqual( leafScene.readAttribute( IECoreScene.LinkedScene.linkAttribute, 0 ), IECore.CompoundData( { "fileName":IECore.StringData('test/IECore/data/sccFiles/animatedSpheres.scc'), "root":IECore.InternedStringVectorData([ 'A', 'a' ]) } ) )
562560
self.assertFalse( leafScene.hasObject() )
563561

564562
# expand scene to meshes

test/IECoreMaya/SceneShapeProxyTest.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ class SceneShapeProxyTest( SceneShapeTest.SceneShapeTest ):
4242

4343
def setUp( self ):
4444
IECoreMaya.TestCase.setUp(self)
45-
self._node = maya.cmds.createNode( "ieSceneShapeProxy" )
45+
self._shapeType = "ieSceneShapeProxy"
46+
self._node = maya.cmds.createNode( self._shapeType )
4647

4748
if __name__ == "__main__":
4849
IECoreMaya.TestProgram( plugins = [ "ieCore" ] )

test/IECoreMaya/SceneShapeTest.py

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,12 @@ class SceneShapeTest( IECoreMaya.TestCase ) :
4747
__testPlugFile = "test/testPlug.scc"
4848
__testPlugAnimFile = "test/testPlugAnim.scc"
4949
__testPlugAttrFile = "test/testPlugAttr.scc"
50+
__testLinkFile = "test/test.lscc"
5051

5152
def setUp( self ):
5253
super( SceneShapeTest, self ).setUp()
53-
self._node = maya.cmds.createNode( "ieSceneShape" )
54+
self._shapeType = "ieSceneShape"
55+
self._node = maya.cmds.createNode( self._shapeType )
5456

5557
def writeSCC( self, file, rotation=imath.V3d( 0, 0, 0 ), time=0 ) :
5658

@@ -550,10 +552,113 @@ def testLinkedLiveSceneTags( self ) :
550552
self.assertEqual( sorted([ str(x) for x in child2.readTags() ]), ["ObjectType:MeshPrimitive","b"] )
551553
self.assertEqual( sorted([ str(x) for x in child3.readTags() ]), ["ObjectType:MeshPrimitive","c"] )
552554

555+
def testReadSceneShapeLink( self ):
556+
557+
# Create an .lscc with three child locations that we will time remap once we have read it back into maya
558+
self.writeAnimSCC( SceneShapeTest.__testFile )
559+
560+
sceneCache = IECoreScene.SceneCache( SceneShapeTest.__testFile, IECore.IndexedIO.OpenMode.Read )
561+
linkedScene = IECoreScene.LinkedScene( SceneShapeTest.__testLinkFile, IECore.IndexedIO.OpenMode.Write )
562+
563+
noRemapLocation = linkedScene.createChild( "NoRemap" )
564+
noRemapLocation.writeLink( sceneCache )
565+
remapLocation = linkedScene.createChild( "Remap" )
566+
remapLocation.writeLink( sceneCache )
567+
holdLocation = linkedScene.createChild( "Hold" )
568+
holdLocation.writeLink( sceneCache )
569+
570+
del noRemapLocation, remapLocation, holdLocation
571+
del linkedScene
572+
573+
# Create a root level scene shape node to read in the .lscc
574+
rootFn = IECoreMaya.FnSceneShape.create( "Root", shapeType=self._shapeType )
575+
maya.cmds.setAttr( rootFn.name() + ".file", SceneShapeTest.__testLinkFile, type="string" )
576+
maya.cmds.setAttr( rootFn.name() + ".root", "/", type="string" )
577+
578+
holdFn, noRemapFn, remapFn = rootFn.expandOnce()
579+
580+
# check that we don't have any other value than global maya time
581+
mayaTime = maya.cmds.currentTime( query=True )
582+
self.assertEqual( maya.cmds.getAttr( holdFn.name() + ".time" ), mayaTime )
583+
self.assertEqual( maya.cmds.getAttr( noRemapFn.name() + ".time" ), mayaTime )
584+
self.assertEqual( maya.cmds.getAttr( remapFn.name() + ".time" ), mayaTime )
585+
586+
# break the time connection to create a time hold
587+
maya.cmds.disconnectAttr( rootFn.name() + ".outTime", holdFn.name() + ".time" )
588+
maya.cmds.setAttr( holdFn.name() + ".time", 5.0 )
589+
self.assertEqual( maya.cmds.getAttr( holdFn.name() + ".time" ), 5.0 )
590+
591+
# add an offset to create a time remapping
592+
addNode = maya.cmds.createNode( "addDoubleLinear" )
593+
maya.cmds.connectAttr( "time1.outTime", addNode + ".input1" )
594+
maya.cmds.setAttr( addNode + ".input2", 10.0 )
595+
maya.cmds.connectAttr( addNode + ".output", remapFn.name() + ".time", force=True )
596+
self.assertEqual( maya.cmds.getAttr( remapFn.name() + ".time" ), 11.0 )
597+
598+
# set up the LiveScenes for actual testing
599+
holdFn.expandAll()
600+
holdLiveScene = IECoreMaya.LiveScene()
601+
holdLocation = holdLiveScene.child( "|Root|Hold" )
602+
holdChild1 = holdLocation.child( holdLocation.childNames()[0] )
603+
holdChild2 = holdChild1.child( holdChild1.childNames()[0] )
604+
holdChild3 = holdChild2.child( holdChild2.childNames()[0] )
605+
holdLocations = [holdLocation, holdChild1, holdChild2, holdChild3]
606+
607+
noRemapFn.expandAll()
608+
noRemapLiveScene = IECoreMaya.LiveScene()
609+
noRemapLocation = noRemapLiveScene.child( "|Root|NoRemap" )
610+
noRemapChild1 = noRemapLocation.child( noRemapLocation.childNames()[0] )
611+
noRemapChild2 = noRemapChild1.child( noRemapChild1.childNames()[0] )
612+
noRemapChild3 = noRemapChild2.child( noRemapChild2.childNames()[0] )
613+
noRemapLocations = [noRemapLocation, noRemapChild1, noRemapChild2, noRemapChild3]
614+
615+
remapFn.expandAll()
616+
remapLiveScene = IECoreMaya.LiveScene()
617+
remapLocation = remapLiveScene.child( "|Root|Remap" )
618+
remapChild1 = remapLocation.child( remapLocation.childNames()[0] )
619+
remapChild2 = remapChild1.child( remapChild1.childNames()[0] )
620+
remapChild3 = remapChild2.child( remapChild2.childNames()[0] )
621+
remapLocations = [remapLocation, remapChild1, remapChild2, remapChild3]
622+
623+
# set up some constants used during testing
624+
FPS = 24
625+
TIME_HOLD = 5.0
626+
TIME_OFFSET = 10.0
627+
628+
for time in [1.0, 5.0, 10.0, 50.0, 100.0]:
629+
630+
maya.cmds.currentTime( time, edit=True )
631+
mayaTime = maya.cmds.currentTime( query=True )
632+
# check that we actually moved in time
633+
self.assertEqual( mayaTime, time )
634+
635+
# test no time remap
636+
for location in noRemapLocations:
637+
nodeTime = maya.cmds.getAttr( str(location.dagPath()) + ".outTime" )
638+
linkAttr = location.readAttribute( IECoreScene.LinkedScene.linkAttribute, mayaTime )
639+
self.assertFalse( linkAttr.has_key( "time" ) )
640+
self.assertEqual( nodeTime, mayaTime )
641+
642+
# test time remap
643+
for location in remapLocations:
644+
linkAttr = location.readAttribute( IECoreScene.LinkedScene.linkAttribute, mayaTime )
645+
self.assertTrue( linkAttr.has_key( "time" ) )
646+
self.assertEqual( linkAttr["time"].value * FPS, mayaTime + TIME_OFFSET )
647+
648+
# test time hold
649+
for location in holdLocations:
650+
linkAttr = location.readAttribute( IECoreScene.LinkedScene.linkAttribute, mayaTime )
651+
self.assertTrue( linkAttr.has_key( "time" ) )
652+
self.assertEqual( linkAttr["time"].value * FPS, TIME_HOLD )
653+
553654

554655
def tearDown( self ) :
555656

556-
for f in [ SceneShapeTest.__testFile, SceneShapeTest.__testPlugFile, SceneShapeTest.__testPlugAnimFile, SceneShapeTest.__testPlugAttrFile ] :
657+
for f in [
658+
SceneShapeTest.__testFile, SceneShapeTest.__testPlugFile,
659+
SceneShapeTest.__testPlugAnimFile, SceneShapeTest.__testPlugAttrFile,
660+
SceneShapeTest.__testLinkFile
661+
]:
557662
if os.path.exists( f ) :
558663
os.remove( f )
559664

0 commit comments

Comments
 (0)