Exemple #1
0
    def apply(self, objects, **kwargs):
        presetDict = self.unpickle()
        srcObjs = presetDict[kEXPORT_DICT_OBJECTS]
        clip = presetDict[kEXPORT_DICT_THE_CLIP]

        #do a version check - if older version clip is being used - perhaps we can write conversion functionality?
        try:
            ver = presetDict[kEXPORT_DICT_TOOL_VER]
            if ver != VER:
                api.melWarning("the anim clip version don't match!")
        except KeyError:
            api.melWarning(
                "this is an old VER 1 pose clip - I don't know how to load them anymore..."
            )
            return

        #generate the name mapping
        slamApply = kwargs.get('slam', False)
        if slamApply:
            objects = cmd.ls(typ='transform')
            tgts = names.matchNames(srcObjs,
                                    objects,
                                    threshold=kDEFAULT_MAPPING_THRESHOLD)
            mapping = Mapping(srcObjs, tgts)
        else:
            tgts = names.matchNames(srcObjs,
                                    objects,
                                    threshold=kDEFAULT_MAPPING_THRESHOLD)
            mapping = Mapping(srcObjs, tgts)

        #run the clip's apply method
        clip.apply(mapping, **kwargs)
Exemple #2
0
	def apply( self, objects, attributes=None, **kwargs ):
		presetDict = self.unpickle()
		srcObjs = presetDict[ kEXPORT_DICT_OBJECTS ]
		clip = presetDict[ kEXPORT_DICT_THE_CLIP ]

		#do a version check - if older version clip is being used - perhaps we can write conversion functionality?
		try:
			ver = presetDict[ kEXPORT_DICT_TOOL_VER ]
			if ver != VER:
				api.melWarning("the anim clip version don't match!")
		except KeyError:
			api.melWarning("this is an old VER 1 pose clip - I don't know how to load them anymore...")
			return

		#generate the name mapping
		slamApply = kwargs.get( 'slam', False )
		if slamApply:
			objects = cmd.ls( typ='transform' )
			tgts = names.matchNames( srcObjs, objects, threshold=kDEFAULT_MAPPING_THRESHOLD )
			mapping = Mapping( srcObjs, tgts )
		else:
			tgts = names.matchNames( srcObjs, objects, threshold=kDEFAULT_MAPPING_THRESHOLD )
			mapping = Mapping( srcObjs, tgts )

		#run the clip's apply method
		clip.apply( mapping, attributes, **kwargs )
def merge( directionAstart, directionAend, directionBstart, newStart ):
	'''merges two different locomotes together - for example N and E to give a NE locomote'''
	#determine which ctrl set to use
	length = directionAend-directionAstart
	ctrlSet = names.matchNames(['body_ctrls'],cmd.ls(type='objectSet'))
	if not ctrlSet:
		raise Exception('control set not found')
	ctrlSet = ctrlSet[0]

	ctrls = cmd.sets(ctrlSet,q=True)


	#deal with the assets for the new animation
	vx = exportManagerCore.ExportManager()
	assetA = vx.exists(start=directionAstart,end=directionAend)[0]
	assetB = vx.exists(start=directionBstart,end=directionBstart+length)[0]
	exportSet = assetA.obj

	assetC = vx.exists(start=newStart,end=newStart+length)
	if not assetC:
		assetC = vx.createAsset(exportSet)
		assetC.setAttr('start', newStart)
		assetC.setAttr('end', newStart+length)
		assetC.setAttr('name', assetA.name + assetB.name)
		assetC.setAttr('type', exportManagerCore.ExportComponent.kANIM)


	#now start building the animations
	animationA = Animation(ctrls,directionAstart,directionAend)
	animationB = Animation(ctrls,directionBstart,directionBstart+length)
	animationB.offset(-directionBstart+directionAstart)
	animationC = animationA+animationB
	animationC.offset(newStart)

	#grab the list of ctrls we need to actually transform
	toFind = ['upperBodyControl','legControl_L','legControl_R']
	xformCtrls = [name for name in names.matchNames(toFind,ctrls,parity=True,threshold=0.8) if name != '']

	for ctrl in xformCtrls:
		motionA = motionList(ctrl,directionAstart,directionAend)
		motionB = motionList(ctrl,directionBstart,directionBstart+length)

		#make the time zero based
		times = [int(time)-newStart for time in animationC[ctrl].get_times(channels=['translateX','translateZ'])]
		times.sort()
		print times,len(motionA),len(motionB)
		for time in times:
			print motionA[time],motionB[time]
			newPos = vectors.Vector(motionA[time]) + vectors.Vector(motionB[time])
			newPos *= 0.70710678118654757 #= math.cos(45degrees)
			tx = animationC[ctrl].translateX[time]
			tz = animationC[ctrl].translateZ[time]
			if tx: tx.keys[0] = newPos.x
			if tz: tz.keys[0] = newPos.z

	animationC.applyToObjs()


#end
Exemple #4
0
def merge( directionAstart, directionAend, directionBstart, newStart ):
	'''merges two different locomotes together - for example N and E to give a NE locomote'''
	#determine which ctrl set to use
	length = directionAend-directionAstart
	ctrlSet = names.matchNames(['body_ctrls'],cmd.ls(type='objectSet'))
	if not ctrlSet:
		raise Exception('control set not found')
	ctrlSet = ctrlSet[0]

	ctrls = cmd.sets(ctrlSet,q=True)


	#deal with the assets for the new animation
	vx = exportManagerCore.ExportManager()
	assetA = vx.exists(start=directionAstart,end=directionAend)[0]
	assetB = vx.exists(start=directionBstart,end=directionBstart+length)[0]
	exportSet = assetA.obj

	assetC = vx.exists(start=newStart,end=newStart+length)
	if not assetC:
		assetC = vx.createAsset(exportSet)
		assetC.setAttr('start', newStart)
		assetC.setAttr('end', newStart+length)
		assetC.setAttr('name', assetA.name + assetB.name)
		assetC.setAttr('type', exportManagerCore.ExportComponent.kANIM)


	#now start building the animations
	animationA = Animation(ctrls,directionAstart,directionAend)
	animationB = Animation(ctrls,directionBstart,directionBstart+length)
	animationB.offset(-directionBstart+directionAstart)
	animationC = animationA+animationB
	animationC.offset(newStart)

	#grab the list of ctrls we need to actually transform
	toFind = ['upperBodyControl','legControl_L','legControl_R']
	xformCtrls = [name for name in names.matchNames(toFind,ctrls,parity=True,threshold=0.8) if name != '']

	for ctrl in xformCtrls:
		motionA = motionList(ctrl,directionAstart,directionAend)
		motionB = motionList(ctrl,directionBstart,directionBstart+length)

		#make the time zero based
		times = [int(time)-newStart for time in animationC[ctrl].get_times(channels=['translateX','translateZ'])]
		times.sort()
		print times,len(motionA),len(motionB)
		for time in times:
			print motionA[time],motionB[time]
			newPos = vectors.Vector(motionA[time]) + vectors.Vector(motionB[time])
			newPos *= 0.70710678118654757 #= math.cos(45degrees)
			tx = animationC[ctrl].translateX[time]
			tz = animationC[ctrl].translateZ[time]
			if tx: tx.keys[0] = newPos.x
			if tz: tz.keys[0] = newPos.z

	animationC.applyToObjs()


#end
Exemple #5
0
    def on_selectSrc(self, *a):
        src = self.getSelectedSrc()
        if src:
            #if the object doesnt' exist in teh scene - try to find it
            if not cmd.objExists(src):
                src = names.matchNames([src], cmd.ls(typ='transform'))[0]

            if cmd.objExists(src):
                cmd.select(src)
	def on_selectSrc( self, *a ):
		src = self.getSelectedSrc()
		if src:
			#if the object doesnt' exist in teh scene - try to find it
			if not cmd.objExists( src ):
				src = names.matchNames( [ src ], cmd.ls( typ='transform' ) )[ 0 ]

			if cmd.objExists( src ):
				cmd.select( src )
 def mapSrcItem(self, src):
     self._srcToTgtDict[src] = names.matchNames(
         [src],
         self.tgts,
         self.STRIP_NAMESPACES,
         self.PARITY_MATCH,
         self.UNIQUE_MATCHING,
         self.MATCH_OPPOSITE_PARITY,
         self.THRESHOLD,
     )
	def on_selectTgt( self, *a ):
		tgts = self.getSelectedTgts()
		if tgts:
			toSearch = cmd.ls( typ='transform' )
			existingTgts = []
			for t in tgts:
				if not cmd.objExists( t ):
					t = names.matchNames( [ t ], toSearch )[ 0 ]

				if cmd.objExists( t ):
					existingTgts.append( t )

			if existingTgts:
				cmd.select( existingTgts )
Exemple #9
0
def resolveMapping(mapping, **kw):
    '''
	resolves the mapping to actual maya nodes - returns a mapping object with non existing nodes
	stripped.  any additional kw args are passed to the matchNames function
	'''
    assert isinstance(mapping, names.Mapping)

    toSearch = cmd.ls(typ='transform')
    existingSrcs = []
    existingTgts = []

    for src, tgt in mapping.iteritems():
        if not cmd.objExists(src):
            src = names.matchNames([src], toSearch, **kw)[0]

        if not cmd.objExists(tgt):
            tgt = names.matchNames([tgt], toSearch, **kw)[0]

        if cmd.objExists(src) and cmd.objExists(tgt):
            existingSrcs.append(src)
            existingTgts.append(tgt)

    return names.Mapping(existingSrcs, existingTgts)
Exemple #10
0
def resolveMapping( mapping, **kw ):
	'''
	resolves the mapping to actual maya nodes - returns a mapping object with non existing nodes
	stripped.  any additional kw args are passed to the matchNames function
	'''
	assert isinstance( mapping, names.Mapping )

	toSearch = cmd.ls( typ='transform' )
	existingSrcs = []
	existingTgts = []

	for src, tgt in mapping.iteritems():
		if not cmd.objExists( src ):
			src = names.matchNames( [ src ], toSearch, **kw )[ 0 ]

		if not cmd.objExists( tgt ):
			tgt = names.matchNames( [ tgt ], toSearch, **kw )[ 0 ]

		if cmd.objExists( src ) and cmd.objExists( tgt ):
			existingSrcs.append( src )
			existingTgts.append( tgt )

	return names.Mapping( existingSrcs, existingTgts )
Exemple #11
0
    def on_selectTgt(self, *a):
        tgts = self.getSelectedTgts()
        if tgts:
            toSearch = cmd.ls(typ='transform')
            existingTgts = []
            for t in tgts:
                if not cmd.objExists(t):
                    t = names.matchNames([t], toSearch)[0]

                if cmd.objExists(t):
                    existingTgts.append(t)

            if existingTgts:
                cmd.select(existingTgts)
Exemple #12
0
def loadPostTraceSchemeFilepath( presetFile ):
	'''
	re-applies a stored post trace command scheme back to the controls found in the current scene
	'''

	#first we need to purge all existing post trace commands
	clearPostTraceScheme()

	presetFile = Path( presetFile )
	if not presetFile.isfile():
		raise IOError, "no such preset"

	xportDict, postTraceDict = presetFile.unpickle()

	allTransforms = cmd.ls( typ='transform' )
	for n, postTraceCmd in postTraceDict.iteritems():
		n = n.split( '.' )[ 0 ]  #strip off the attribute
		nInScene = names.matchNames( [ n ], allTransforms )[ 0 ]
		if cmd.objExists( nInScene ):
			api.mel.zooSetPostTraceCmd( nInScene, postTraceCmd )
Exemple #13
0
def loadPostTraceSchemeFilepath(presetFile):
    '''
	re-applies a stored post trace command scheme back to the controls found in the current scene
	'''

    #first we need to purge all existing post trace commands
    clearPostTraceScheme()

    presetFile = Path(presetFile)
    if not presetFile.isfile():
        raise IOError, "no such preset"

    xportDict, postTraceDict = presetFile.unpickle()

    allTransforms = cmd.ls(typ='transform')
    for n, postTraceCmd in postTraceDict.iteritems():
        n = n.split('.')[0]  #strip off the attribute
        nInScene = names.matchNames([n], allTransforms)[0]
        if cmd.objExists(nInScene):
            api.mel.zooSetPostTraceCmd(nInScene, postTraceCmd)
Exemple #14
0
def commonApply(rig,
                rigNS,
                filename,
                nodes,
                mapping,
                postTraceSchemeFilepath=None,
                sortBySrcs=True):

    #apply the post trace scheme if applicable
    if postTraceSchemeFilepath is not None:
        loadPostTraceSchemeFilepath(postTraceSchemeFilepath)

    possibleSrcs = cmd.ls('%s*' % IMPORT_DATA_NS, typ='transform')
    possibleTgts = cmd.ls('%s*' % rigNS, typ='transform')

    #build the ctrl-bone mapping - and ensure proper namespaces are present...  the mapping contains no namespaces
    srcs, tgts = [], []
    idx = 0 if sortBySrcs else 1
    toSort = []
    for src, tgt in mapping.iteritems():
        src = names.matchNames([src], possibleSrcs)[0]
        tgt = names.matchNames([tgt], possibleTgts)[0]
        srcOrTgt = src, tgt

        if cmd.objExists(srcOrTgt[idx]):
            numParents = len(list(api.iterParents(srcOrTgt[idx])))
            toSort.append((numParents, src, tgt))

    toSort.sort()
    for idx, src, tgt in toSort:
        srcs.append(src)
        tgts.append(tgt)

    print "rig namespace is:", rigNS
    print 'srcs are', srcs
    print 'tgts are', tgts

    #sort the items by hierarchy based on the src items - xferAnim does have the option of doing this, but it sorts using the tgt list, and its done in mel, so...  I don't trust it
    srcsParentCount = [(len([p for p in api.iterParents(s)]), s, t)
                       for s, t in zip(srcs, tgts) if cmd.objExists(s)]
    srcsParentCount.sort()
    srcs = [s[1] for s in srcsParentCount]
    tgts = [s[2] for s in srcsParentCount]

    #now turn any ik off - we'll restore it afterwards, but if ik is on, then fk controls don't get traced properly...  coz maya is ghey!
    initIkBlendValues = {}
    for t in tgts:
        attrPath = "%s.ikBlend" % t
        if cmd.objExists(attrPath):
            initIkBlendValues[attrPath] = cmd.getAttr(attrPath)
            cmd.setAttr(attrPath, 0)

    #perform the trace
    api.melecho.zooXferTrace(srcs, tgts, True, True, False, True, False, -1000,
                             1000)

    #restore ik settings
    for attrPath, value in initIkBlendValues.iteritems():
        cmd.setAttr(attrPath, value)

    #rename the file
    mayaFilepath = apps.getAssetRoot(
        rig, apps.MAYA) / 'maya/animation' / filename.name()
    mayaFilepath.up().create()
    cmd.file(rename=mayaFilepath)
    mayaFilepath = Path(cmd.file(q=True, sn=True))

    #try to determine the info node to export
    exportNode = None
    for n in cmd.ls(typ='vstInfo'):
        if n.startswith(rigNS):
            exportNode = n
            break

    #setup the export manager data if we can...
    if exportNode is not None:
        xm = exportManagerCore.ExportManager()
        comp = xm.createExportComponent([exportNode])
        comp.setAttr('name', mayaFilepath.name())
        comp.setAttr('type', exportManagerCore.ExportComponent.kANIM)

    #save changes...
    cmd.file(save=True, f=True)

    return mayaFilepath
	def mapSrcItem( self, src ):
		self._srcToTgtDict[ src ] = names.matchNames( [ src ], self.tgts, self.STRIP_NAMESPACES, self.PARITY_MATCH, self.UNIQUE_MATCHING, self.MATCH_OPPOSITE_PARITY, self.THRESHOLD )
Exemple #16
0
def generate( baseStart, baseEnd,\
     rotations =               PRIMARY_ROTATIONS,\
     strideLengthMultipliers = PRIMARY_SPEEDS,\
     starts =                  PRIMARY_START_FRAMES,\
     directions =              PRIMARY_NAMES ):

    #determine which ctrl set to use
    ctrlSet = names.matchNames(['body_ctrls'],
                               cmd.ls(type='objectSet'),
                               threshold=1)
    if not ctrlSet:
        raise Exception('control set not found')
    ctrlSet = ctrlSet[0]

    ctrls = cmd.sets(ctrlSet, q=True)
    length = baseEnd - baseStart
    num = len(rotations)

    #does the base locomote have an asset?
    vx = exportManagerCore.ExportManager()
    baseAsset = vx.exists(start=baseStart, end=baseEnd)
    infoNode = ''
    exportSet = ''
    if len(baseAsset):
        baseAsset = baseAsset[0]
        exportSet = baseAsset.obj
    else:
        #if it doesn't exist, try and create one
        infoNodes = cmd.ls(type='vstInfo')
        candidates = []
        for node in infoNodes:
            if not cmd.referenceQuery(node, inr=True): continue
            if not cmd.listRelatives(node): continue
            candidates.append(node)
        infoNode = candidates[0]
        exportSet = exportManagerCore.ExportManager.CreateExportSet([infoNode])

        #now build the actual asset
        asset = vx.createAsset(exportSet)
        asset.setAttr('start', baseStart)
        asset.setAttr('end', baseEnd)
        asset.setAttr('name', 'N')
        asset.setAttr('type', exportManagerCore.ExportComponent.kANIM)

    #grab the list of ctrls we need to actually transform
    toFind = ['upperBodyControl', 'legControl_L',
              'legControl_R']  #, 'armControl_L', 'armControl_R' ]
    xformCtrls = [
        name
        for name in names.matchNames(toFind, ctrls, parity=True, threshold=0.8)
        if name != ''
    ]

    animation = Animation(ctrls, baseStart, baseEnd)
    animation.getWorld(xformCtrls, ['translateX', 'translateZ'])

    #save the animation out - useful for doing deltas later on
    #write(animation,g_defaultKeyUtilsPickle)

    #build the rotation axis
    axis = vectors.Vector([0, 1, 0])

    for n in xrange(num):
        offset = starts[n] - baseStart

        tmpAnim = animation.copy()
        tmpAnim.offset(offset)

        #convert angles to radians, and do other static calcs
        angle = rotations[n]
        angle = math.radians(angle)
        quat = vectors.Quaternion.AxisAngle(axis, angle)

        for ctrl in xformCtrls:
            clip = tmpAnim[ctrl]

            #do the actual rotation around Y
            mats = clip.world
            translateX = clip.translateX.keys = []
            translateZ = clip.translateZ.keys = []
            for mat in mats:
                pos = mat.get_position()
                pos = pos.rotate(quat)
                mat[3][:3] = pos

                translateX.append(Key(time=mat.time, value=pos.x))
                translateZ.append(Key(time=mat.time, value=pos.z))

            #now do stride length multiplication
            strideMult = strideLengthMultipliers[n]
            if strideMult is not None:

                def makeShorter(key):
                    key.value *= strideMult
                    return key

                clip.translateX.transform(makeShorter)
                clip.translateZ.transform(makeShorter)

        tmpAnim.applyToObjs(clearFirst=True)

        #finally create an asset for the new anim
        existing = vx.exists(start=starts[n],
                             end=starts[n] + length,
                             name=directions[n])
        if not len(existing):
            asset = vx.createAsset(exportSet)
            asset.setAttr('start', starts[n])
            asset.setAttr('end', starts[n] + length)
            asset.setAttr('name', directions[n])
            asset.setAttr('type', exportManagerCore.ExportComponent.kANIM)
Exemple #17
0
def commonApply( rig, rigNS, filename, nodes, mapping, postTraceSchemeFilepath=None, sortBySrcs=True ):

	#apply the post trace scheme if applicable
	if postTraceSchemeFilepath is not None:
		loadPostTraceSchemeFilepath( postTraceSchemeFilepath )


	possibleSrcs = cmd.ls( '%s*' % IMPORT_DATA_NS, typ='transform' )
	possibleTgts = cmd.ls( '%s*' % rigNS, typ='transform' )


	#build the ctrl-bone mapping - and ensure proper namespaces are present...  the mapping contains no namespaces
	srcs, tgts = [], []
	idx = 0 if sortBySrcs else 1
	toSort = []
	for src, tgt in mapping.iteritems():
		src = names.matchNames( [ src ], possibleSrcs )[ 0 ]
		tgt = names.matchNames( [ tgt ], possibleTgts )[ 0 ]
		srcOrTgt = src, tgt

		if cmd.objExists( srcOrTgt[ idx ] ):
			numParents = len( list( api.iterParents( srcOrTgt[ idx ] ) ) )
			toSort.append( (numParents, src, tgt) )

	toSort.sort()
	for idx, src, tgt in toSort:
		srcs.append( src )
		tgts.append( tgt )


	print "rig namespace is:", rigNS
	print 'srcs are', srcs
	print 'tgts are', tgts


	#sort the items by hierarchy based on the src items - xferAnim does have the option of doing this, but it sorts using the tgt list, and its done in mel, so...  I don't trust it
	srcsParentCount = [ (len( [p for p in api.iterParents( s )] ), s, t) for s, t in zip( srcs, tgts ) if cmd.objExists( s ) ]
	srcsParentCount.sort()
	srcs = [ s[ 1 ] for s in srcsParentCount ]
	tgts = [ s[ 2 ] for s in srcsParentCount ]


	#now turn any ik off - we'll restore it afterwards, but if ik is on, then fk controls don't get traced properly...  coz maya is ghey!
	initIkBlendValues = {}
	for t in tgts:
		attrPath = "%s.ikBlend" % t
		if cmd.objExists( attrPath ):
			initIkBlendValues[ attrPath ] = cmd.getAttr( attrPath )
			cmd.setAttr( attrPath, 0 )


	#perform the trace
	api.melecho.zooXferTrace( srcs, tgts, True, True, False, True, False, -1000, 1000 )


	#restore ik settings
	for attrPath, value in initIkBlendValues.iteritems():
		cmd.setAttr( attrPath, value )


	#rename the file
	mayaFilepath = apps.getAssetRoot( rig, apps.MAYA ) / 'maya/animation' / filename.name()
	mayaFilepath.up().create()
	cmd.file( rename=mayaFilepath )
	mayaFilepath = Path( cmd.file( q=True, sn=True ) )


	#try to determine the info node to export
	exportNode = None
	for n in cmd.ls( typ='vstInfo' ):
		if n.startswith( rigNS ):
			exportNode = n
			break


	#setup the export manager data if we can...
	if exportNode is not None:
		xm = exportManagerCore.ExportManager()
		comp = xm.createExportComponent( [ exportNode ] )
		comp.setAttr( 'name', mayaFilepath.name() )
		comp.setAttr( 'type', exportManagerCore.ExportComponent.kANIM )


	#save changes...
	cmd.file( save=True, f=True )

	return mayaFilepath
Exemple #18
0
def generate( baseStart, baseEnd,\
			  rotations =               PRIMARY_ROTATIONS,\
			  strideLengthMultipliers = PRIMARY_SPEEDS,\
			  starts =                  PRIMARY_START_FRAMES,\
			  directions =              PRIMARY_NAMES ):

	#determine which ctrl set to use
	ctrlSet = names.matchNames(['body_ctrls'],cmd.ls(type='objectSet'),threshold=1)
	if not ctrlSet:
		raise Exception('control set not found')
	ctrlSet = ctrlSet[0]

	ctrls = cmd.sets(ctrlSet,q=True)
	length = baseEnd-baseStart
	num = len(rotations)


	#does the base locomote have an asset?
	vx = exportManagerCore.ExportManager()
	baseAsset = vx.exists(start=baseStart,end=baseEnd)
	infoNode = ''
	exportSet = ''
	if len(baseAsset):
		baseAsset = baseAsset[0]
		exportSet = baseAsset.obj
	else:
		#if it doesn't exist, try and create one
		infoNodes = cmd.ls(type='vstInfo')
		candidates = []
		for node in infoNodes:
			if not cmd.referenceQuery(node,inr=True): continue
			if not cmd.listRelatives(node): continue
			candidates.append(node)
		infoNode = candidates[0]
		exportSet = exportManagerCore.ExportManager.CreateExportSet( [infoNode] )

		#now build the actual asset
		asset = vx.createAsset(exportSet)
		asset.setAttr('start', baseStart)
		asset.setAttr('end', baseEnd)
		asset.setAttr('name', 'N')
		asset.setAttr('type', exportManagerCore.ExportComponent.kANIM)


	#grab the list of ctrls we need to actually transform
	toFind = [ 'upperBodyControl', 'legControl_L', 'legControl_R' ]#, 'armControl_L', 'armControl_R' ]
	xformCtrls = [ name for name in names.matchNames( toFind, ctrls, parity=True, threshold=0.8 ) if name != '' ]

	animation = Animation( ctrls, baseStart, baseEnd )
	animation.getWorld(xformCtrls,['translateX','translateZ'])

	#save the animation out - useful for doing deltas later on
	#write(animation,g_defaultKeyUtilsPickle)

	#build the rotation axis
	axis = vectors.Vector([0, 1, 0])

	for n in xrange(num):
		offset = starts[n]-baseStart

		tmpAnim = animation.copy()
		tmpAnim.offset( offset )

		#convert angles to radians, and do other static calcs
		angle = rotations[n]
		angle = math.radians(angle)
		quat = vectors.Quaternion.AxisAngle( axis, angle )

		for ctrl in xformCtrls:
			clip = tmpAnim[ctrl]

			#do the actual rotation around Y
			mats = clip.world
			translateX = clip.translateX.keys = []
			translateZ = clip.translateZ.keys = []
			for mat in mats:
				pos = mat.get_position()
				pos = pos.rotate(quat)
				mat[3][:3] = pos

				translateX.append( Key( time=mat.time, value=pos.x ) )
				translateZ.append( Key( time=mat.time, value=pos.z ) )

			#now do stride length multiplication
			strideMult = strideLengthMultipliers[n]
			if strideMult is not None:
				def makeShorter( key ):
					key.value *= strideMult
					return key

				clip.translateX.transform(makeShorter)
				clip.translateZ.transform(makeShorter)

		tmpAnim.applyToObjs(clearFirst=True)

		#finally create an asset for the new anim
		existing = vx.exists( start=starts[n], end=starts[n]+length, name=directions[n] )
		if not len(existing):
			asset = vx.createAsset( exportSet )
			asset.setAttr('start', starts[n])
			asset.setAttr('end', starts[n]+length)
			asset.setAttr('name', directions[n])
			asset.setAttr('type', exportManagerCore.ExportComponent.kANIM)