435 lines
19 KiB
Python
Executable File
435 lines
19 KiB
Python
Executable File
from pyfbsdk import *
|
|
import RS.Globals as glo
|
|
import RS.Utils.Scene
|
|
import RS.Perforce
|
|
import os
|
|
|
|
###############################################################################################################
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
##
|
|
## Description: Compare And Rename
|
|
##
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
###############################################################################################################
|
|
|
|
global gArray
|
|
gArray = []
|
|
|
|
###############################################################################################################
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
##
|
|
## Description: Find Animation Node Helper Function
|
|
##
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
###############################################################################################################
|
|
|
|
def findAnimationNode( pName, pNode ):
|
|
lResult = None
|
|
lName = pName.split( '/' )
|
|
for lNode in pNode.Nodes:
|
|
if lNode.Name == lName[0]:
|
|
if len( lName ) > 1:
|
|
lResult = findAnimationNode( pName.replace( '%s/' % lName[0], '' ), lNode )
|
|
else:
|
|
lResult = lNode
|
|
return lResult
|
|
|
|
# This recursive function finds the first and last keyframe of an
|
|
# animation node.
|
|
def FindLimits( pNode, pLLimit=None, pRLimit=None ):
|
|
# First let's see if the node has any keys
|
|
if pNode.FCurve:
|
|
|
|
# Got thru the list, updating the first and last frame if necessary.
|
|
# Limits are initialised on first comparaison attempt.
|
|
for lKey in pNode.FCurve.Keys:
|
|
|
|
if pLLimit:
|
|
if lKey.Time.Get() < pLLimit.Get():
|
|
pLLimit.Set( lKey.Time.Get())
|
|
else:
|
|
pLLimit = FBTime()
|
|
pLLimit.Set( lKey.Time.Get())
|
|
if pRLimit:
|
|
if lKey.Time.Get() > pRLimit.Get():
|
|
pRLimit.Set( lKey.Time.Get())
|
|
else:
|
|
pRLimit = FBTime()
|
|
pRLimit.Set( lKey.Time.Get())
|
|
|
|
# If the node has any children nodes, we navigate those.
|
|
if pNode.Nodes:
|
|
for lNode in pNode.Nodes:
|
|
( pLLimit, pRLimit ) = FindLimits( lNode, pLLimit, pRLimit )
|
|
|
|
return ( pLLimit, pRLimit )
|
|
|
|
###############################################################################################################
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
##
|
|
## Description: Move Animation Helper Function
|
|
##
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
###############################################################################################################
|
|
|
|
def MoveAnimation(pNode, pDelta):
|
|
# Modify all the keys of the current node.
|
|
if pNode.FCurve:
|
|
# Create a list of the keys. This new list can be re-sorted without
|
|
# affecting the internal list.
|
|
lKeys = [ lKey for lKey in pNode.FCurve.Keys ]
|
|
|
|
# If the delta is positive, we need to move the keys starting with
|
|
# the last. This prevent any changes in the order of the keys in the
|
|
# internal list.
|
|
if pDelta.Get() > 0:
|
|
lKeys.reverse()
|
|
|
|
# Set the new time value for all the keys.
|
|
for lKey in lKeys:
|
|
lTime = FBTime()
|
|
lTime.Set( lKey.Time.Get() + pDelta.Get() )
|
|
lKey.Time = lTime
|
|
|
|
# Now deal with all the children nodes.
|
|
if pNode.Nodes:
|
|
for lNode in pNode.Nodes:
|
|
MoveAnimation( lNode, pDelta )
|
|
|
|
|
|
###############################################################################################################
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
##
|
|
## Description: Copy the Animation Helper Function
|
|
##
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
###############################################################################################################
|
|
|
|
def copyAnimation(pSrc):
|
|
global gArray
|
|
lArray = []
|
|
lArray.append(pSrc.Name)
|
|
for pName in [ 'Lcl Translation/X','Lcl Translation/Y','Lcl Translation/Z', 'Lcl Rotation/X','Lcl Rotation/Y','Lcl Rotation/Z']:
|
|
|
|
lSrcNode = findAnimationNode( pName, pSrc.AnimationNode )
|
|
|
|
if lSrcNode and lSrcNode.FCurve:
|
|
lArray.append(lSrcNode.FCurve)
|
|
|
|
gArray.append(lArray)
|
|
|
|
###############################################################################################################
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
##
|
|
## Description: Creat Ghost
|
|
##
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
###############################################################################################################
|
|
|
|
def CreateGhost(pPath, pName):
|
|
|
|
lPath = pPath
|
|
lOptions = FBFbxOptions(True, lPath)
|
|
lOptions.SetAll(FBElementAction.kFBElementActionDiscard, False)
|
|
lOptions.Bones = FBElementAction.kFBElementActionAppend
|
|
lOptions.Models = FBElementAction.kFBElementActionAppend
|
|
lOptions.Groups = FBElementAction.kFBElementActionAppend
|
|
lOptions.TakeSpan = FBTakeSpanOnLoad.kFBLeaveAsIs
|
|
lOptions.NamespaceList = "GHOST"
|
|
|
|
for lTakeIndex in range( lOptions.GetTakeCount() ):
|
|
lOptions.SetTakeSelect( lTakeIndex, False )
|
|
|
|
lOptions.BaseCameras = False
|
|
lOptions.CameraSwitcherSettings = False
|
|
lOptions.CurrentCameraSettings = False
|
|
lOptions.CamerasAnimation = False
|
|
lOptions.TransportSettings = False
|
|
lOptions.GlobalLightingSettings = False
|
|
|
|
# Make sure you have a copy of this file on your computer:
|
|
if not os.path.isfile( lPath ):
|
|
RS.Perforce.Sync( lPath )
|
|
|
|
lApp = FBApplication()
|
|
lApp.FileMerge(lPath, False, lOptions)
|
|
|
|
lMover = FBFindModelByLabelName("GHOST:mover")
|
|
if not lMover:
|
|
FBMessageBox("CreateGhost", "Can't find ghost mover!", "OK")
|
|
return
|
|
lMover.Show = True
|
|
|
|
lProp = lMover.PropertyCreate('Ghost Type', FBPropertyType.kFBPT_charptr, 'String', False, True, None)
|
|
if lProp:
|
|
lProp.Data = pName
|
|
|
|
for lTake in glo.gTakes:
|
|
lTake.PropertyCreate('Ghost Take Anim', FBPropertyType.kFBPT_charptr, 'String', False, True, None)
|
|
|
|
lShaderManager = FBShaderManager()
|
|
|
|
lShader = lShaderManager.CreateShader( "LightedShader" )
|
|
lShader.Name = "GHOST:Shader"
|
|
lShader.Transparency = FBAlphaSource.kFBAlphaSource2DTransparency
|
|
lShader.Alpha = 0.51
|
|
|
|
lGeometry = FBFindModelByLabelName("GHOST:Geometry")
|
|
if lGeometry:
|
|
for iChild in lGeometry.Children:
|
|
iChild.ShadingMode = FBModelShadingMode.kFBModelShadingAll
|
|
lShader.ReplaceAll( iChild )
|
|
glo.gScene.Evaluate()
|
|
|
|
|
|
###############################################################################################################
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
##
|
|
## Description:
|
|
##
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
###############################################################################################################
|
|
|
|
def rs_CopyAnimationFromTake(ghostTake, ghost, startFrame):
|
|
lScene = FBSystem().Scene
|
|
# This get the current Take in the scene
|
|
lCurrentTake = FBSystem().CurrentTake
|
|
for iTake in lScene.Takes:
|
|
# if the current take in the scene is set to the one in the Ghost Take the user set, then set the current take Ghost Take
|
|
if iTake.Name == ghostTake:
|
|
FBSystem().CurrentTake = iTake
|
|
|
|
#If we migrate this code to 2013 and higher, there is no bool value for the first variable, so remove the parameter then.
|
|
lPlayer = FBPlayerControl()
|
|
lGhostStartFrame = lPlayer.ZoomWindowStart.GetFrame()
|
|
lGhostStopFrame = lPlayer.ZoomWindowStop.GetFrame()
|
|
lSizeGhostAnimFrame = lGhostStopFrame - lGhostStartFrame
|
|
|
|
lFound = False
|
|
for lSkel in glo.gSkelArray:
|
|
if lSkel == "mover":
|
|
lFound = True
|
|
if lFound == False:
|
|
glo.gSkelArray.append("mover")
|
|
|
|
# Copy Animation
|
|
for iBone in glo.gSkelArray:
|
|
|
|
lSrc = FBFindModelByLabelName(ghost + ":" + iBone)
|
|
if lSrc:
|
|
lSrc.Translation.SetAnimated(True)
|
|
lSrc.Rotation.SetAnimated(True)
|
|
lSrc.Scaling.SetAnimated(True)
|
|
copyAnimation(lSrc)
|
|
|
|
FBSystem().CurrentTake = lCurrentTake
|
|
|
|
# Setting the Transport Controls View
|
|
lActualStartFrame = lPlayer.ZoomWindowStart.GetFrame()
|
|
lActualStopFrame = lPlayer.ZoomWindowStop.GetFrame()
|
|
|
|
# Putting Animation on the Ghost
|
|
for i in range(len(gArray)):
|
|
|
|
# The first item in each list in the list is the bone name, first we find that bone on the ghost
|
|
# This is what the array holds ['SKEL_L_Finger0_NUB', 1->XTranslation, 2->YTranslation, 3->ZTranslation, 4->XRotation, 5->YRotation, 6->ZRotation]
|
|
lBone = FBFindModelByLabelName("GHOST:" + gArray[i][0])
|
|
if lBone:
|
|
print lBone.LongName
|
|
lBone.Translation.SetAnimated(True)
|
|
lBone.Rotation.SetAnimated(True)
|
|
|
|
lBone.Translation.GetAnimationNode().Nodes[0].FCurve.EditClear()
|
|
lBone.Translation.GetAnimationNode().Nodes[1].FCurve.EditClear()
|
|
lBone.Translation.GetAnimationNode().Nodes[2].FCurve.EditClear()
|
|
|
|
lBone.Translation.GetAnimationNode().Nodes[0].FCurve.KeyReplaceBy(gArray[i][1])
|
|
#lKeys = [ lKey for lKey in gArray[i][1].Keys ]
|
|
#for lKey in lKeys:
|
|
# print lKey.Value
|
|
print lBone.Translation.GetAnimationNode().Nodes[0]
|
|
lBone.Translation.GetAnimationNode().Nodes[1].FCurve.KeyReplaceBy(gArray[i][2])
|
|
lBone.Translation.GetAnimationNode().Nodes[2].FCurve.KeyReplaceBy(gArray[i][3])
|
|
|
|
lBone.Rotation.GetAnimationNode().Nodes[0].FCurve.EditClear()
|
|
lBone.Rotation.GetAnimationNode().Nodes[1].FCurve.EditClear()
|
|
lBone.Rotation.GetAnimationNode().Nodes[2].FCurve.EditClear()
|
|
|
|
lBone.Rotation.GetAnimationNode().Nodes[0].FCurve.KeyReplaceBy(gArray[i][4])
|
|
lBone.Rotation.GetAnimationNode().Nodes[1].FCurve.KeyReplaceBy(gArray[i][5])
|
|
lBone.Rotation.GetAnimationNode().Nodes[2].FCurve.KeyReplaceBy(gArray[i][6])
|
|
|
|
|
|
# Only need to Move the Animation if an alternate start frame is provided in the UI
|
|
if startFrame != "":
|
|
print "Not Moving the animation"
|
|
startFrame = int(startFrame)
|
|
for i in range(len(gArray)):
|
|
|
|
# The first item in each list in the list is the bone name, first we find that bone on the ghost
|
|
# This is what the array holds ['SKEL_L_Finger0_NUB', 1->XTranslation, 2->YTranslation, 3->ZTranslation, 4->XRotation, 5->YRotation, 6->ZRotation]
|
|
lBone = FBFindModelByLabelName("GHOST:" + gArray[i][0])
|
|
if lBone:
|
|
# Find the earliest keyframe.
|
|
( lLTime, lRTime ) = FindLimits( lBone.AnimationNode )
|
|
# If we do have a first keyframe...
|
|
if lLTime:
|
|
# Compute the delta between the current time and the first key.
|
|
lNewStartTime = FBTime(0,0,0,startFrame)
|
|
lDelta = FBTime()
|
|
lDelta.Set( lNewStartTime.Get() - lLTime.Get())
|
|
|
|
# Do the work...
|
|
MoveAnimation( lBone.AnimationNode, lDelta )
|
|
|
|
# Makes sure the Transport Control spans both the actual take and the ghost take animation
|
|
if startFrame < lActualStartFrame:
|
|
lPlayer.ZoomWindowStart = FBTime(0,0,0,startFrame)
|
|
lPlayer.LoopStart = FBTime(0,0,0,startFrame)
|
|
lPlayer.Goto (FBTime(0,0,0,startFrame))
|
|
if (startFrame+lSizeGhostAnimFrame) > lActualStopFrame:
|
|
lPlayer.ZoomWindowStop = FBTime(0,0,0,(startFrame+lSizeGhostAnimFrame))
|
|
lPlayer.LoopStop = FBTime(0,0,0,(startFrame+lSizeGhostAnimFrame))
|
|
|
|
# Makes sure the Transport Control spans both the actual take and the ghost take animation
|
|
else:
|
|
if lGhostStartFrame<lActualStartFrame:
|
|
lPlayer.ZoomWindowStart = FBTime(0,0,0,lGhostStartFrame)
|
|
lPlayer.LoopStart = FBTime(0,0,0,lGhostStartFrame)
|
|
lPlayer.Goto (FBTime(0,0,0,lGhostStartFrame))
|
|
if lGhostStopFrame>lActualStopFrame:
|
|
lPlayer.ZoomWindowStop = FBTime(0,0,0,lGhostStopFrame)
|
|
lPlayer.LoopStop = FBTime(0,0,0,lGhostStopFrame)
|
|
|
|
###############################################################################################################
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
##
|
|
## Description: Compare And Rename
|
|
##
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
###############################################################################################################
|
|
def rs_CreateGhost(ghost):
|
|
|
|
# By Design you can only create one ghost in the scene at a time
|
|
cl = RS.Utils.Scene.FindObjectsByNamespace( "GHOST*" )
|
|
|
|
if cl:
|
|
FBMessageBox("rs_CreateGhost", "There is already a ghost, you cannot create another one, unless you delete it", "OK")
|
|
return
|
|
|
|
lNull = FBFindModelByLabelName("RS_Null:" + ghost)
|
|
|
|
if lNull:
|
|
|
|
# Get the file location of the reference
|
|
lProp = lNull.PropertyList.Find("Reference Path")
|
|
|
|
if lProp:
|
|
CreateGhost(lProp.Data, ghost)
|
|
|
|
###############################################################################################################
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
##
|
|
## Description: The puts the animation from the selected take onto the ghost in the current take
|
|
##
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
###############################################################################################################
|
|
def rs_CreateGhostTake(ghostTake, startFrame):
|
|
lMover = FBFindModelByLabelName("GHOST:mover")
|
|
if lMover:
|
|
lProp = lMover.PropertyList.Find('Ghost Type')
|
|
if lProp:
|
|
if lProp.Data:
|
|
ghost = lProp.Data
|
|
rs_CopyAnimationFromTake(ghostTake, ghost, startFrame)
|
|
else:
|
|
FBMessageBox("rs_GhostTakeCoreFunctions", "There is no ghost is this file, please add one first", "OK")
|
|
###############################################################################################################
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
##
|
|
## Description: Delete the Ghost from the file
|
|
##
|
|
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
###############################################################################################################
|
|
|
|
def DestroyGroup(Model):
|
|
for child in Model.Children:
|
|
if len (child.Children) < 1:
|
|
child.FBDelete()
|
|
else:
|
|
DestroyGroup(child)
|
|
|
|
def DestroyModel( pModel ):
|
|
# Always destroy from the last children to the first
|
|
while len( pModel.Children ) > 0:
|
|
DestroyModel( pModel.Children[-1] )
|
|
pModel.FBDelete()
|
|
|
|
def rs_DeleteGhost(pControl, pEvent):
|
|
|
|
# Remove 'Ghost Take Anim' Property from Takes
|
|
for lTake in FBSystem().Scene.Takes:
|
|
lProp = lTake.PropertyList.Find("Ghost Take Anim")
|
|
if lProp:
|
|
lTake.PropertyRemove (lProp)
|
|
|
|
lObj = FBFindObjectByFullName ("GHOST:RexRageCutsceneExportMarkup")
|
|
if lObj:
|
|
lObj.FBDelete()
|
|
|
|
|
|
# Since this works off selection, we have to make sure nothing else is selected.
|
|
for lComp in FBSystem().Scene.Components:
|
|
lComp.Selected = False
|
|
|
|
FBSystem().Scene.NamespaceSelectContent("GHOST", True)
|
|
lModelList = FBModelList()
|
|
|
|
# Deleting Models
|
|
for i in range(10):
|
|
FBGetSelectedModels( lModelList )
|
|
|
|
if lModelList.count() > 0:
|
|
DestroyModel( lModelList[0] )
|
|
|
|
lModelList.Clear()
|
|
|
|
# Since this works off selection, we have to make sure nothing else is selected.
|
|
for lComp in FBSystem().Scene.Components:
|
|
lComp.Selected = False
|
|
|
|
# Clean up all the empty folders
|
|
for folder in FBSystem().Scene.Folders:
|
|
for item in folder.Items:
|
|
if isinstance(item,FBCharacter):
|
|
folder.Items.remove(item)
|
|
|
|
lFolderList = []
|
|
for lFolder in glo.gFolders:
|
|
if len(lFolder.Items) == 0:
|
|
lFolderList.append(lFolder)
|
|
|
|
map( FBComponent.FBDelete, lFolderList )
|
|
|
|
FBSystem().Scene.NamespaceSelectContent("GHOST", True)
|
|
|
|
|
|
# Deleting all the remaining components in the scene
|
|
lList = []
|
|
for lComp in FBSystem().Scene.Components:
|
|
if lComp != None and lComp.Selected:
|
|
if lComp.ClassName() == 'FBGroup':
|
|
# Appending to list to be deleted after
|
|
lList.append(lComp)
|
|
|
|
for iDelete in lList:
|
|
try:
|
|
iDelete.FBDelete()
|
|
except:
|
|
pass
|
|
|
|
# The stupid Decklink Video Capture, gets the GHOST namespace
|
|
cl = RS.Utils.Scene.FindObjectsByNamespace("GHOST")
|
|
for item in cl:
|
|
item.ProcessObjectNamespace(FBNamespaceAction.kFBRemoveAllNamespace, "GHOST")
|
|
|