Files
2025-09-29 00:52:08 +02:00

1526 lines
83 KiB
Python
Executable File

###############################################################################################################
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
##
## Script Name: Core\AnimToFBX.py
## Written And Maintained By: David Bailey
## Contributors: Ross George and Kristine Middlemiss
## Description: This tool plots animation from Anim files to FBX Character
##
## Rules: Definitions: Prefixed with "rs_"
## Global Variables: Prefixed with "g"
## Local Variables: Prefixed with "l"
## Iteration Variables: Prefixed with "i"
## Arguments: Prefixed with "p"
##
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
###############################################################################################################
from pyfbsdk import *
import RS.Globals
import RS.Utils.Path
import RS.Utils.Scene
import RS.Utils.AnimFile
import RS.Config
import os
import subprocess
import clr
from pythonidelib import *
clr.AddReference("RSG.Base.Configuration")
from RSG.Base.Configuration import ConfigFactory
import RS.Tools.ModelViews.AnimToFBX as depotFileData
_Config = ConfigFactory.CreateConfig()
###############################################################################################################
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
##
## Description: Globals
##
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
###############################################################################################################
gProjRoot = RS.Config.Project.Path.Root
gToolsRoot = RS.Config.Tool.Path.Root
def partition(alist, indices):
return [alist[i:j] for i, j in zip([0]+indices, indices+[None])]
'''
!!! This entire script needs to be rewritten !!!!
Added better way to run anim to bat file but we shoudl pipe the data instead into a class (I've got shelved code to do this)
'''
def runAnimBatch(pFileName):
defaultskel = 'player.skel'
if RS.Config.Project.Name == 'RDR3':
defaultskel = 'biped.skel'
cmd = '{0}/anim/animdump.exe -anim {1} -values -eulers -output > {1}.txt -skel "{2}/etc/config/anim/skeletons/{3}" '.format(RS.Config.Tool.Path.Bin, pFileName, RS.Config.Tool.Path.Root, defaultskel)
os.system(pFileName)
''''''
def rs_TrackArray(pFileName, pSource):
# This extracts the anim file
runAnimBatch(pFileName)
# A check to ensure people are selecting a file that ends in .anim
if pFileName.endswith(".anim"):
if pSource == "FACIAL":
lFile = None
lTrackIndexArray = []
lEndFrame = None
# Reading the anim.txt file to retrieve the key information
lFile = open(pFileName + ".txt", "r")
lFile = lFile.readlines()
for iLine in lFile:
if iLine.startswith("InternalFrames"):
#This Value is in Frames
lEndFrame = int(iLine.partition("\t")[2])
if iLine.startswith("Track"):
# lTrackIndexArray is tracking the line number that start with Track
lTrackIndexArray.append(lFile.index(iLine))
if lEndFrame != None:
lTrackArray = []
# This basically take the two different data's you have and zips it into one array
lTrackArray = partition(lFile, lTrackIndexArray)
lCmdString = ""
lName = pFileName.split(".")
lInputFile = lName[0] + ".clip"
lCmdString = "{0}\\bin\\anim\\clipdump.bat \"{InputFile}\"".format( RS.Config.Tool.Path.Root, InputFile = lInputFile)
subprocess.call(lCmdString, stdin=None, stdout=None, stderr=None, shell=True)
# Reading the clip.txt file to retrieve player controls information
lFile2 = open(lInputFile + ".txt", "r")
lFile2 = lFile2.readlines()
TimeOfPreDelay = None
# This is just making sure the Transport Controls is setup to see all the frames so the user doesn't have to update it.
for iLine in lFile2:
if iLine.startswith("float"):
#This Value is in Seconds
floatLine = float(iLine.partition(" ")[2].strip())
lValueFrames = floatLine * 30 # 30 Frames a second for project
TimeOfPreDelay = int(round(-lValueFrames))
break
if TimeOfPreDelay != None:
lStartFrame = FBTime(0,0,0,TimeOfPreDelay)
lEndFrame = FBTime(0,0,0,lEndFrame+TimeOfPreDelay)
lPlayerControls = FBPlayerControl()
lPlayerControls.LoopStart = lStartFrame
lPlayerControls.ZoomWindowStart = lStartFrame
lPlayerControls.LoopStop = lEndFrame
lPlayerControls.ZoomWindowStop = lEndFrame
lPlayerControls.Goto(lStartFrame)
# Workaround for getting the last take to commit
curTake = FBSystem().CurrentTake
curTake.LocalTimeSpan = FBTimeSpan(lStartFrame, lEndFrame)
return lTrackArray, TimeOfPreDelay
else:
lStartFrame = FBTime(0,0,0,0)
# -1 to compensate for the zero frame
lEndFrame = FBTime(0,0,0,lEndFrame-1)
lPlayerControls = FBPlayerControl()
lPlayerControls.LoopStart = lStartFrame
lPlayerControls.ZoomWindowStart = lStartFrame
lPlayerControls.LoopStop = lEndFrame
lPlayerControls.ZoomWindowStop = lEndFrame
lPlayerControls.Goto(lStartFrame)
# Workaround for getting the last take to commit
curTake = FBSystem().CurrentTake
curTake.LocalTimeSpan = FBTimeSpan(lStartFrame, lEndFrame)
FBMessageBox( "Warning", "No Pre-Delay value was found, the animation is starting at zero.", "OK")
return lTrackArray, None
else:
FBMessageBox( "Error", "The value for 'InternalFrames' was not found in the anim file.", "OK")
return None
# For CHARACTER and PROPS and POSES
else:
lFile = None
lTrackIndexArray = []
# Reading the anim.txt file to retrieve some key information
#pFileName = 'x:\\rdr3\\assets\\anim\\ingame/MECH_LOCO/@PLAYER/@ZERO/@GENERIC/@BASE/Idle.anim'
lFile = open(pFileName + ".txt", "r")
lFile = lFile.readlines()
for iLine in lFile:
if iLine.startswith("InternalFrames"):
# This is just making sure the Transport Controls is setup to see all the frames so the user doesn't have to update it.
lEndFrame = int(iLine.partition("\t")[2])
lStartFrame = FBTime(0,0,0,0)
# -1 to compensate for the zero frame
lEndFrame = FBTime(0,0,0,lEndFrame-1)
FBPlayerControl().LoopStart = lStartFrame
FBPlayerControl().LoopStop = lEndFrame
FBPlayerControl().Goto(lStartFrame)
# Workaround for getting the last take to commit
curTake = FBSystem().CurrentTake
curTake.LocalTimeSpan = FBTimeSpan(lStartFrame, lEndFrame)
if iLine.startswith("Track"):
# lTrackIndexArray is tracking the line number that start with Track
lTrackIndexArray.append(lFile.index(iLine))
lTrackArray = []
# This basically take the two different data's you have and zips it into one array
lTrackArray = partition(lFile, lTrackIndexArray)
return lTrackArray
else:
FBMessageBox( "Error", "You did not select a file that ends with .anim, please try again!", "OK")
return None
def rs_SkelFile(fSkel = None):
lFilePopup = FBFilePopup();
lFilePopup.Filter = '*.skel'
lFilePopup.Style = FBFilePopupStyle.kFBFilePopupOpen
lFilePopup.Path = "{0}\\etc\\config\\anim\\skeletons".format( RS.Config.Tool.Path.Root )
gFileName = ""
if fSkel:
gFileName2 = lFilePopup.Path
gFileName3 = gFileName2 + "\\"
gFileName4 = gFileName3 + fSkel
lSkelFile = open(gFileName4, "r")
lSkelFile = lSkelFile.readlines()
return lSkelFile
else:
if lFilePopup.Execute():
gFileName = lFilePopup.FullFilename
lSkelFile = open(gFileName, "r")
lSkelFile = lSkelFile.readlines()
return lSkelFile
else:
return
def rs_AnimToFBX(lTrackArray, lSkelFile, lSource, lStartFrame = None):
#Only Needed for Character or Facial Animation
if lSource == "CHARACTER" or lSource == "FACIAL":
lApp = FBApplication()
lCurrentCharacter = lApp.CurrentCharacter
lNamespace = lCurrentCharacter.LongName.split(":")
if len(lNamespace) <= 1:
FBMessageBox( "Error", "You did not use the reference system to load your character.", "OK")
return
lNamespace = lCurrentCharacter.LongName.split(":")[0]
# go through each track line from the .anim.txt file
for i in range(len(lTrackArray)):
if i > 0:
lTrackID = None
lBoneID = None
lTrackID = lTrackArray[i][0].partition("track ")[2].partition("id")[0]
lBoneID = lTrackArray[i][0].partition("id ")[2].partition(" ")[0]
# Facial Animation No Skeleton File
if lSkelFile == None:
lBoneID = int(lBoneID)
lTrackID = int(lTrackID)
# For Props - track 5 - moverTranslation
if lTrackID == 5:
lModel = FBFindModelByLabelName("geo_Control")
if lModel:
lModel.Translation.SetAnimated(True)
lModelTrans = lModel.Translation.GetAnimationNode()
if lModelTrans:
# This goes through each of the key values, so each line Value in the .anim.txt file
for j in range(len(lTrackArray[i])):
if j > 0 and j != len(lTrackArray[i]) - 1:
if lTrackArray[i][j] != "":
lValueArray = lTrackArray[i][j].partition("\t")[2].split(" ")
# the export anim starts from 0 so we need to -1 here or we end up starting at 1
if not lValueArray[0].endswith('#IND00') and not lValueArray[1].endswith('#IND00') and not lValueArray[2].endswith('#IND00'):
if lValueArray[0] and lValueArray[1] and lValueArray[2]:
lModelTrans.Nodes[0].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[0]))
lModelTrans.Nodes[1].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[1]))
lModelTrans.Nodes[2].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[2]))
# For Props - track 6 - moverRotation
elif lTrackID == 6:
lModel = FBFindModelByLabelName("geo_Control")
if lModel:
lModel.Rotation.SetAnimated(True)
lModelRot = lModel.Rotation.GetAnimationNode()
if lModelRot:
# This goes through each of the key values, so each line Value in the .anim.txt file
for j in range(len(lTrackArray[i])):
if j > 0 and j != len(lTrackArray[i]) - 1:
if lTrackArray[i][j] != "":
lValueArray = lTrackArray[i][j].partition("\t")[2].split(" ")
# the export anim starts from 0 so we need to -1 here or we end up starting at 1
if lValueArray[0] and lValueArray[1] and lValueArray[2]:
lModelRot.Nodes[0].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[0]))
lModelRot.Nodes[1].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[1]))
lModelRot.Nodes[2].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[2]))
# For Face FX Rig - track 22
elif lTrackID == 22:
# Controller Names with their ID's are defined in a dictionary in glo
for lAmbientControllerName, lAmbientControllerID in RS.Globals.gAmbientControllerIds.items():
# Looking for the controller ID's that match the ones that are animation in the .anim files.
if lAmbientControllerID == lBoneID:
lModel = FBFindModelByLabelName(lNamespace + ":" + lAmbientControllerName)
if lModel:
lModel.Translation.SetAnimated(True)
lModelTrans = lModel.Translation.GetAnimationNode()
if lModelTrans:
# This goes through each of the key values, so each line Value in the .anim.txt file
for j in range(len(lTrackArray[i])):
if j > 0 and j != len(lTrackArray[i]) - 1:
if lTrackArray[i][j] != "":
# For Face FX, only the Y is animated, so we don't need to deal with x and z
lValueArray = lTrackArray[i][j].partition("\t")[2].split(" ")
# the export anim starts from 0 so we need to -1 here or we end up starting at 1
if lValueArray[0]:
if lStartFrame == None:
lModelTrans.Nodes[1].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[0]))
else:
lModelTrans.Nodes[1].KeyAdd(FBTime(0,0,0,(j-1)+lStartFrame), float(lValueArray[0]))
# For Face Ambient Rig - track 25 - facialTranslation
elif lTrackID == 25:
# Controller Names with their ID's are defined in a dictionary in glo
for lAmbientControllerName, lAmbientControllerID in RS.Globals.gAmbientControllerIds.items():
# Looking for the controller ID's that match the ones that are animation in the .anim files.
if lAmbientControllerID == lBoneID:
lModel = FBFindModelByLabelName(lNamespace + ":" + lAmbientControllerName)
if lModel:
lModel.Translation.SetAnimated(True)
lModelTrans = lModel.Translation.GetAnimationNode()
if lModelTrans:
# This goes through each of the key values, so each line Value in the .anim.txt file
for j in range(len(lTrackArray[i])):
if j > 0 and j != len(lTrackArray[i]) - 1:
if lTrackArray[i][j] != "":
lValueArray = lTrackArray[i][j].partition("\t")[2].split(" ")
# the export anim starts from 0 so we need to -1 here or we end up starting at 1
if lValueArray[0] and lValueArray[1] and lValueArray[2]:
if lStartFrame == None:
lModelTrans.Nodes[0].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[0]))
lModelTrans.Nodes[1].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[1]))
lModelTrans.Nodes[2].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[2]))
else:
lModelTrans.Nodes[0].KeyAdd(FBTime(0,0,0,(j-1)+lStartFrame), float(lValueArray[0]))
lModelTrans.Nodes[1].KeyAdd(FBTime(0,0,0,(j-1)+lStartFrame), float(lValueArray[1]))
lModelTrans.Nodes[2].KeyAdd(FBTime(0,0,0,(j-1)+lStartFrame), float(lValueArray[2]))
# For Face Ambient Rig - track 26 - facialRotation
elif lTrackID == 26:
# Controller Names with their ID's are defined in a dictionary in glo
for lAmbientControllerName, lAmbientControllerID in RS.Globals.gAmbientControllerIds.items():
# Looking for the controller ID's that match the ones that are animation in the .anim files.
if lAmbientControllerID == lBoneID:
lModel = FBFindModelByLabelName(lNamespace + ":" + lAmbientControllerName)
if lModel:
lModel.Rotation.SetAnimated(True)
lModelRot = lModel.Rotation.GetAnimationNode()
if lModelRot:
# This goes through each of the key values, so each line Value in the .anim.txt file
for j in range(len(lTrackArray[i])):
if j > 0 and j != len(lTrackArray[i]) - 1:
if lTrackArray[i][j] != "":
lValueArray = lTrackArray[i][j].partition("\t")[2].split(" ")
# the export anim starts from 0 so we need to -1 here or we end up starting at 1
if lValueArray[0] and lValueArray[1] and lValueArray[2]:
if lStartFrame == None:
lModelRot.Nodes[0].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[0]))
lModelRot.Nodes[1].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[1]))
lModelRot.Nodes[2].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[2]))
else:
lModelRot.Nodes[0].KeyAdd(FBTime(0,0,0,(j-1)+lStartFrame), float(lValueArray[0]))
lModelRot.Nodes[1].KeyAdd(FBTime(0,0,0,(j-1)+lStartFrame), float(lValueArray[1]))
lModelRot.Nodes[2].KeyAdd(FBTime(0,0,0,(j-1)+lStartFrame), float(lValueArray[2]))
# For functionality that requires the skeleton file
else:
if lSource == "CHARACTER":
for iLine in lSkelFile:
if (" " + lBoneID + "\n") in iLine:
lBoneName = lSkelFile[lSkelFile.index(iLine) - 1].replace("\t", "", len(lSkelFile[lSkelFile.index(iLine) - 1]))
lBoneName = lBoneName.split(" ")[1]
lModel = FBFindModelByLabelName(lNamespace + ":" + lBoneName)
if lModel:
if "boneRotation" in lTrackArray[i][0]:
if (gToolsRoot != 'X:\\gta5\\tools_ng' and gToolsRoot != 'X:\\gta5\\tools') and (lBoneName == "SKEL_L_UpperArm" or lBoneName == "SKEL_R_UpperArm"):
EnableRotationDOF(lCurrentCharacter, lBoneName, False)
lModel.Rotation.SetAnimated(True)
lModelRot = lModel.Rotation.GetAnimationNode()
if lModelRot:
for j in range(len(lTrackArray[i])):
if j > 0 and j != len(lTrackArray[i]) - 1:
if lTrackArray[i][j] != "":
lValueArray = lTrackArray[i][j].partition("\t")[2].split(" ")
# the export anim starts from 0 so we need to -1 here or we end up starting at 1
if not lValueArray[0].endswith('#IND00') and not lValueArray[1].endswith('#IND00') and not lValueArray[2].endswith('#IND00'):
lModelRot.Nodes[1].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[1]) )
lModelRot.Nodes[0].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[0]) )
lModelRot.Nodes[2].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[2]) )
if "boneTranslation" in lTrackArray[i][0] :
lModel.Rotation.SetAnimated(True)
lModelTrans = lModel.Translation.GetAnimationNode()
if lModelTrans:
for j in range(len(lTrackArray[i])):
if j > 0 and j != len(lTrackArray[i]) - 1:
if lTrackArray[i][j] != "":
lValueArray = lTrackArray[i][j].partition("\t")[2].split(" ")
# the export anim starts from 0 so we need to -1 here or we end up starting at 1
lModelTrans.Nodes[0].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[0]))
lModelTrans.Nodes[1].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[1]))
lModelTrans.Nodes[2].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[2]))
elif lSource == "POSE":
# Only animation on frame 0.
for iLine in lSkelFile:
if (" " + lBoneID + "\n") in iLine:
lBoneName = lSkelFile[lSkelFile.index(iLine) - 1].replace("\t", "", len(lSkelFile[lSkelFile.index(iLine) - 1]))
lBoneName = lBoneName.split(" ")[1]
lModel = FBFindModelByLabelName("TEMPORARY:" + lBoneName)
if lModel:
if "boneRotation" in lTrackArray[i][0]:
lModel.Rotation.SetAnimated(True)
lModelRot = lModel.Rotation.GetAnimationNode()
if lModelRot:
if lTrackArray[i][1] != "":
lValueArray = lTrackArray[i][1].partition("\t")[2].split(" ")
# the export anim starts from 0 so we need to -1 here or we end up starting at 1
lModelRot.Nodes[0].KeyAdd(FBTime(0,0,0,0), float(lValueArray[0]))
lModelRot.Nodes[1].KeyAdd(FBTime(0,0,0,0), float(lValueArray[1]))
lModelRot.Nodes[2].KeyAdd(FBTime(0,0,0,0), float(lValueArray[2]))
if "boneTranslation" in lTrackArray[i][0] :
lModelTrans = lModel.Translation.GetAnimationNode()
if lModelTrans:
if lTrackArray[i][1] != "":
lValueArray = lTrackArray[i][1].partition("\t")[2].split(" ")
# the export anim starts from 0 so we need to -1 here or we end up starting at 1
lModelTrans.Nodes[0].KeyAdd(FBTime(0,0,0,0), float(lValueArray[0]))
lModelTrans.Nodes[1].KeyAdd(FBTime(0,0,0,0), float(lValueArray[1]))
lModelTrans.Nodes[2].KeyAdd(FBTime(0,0,0,0), float(lValueArray[2]))
if lBoneID != "" and int(lBoneID) == 0:
if "moverTranslation" in lTrackArray[i][0]:
lModel = FBFindModelByLabelName("TEMPORARY:mover")
if lModel:
lModelTrans = lModel.Translation.GetAnimationNode()
if lModelTrans:
if lTrackArray[i][1] != "":
lValueArray = lTrackArray[i][1].partition("\t")[2].split(" ")
lModelTrans.Nodes[0].KeyAdd(FBTime(0,0,0,0), float(lValueArray[0]))
lModelTrans.Nodes[1].KeyAdd(FBTime(0,0,0,0), float(lValueArray[1]))
lModelTrans.Nodes[2].KeyAdd(FBTime(0,0,0,0), float(lValueArray[2]))
if "moverRotation" in lTrackArray[i][0]:
lModel = FBFindModelByLabelName("TEMPORARY:mover")
if lModel:
lModelRot = lModel.Rotation.GetAnimationNode()
if lModelRot:
if lTrackArray[i][1] != "":
lValueArray = lTrackArray[i][1].partition("\t")[2].split(" ")
lModelRot.Nodes[0].KeyAdd(FBTime(0,0,0,0), float(lValueArray[0]))
lModelRot.Nodes[1].KeyAdd(FBTime(0,0,0,0), float(lValueArray[1]))
lModelRot.Nodes[2].KeyAdd(FBTime(0,0,0,0), float(lValueArray[2]))
lBoneName = lTrackArray[i][0].rpartition(":")[2].replace("\n", "", len(lTrackArray[i][0].rpartition(":")[2]))
lModel = FBFindModelByLabelName("TEMPORARY:" + lBoneName)
if lModel:
if "boneRotation" in lTrackArray[i][0]:
lModelRot = lModel.Rotation.GetAnimationNode()
if lModelRot:
if lTrackArray[i][1] != "":
lValueArray = lTrackArray[i][1].partition("\t")[2].split(" ")
lModelRot.Nodes[0].KeyAdd(FBTime(0,0,0,1), float(lValueArray[0]))
lModelRot.Nodes[1].KeyAdd(FBTime(0,0,0,1), float(lValueArray[1]))
lModelRot.Nodes[2].KeyAdd(FBTime(0,0,0,1), float(lValueArray[2]))
if "boneTranslation" in lTrackArray[i][0] :
lModelTrans = lModel.Translation.GetAnimationNode()
if lModelTrans:
if lTrackArray[i][1] != "":
lValueArray = lTrackArray[i][1].partition("\t")[2].split(" ")
lModelTrans.Nodes[0].KeyAdd(FBTime(0,0,0,0), float(lValueArray[0]))
lModelTrans.Nodes[1].KeyAdd(FBTime(0,0,0,0), float(lValueArray[1]))
lModelTrans.Nodes[2].KeyAdd(FBTime(0,0,0,0), float(lValueArray[2]))
###################################################################################################
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
##
## Description: Globals
##
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
###################################################################################################
if lSource != "POSE" and lSource != "PROP":
if lBoneID != "" and int(lBoneID) == 0:
lBoneName = lTrackArray[i][0].rpartition(":")[2].replace("\n", "", len(lTrackArray[i][0].rpartition(":")[2]))
lModel = FBFindModelByLabelName(lNamespace + ":" + lBoneName)
if lModel:
if "boneRotation" in lTrackArray[i][0]:
lModelRot = lModel.Rotation.GetAnimationNode()
if lModelRot:
for j in range(len(lTrackArray[i])):
if j > 0 and j != len(lTrackArray[i]) - 1:
if lTrackArray[i][j] != "":
lValueArray = lTrackArray[i][j].partition("\t")[2].split(" ")
# the export anim starts from 0 so we need to -1 here or we end up starting at 1
lModelRot.Nodes[0].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[0]))
lModelRot.Nodes[1].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[1]))
lModelRot.Nodes[2].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[2]))
if "boneTranslation" in lTrackArray[i][0] :
lModelTrans = lModel.Translation.GetAnimationNode()
if lModelTrans:
for j in range(len(lTrackArray[i])):
if j > 0 and j != len(lTrackArray[i]) - 1:
if lTrackArray[i][j] != "":
lValueArray = lTrackArray[i][j].partition("\t")[2].split(" ")
# the export anim starts from 0 so we need to -1 here or we end up starting at 1
lModelTrans.Nodes[0].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[0]))
lModelTrans.Nodes[1].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[1]))
lModelTrans.Nodes[2].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[2]))
if "moverTranslation" in lTrackArray[i][0]:
lModel = FBFindModelByLabelName(lNamespace + ":mover")
if lModel:
lModelTrans = lModel.Translation.GetAnimationNode()
if lModelTrans:
for j in range(len(lTrackArray[i])):
if j > 0 and j != len(lTrackArray[i]) - 1:
if lTrackArray[i][j] != "":
lValueArray = lTrackArray[i][j].partition("\t")[2].split(" ")
# the export anim starts from 0 so we need to -1 here or we end up starting at 1
lModelTrans.Nodes[0].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[0]))
lModelTrans.Nodes[1].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[1]))
lModelTrans.Nodes[2].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[2]))
if "moverRotation" in lTrackArray[i][0]:
lModel = FBFindModelByLabelName(lNamespace + ":mover")
if lModel:
lModelRot = lModel.Rotation.GetAnimationNode()
if lModelRot:
for j in range(len(lTrackArray[i])):
if j > 0 and j != len(lTrackArray[i]) - 1:
if lTrackArray[i][j] != "":
lValueArray = lTrackArray[i][j].partition("\t")[2].split(" ")
if lValueArray[0] != "":
# the export anim starts from 0 so we need to -1 here or we end up starting at 1
lModelRot.Nodes[0].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[0]))
lModelRot.Nodes[1].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[1]))
lModelRot.Nodes[2].KeyAdd(FBTime(0,0,0,j-1), float(lValueArray[2]))
def rs_SelectFile(source = None):
lFilePopup = FBFilePopup();
lFilePopup.Filter = '*.anim'
lFilePopup.Style = FBFilePopupStyle.kFBFilePopupOpen
#dlcList = _Config.AllProjects()
#for dlc in dlcList.Values:
if source == "PROPS":
lFilePopup.Path = gProjRoot + "\\assets\\cuts"
elif source == "POSE":
lFilePopup.Path = gProjRoot + "\\art\\anim\\export_mb"
elif source == "FACIAL":
lFilePopup.Path = gProjRoot + "\\audio\\dev_ng\\assets\\LipsyncAnims"
elif source == "CAMERA":
lFilePopup.Path = gProjRoot + "\\art\\anim\\export_mb"
else:
lFilePopup.Path = gProjRoot + "\\art\\anim\\export_mb"
#if (lbSelItem):
#dlcList = _Config.AllProjects()
#for dlc in dlcList.Values:
#if lbSelItem == dlc.get_Name():
#if (lbSelItem == "gta5" and gToolsRoot == 'X:\\gta5\\tools_ng'):
#lFilePopup.Path = str(dlc.get_Root()) + '\\art\\ng\\anim\\export_mb'
#break
#elif (lbSelItem == "gta5"):
#lFilePopup.Path = str(dlc.get_Root()) + '\\art\\anim\\export_mb'
#break
#else:
#lFilePopup.Path = str(dlc.get_Root()) + '\\assets\\anim\\ingame'
#break
#else:
#lFilePopup.Path = gProjRoot + "\\art\\anim\\export_mb"
#else:
#lFilePopup.Path = gProjRoot + "\\art\\anim\\export_mb"
lFileName = ""
if os.path.exists(lFilePopup.Path):
pass
else:
lWarning = (lFilePopup.Path + " project path does not exist")
FBMessageBox("Sorry, ", lWarning, "OK" )
if lFilePopup.Execute():
lFileName = lFilePopup.FullFilename
return lFileName
else:
return
def rs_SelectFolder(lbSelItem = None):
lFolderPopup = FBFolderPopup()
lFolderPopup.Caption = "Select Anim Folder"
if (lbSelItem):
## folder logic here
#print lbSelItem
#FlushOutput()
#lFolderPopup.Path = gProjRoot + "\\art\\anim\\export_mb"
#else:
#lFolderPopup.Path = gProjRoot + "\\art\\anim\\export_mb"
dlcList = _Config.AllProjects()
for dlc in dlcList.Values:
if lbSelItem == dlc.get_Name():
if (lbSelItem == "gta5" and gToolsRoot == 'X:\\gta5\\tools_ng'):
lFolderPopup.Path = str(dlc.get_Root()) + '\\art\\ng\\anim\\export_mb'
break
elif (lbSelItem == "gta5"):
lFolderPopup.Path = str(dlc.get_Root()) + '\\art\\anim\\export_mb'
break
else:
lFolderPopup.Path = str(dlc.get_Root()) + '\\assets\\anim\\ingame'
break
else:
lFolderPopup.Path = gProjRoot + "\\art\\anim\\export_mb"
else:
lFolderPopup.Path = gProjRoot + "\\art\\anim\\export_mb"
lResult = lFolderPopup.Execute()
lPath = ""
if lResult:
lPath = lFolderPopup.Path
return lPath
else:
return
def rs_SelectFolder(lbSelItem = None):
lFolderPopup = FBFolderPopup()
lFolderPopup.Caption = "Select Anim Folder"
if (lbSelItem):
dlcList = _Config.AllProjects()
for dlc in dlcList.Values:
if lbSelItem == dlc.get_Name():
if (lbSelItem == "gta5" and gToolsRoot == 'X:\\gta5\\tools_ng'):
lFolderPopup.Path = str(dlc.get_Root()) + '\\art\\ng\\anim\\export_mb'
break
elif (lbSelItem == "gta5"):
lFolderPopup.Path = str(dlc.get_Root()) + '\\art\\anim\\export_mb'
break
else:
lFolderPopup.Path = str(dlc.get_Root()) + '\\assets\\anim\\ingame'
break
else:
lFolderPopup.Path = gProjRoot + "\\art\\anim\\export_mb"
else:
lFolderPopup.Path = gProjRoot + "\\art\\anim\\export_mb"
lResult = lFolderPopup.Execute()
lPath = ""
if lResult:
lPath = lFolderPopup.Path
return lPath
else:
return
def rs_LoadFile(lFileName, skelFile = None, sync = False, useTake = False):
### SYNC ###
if sync:
success = depotFileData.syncSelectedFile(lFileName)
else:
# check if we have the file locally
fName = lFileName.replace("%40", "@")
if not os.path.isfile(str(fName)):
FBMessageBox("Warning", "{0} \n was not found on local drive. Try syncing to perforce depot".format(fName), "OK")
return
#Needed for Character Animation
lApp = FBApplication()
lCurrentCharacter = lApp.CurrentCharacter
if lCurrentCharacter:
lNamespace = lCurrentCharacter.LongName.split(":")[0]
lMover = FBFindModelByLabelName(lNamespace + ":mover")
for iCharacter in RS.Globals.gCharacters:
iCharacter.Active = False
if lMover:
lMover.PropertyList.Find("RotationActive").Data = False
lMover.PropertyList.Find("TranslationActive").Data = False
lMover.PropertyList.Find("TranslationActive").Data = False
lMover.PropertyList.Find("Enable Translation DOF").Data = False
for iConstraint in RS.Globals.gConstraints:
if iConstraint.Name == "mover_toybox_Control":
iConstraint.Active = False
if lFileName:
lFileName = str(lFileName)
fName = lFileName.replace('%40','@')
# use current take instead of a copy if checkbox is checked
if useTake:
#Throw a Messagebox warning to make sure this is what is desired
result = FBMessageBox("WARNING WARNING WARNING!!!!!!!!!!!!!!!!!!", "This will overwrite an existing anim on the Current Character. Are you sure you want to do this?", "Yes, Current Take", "No, New Take")
if result == 1:
lTake = FBSystem().CurrentTake
else:
lTake = FBSystem().CurrentTake.CopyTake(os.path.basename(fName.rpartition(".")[0]))
else:
lTake = FBSystem().CurrentTake.CopyTake(os.path.basename(fName.rpartition(".")[0]))
# The above line copies the animation data too, so if if the keys your adding is not as long as the copied take you have them behind, which is bad.
lTake.ClearAllProperties (False)
lSource = "CHARACTER"
lFileArray = rs_TrackArray(fName,lSource)
if lFileArray != None:
lSkelFile = rs_SkelFile(skelFile)
if lSkelFile != None:
rs_AnimToFBX(lFileArray, lSkelFile, lSource)
lPlayerControl = FBPlayerControl()
lPlayerControl.SnapMode = FBTransportSnapMode.kFBTransportSnapModeSnapAndPlayOnFrames
lPlayerControl.SetTransportFps(FBTimeMode.kFBTimeMode30Frames)
## Verify if Gimble Killer Filter needs to be run.
#if pControl.TextureData == 1:
## Apply Gimbal Killer filter
#lFilterManager = FBFilterManager()
#lGimbalKillerFilter = lFilterManager.CreateFilter('Gimbal Killer')
#if lGimbalKillerFilter:
#lMover.Selected = True
#lGimbalKillerFilter.Apply (lMover.Rotation.GetAnimationNode(), True)
#lGimbalKillerFilter.FBDelete()
#FBSystem().Scene.Evaluate()
#else:
#FBMessageBox( "Error", "No Character is selected in the scene. Please select one in the Character Controls, and try again!", "OK")
if (gToolsRoot != 'X:\\gta5\\tools_ng' and gToolsRoot != 'X:\\gta5\\tools' and lCurrentCharacter):
#Plot(lCurrentCharacter, "mover")
Plot(lCurrentCharacter, "rig")
EnableRotationDOF(lCurrentCharacter,"SKEL_L_UpperArm")
EnableRotationDOF(lCurrentCharacter,"SKEL_R_UpperArm")
Plot(lCurrentCharacter, "skeleton")
DeleteControlRig(lCurrentCharacter)
return lCurrentCharacter
def rs_LoadFolder(lFolderName, skelFile = None, sync = False):
#Needed for Character Animation
lApp = FBApplication()
lCurrentCharacter = lApp.CurrentCharacter
if lCurrentCharacter:
lNamespace = lCurrentCharacter.LongName.split(":")[0]
lMover = FBFindModelByLabelName(lNamespace + ":mover")
for iCharacter in RS.Globals.gCharacters:
iCharacter.Active = False
if lMover:
lMover.PropertyList.Find("RotationActive").Data = False
lMover.PropertyList.Find("Enable Rotation DOF").Data = False
lMover.PropertyList.Find("TranslationActive").Data = False
lMover.PropertyList.Find("Enable Translation DOF").Data = False
for iConstraint in RS.Globals.gConstraints:
if iConstraint.Name == "mover_toybox_Control":
iConstraint.Active = False
if lFolderName: #Check to ensure a file name was selected and not cancelled
lFolderName = str(lFolderName)
fName = lFolderName.replace('%40','@')
### SYNC HERE ### ### SYNC ###
if sync:
success = depotFileData.syncSelectedFile(fName)
lFiles = RS.Utils.Path.Walk(fName, pRecurse = 0, pPattern = '*.anim', pReturn_folders = 0 )
lSkelFile = rs_SkelFile(skelFile)
if lSkelFile != None:
for iFile in lFiles:
lFileArray = []
lSource = "CHARACTER"
lTake = FBSystem().CurrentTake.CopyTake(os.path.basename(iFile.rpartition(".")[0]))
# The above line copies the animation data too, so if if the keys your adding is not as long as the copied take you have them behind, which is bad.
lTake.ClearAllProperties (False)
lFileArray = rs_TrackArray(iFile, lSource)
if lFileArray != None:
rs_AnimToFBX(lFileArray, lSkelFile, lSource)
##Commented out for now until pControl is fixed here
## Verify if Gimble Killer Filter needs to be run.
#if pControl.TextureData == 1:
## Apply Gimbal Killer filter
#lFilterManager = FBFilterManager()
#lGimbalKillerFilter = lFilterManager.CreateFilter('Gimbal Killer')
#if lGimbalKillerFilter:
#lMover.Selected = True
#lGimbalKillerFilter.Apply (lMover.Rotation.GetAnimationNode(), True)
#lGimbalKillerFilter.FBDelete()
#FBSystem().Scene.Evaluate()
#lMover.Selected = False
lPlayerControl = FBPlayerControl()
lPlayerControl.SnapMode = FBTransportSnapMode.kFBTransportSnapModeSnapAndPlayOnFrames
lPlayerControl.SetTransportFps(FBTimeMode.kFBTimeMode30Frames)
else:
FBMessageBox( "Error", "No Character is selected in the scene. Please select one in the Character Controls, and try again!", "OK")
def DeleteControlRig(character):
# Delete Control Rig
lCtrlSet = character.GetCurrentControlSet()
lCtrlSet.FBDelete()
def Plot(character, plotWhere):
if plotWhere == 'skeleton':
plotWhere = FBCharacterPlotWhere.kFBCharacterPlotOnSkeleton
elif plotWhere == 'rig':
plotWhere = FBCharacterPlotWhere.kFBCharacterPlotOnControlRig
# Create a control rig using Forward and Inverse Kinematics,
# as specified by the "True" parameter.
character.CreateControlRig(True)
# Set the control rig to active.
character.ActiveInput = True
#elif plotWhere
else:
print "Warning: The plotWhere variable in the plot() function wasn't given a valid value. Plotting to skeleton by default."
plotWhere = FBCharacterPlotWhere.kFBCharacterPlotOnSkeleton
plotOptions = FBPlotOptions()
plotOptions.PlotAllTakes = False
plotOptions.PlotOnFrame = True
plotOptions.PlotPeriod = FBTime(0, 0, 0, 1)
plotOptions.RotationFilterToApply = FBRotationFilter.kFBRotationFilterGimbleKiller
plotOptions.UseConstantKeyReducer = True
plotOptions.ConstantKeyReducerKeepOneKey = True
plotOptions.PlotTranslationOnRootOnly = True
character.PlotAnimation(plotWhere, plotOptions)
return True
def EnableRotationDOF(character, boneName, setting = True):
lNamespace = character.LongName.split(":")[0]
lBone = FBFindModelByLabelName(lNamespace + ":" + boneName)
lBone.PropertyList.Find("RotationActive").Data = setting
def rs_LoadFolderAnimsBatch(lResourcePathList):
#Needed for Character Animation
lApp = FBApplication()
lCurrentCharacter = lApp.CurrentCharacter
if lCurrentCharacter:
lNamespace = lCurrentCharacter.LongName.split(":")[0]
lMover = FBFindModelByLabelName(lNamespace + ":mover")
for iCharacter in RS.Globals.gCharacters:
iCharacter.Active = False
if lMover:
lMover.PropertyList.Find("RotationActive").Data = False
lMover.PropertyList.Find("Enable Rotation DOF").Data = False
lMover.PropertyList.Find("TranslationActive").Data = False
lMover.PropertyList.Find("Enable Translation DOF").Data = False
for iConstraint in RS.Globals.gConstraints:
if iConstraint.Name == "mover_toybox_Control":
iConstraint.Active = False
lSkelFile = rs_SkelFile()
if lSkelFile != None:
for iFile in lResourcePathList:
lFileArray = []
lSource = "CHARACTER"
lTake = FBSystem().CurrentTake.CopyTake(os.path.basename(iFile.rpartition(".")[0]))
# The above line copies the animation data too, so if if the keys your adding is not as long as the copied take you have them behind, which is bad.
lTake.ClearAllProperties (False)
lFileArray = rs_TrackArray(iFile, lSource)
if lFileArray != None:
rs_AnimToFBX(lFileArray, lSkelFile, lSource)
lPlayerControl = FBPlayerControl()
lPlayerControl.SnapMode = FBTransportSnapMode.kFBTransportSnapModeSnapAndPlayOnFrames
lPlayerControl.SetTransportFps(FBTimeMode.kFBTimeMode30Frames)
else:
FBMessageBox( "Error", "No Character is selected in the scene. Please select one in the Character Controls, and try again!", "OK")
def rs_LoadFacialAnim():
#Needed for Character Animation
lApp = FBApplication()
lCurrentCharacter = lApp.CurrentCharacter
if lCurrentCharacter:
lNamespace = lCurrentCharacter.LongName.split(":")
if len(lNamespace) <= 1:
FBMessageBox( "Error", "You did not use the reference system to load your character.", "OK")
return
lNamespace = lCurrentCharacter.LongName.split(":")[0]
lMover = FBFindModelByLabelName(lNamespace + ":mover")
if lMover:
lMover.PropertyList.Find("RotationActive").Data = False
lMover.PropertyList.Find("Enable Rotation DOF").Data = False
lMover.PropertyList.Find("TranslationActive").Data = False
lMover.PropertyList.Find("Enable Translation DOF").Data = False
for iConstraint in RS.Globals.gConstraints:
if iConstraint.Name == "mover_toybox_Control":
iConstraint.Active = False
lFileName = rs_SelectFile("FACIAL")
if lFileName: #Check to ensure a file name was selected and not cancelled
lFileArray = []
lSkelFile = None
lSource = "FACIAL"
lTake = FBSystem().CurrentTake.CopyTake(os.path.basename(lFileName.rpartition(".")[0]))
# The above line copies the animation data too, so if if the keys your adding is not as long as the copied take you have them behind, which is bad.
lTake.ClearAllProperties (False)
lFileArray, lStartFrame = rs_TrackArray(lFileName, lSource)
if lFileArray != None:
if lStartFrame != None:
rs_AnimToFBX(lFileArray, lSkelFile, lSource, lStartFrame)
else:
rs_AnimToFBX(lFileArray, lSkelFile, lSource)
lPlayerControl = FBPlayerControl()
lPlayerControl.SnapMode = FBTransportSnapMode.kFBTransportSnapModeSnapAndPlayOnFrames
lPlayerControl.SetTransportFps(FBTimeMode.kFBTimeMode30Frames)
else:
FBMessageBox( "Error", "No Character is selected in the scene. Please select one in the Character Controls, and try again!", "OK")
def rs_LoadFacialFolderAnims():
#Needed for Character Animation
lApp = FBApplication()
lCurrentCharacter = lApp.CurrentCharacter
if lCurrentCharacter:
lNamespace = lCurrentCharacter.LongName.split(":")
if len(lNamespace) <= 1:
FBMessageBox( "Error", "You did not use the reference system to load your character.", "OK")
return
lNamespace = lCurrentCharacter.LongName.split(":")[0]
lMover = FBFindModelByLabelName(lNamespace + ":mover")
if lMover:
lMover.PropertyList.Find("RotationActive").Data = False
lMover.PropertyList.Find("Enable Rotation DOF").Data = False
lMover.PropertyList.Find("TranslationActive").Data = False
lMover.PropertyList.Find("Enable Translation DOF").Data = False
for iConstraint in RS.Globals.gConstraints:
if iConstraint.Name == "mover_toybox_Control":
iConstraint.Active = False
lFolderName = rs_SelectFolder()
if lFolderName: #Check to ensure a file name was selected and not cancelled
lFiles = RS.Utils.Path.Walk(lFolderName, pRecurse = 0, pPattern = '*.anim', pReturn_folders = 0 )
lSkelFile = None
for iFile in lFiles:
lFileArray = []
lSkelFile = None
lSource = "FACIAL"
lTake = FBSystem().CurrentTake.CopyTake(os.path.basename(iFile.rpartition(".")[0]))
# The above line copies the animation data too, so if if the keys your adding is not as long as the copied take you have them behind, which is bad.
lTake.ClearAllProperties (False)
lFileArray, lStartFrame = rs_TrackArray(iFile, lSource)
if lFileArray != None:
if lStartFrame != None:
rs_AnimToFBX(lFileArray, lSkelFile, lSource, lStartFrame)
else:
rs_AnimToFBX(lFileArray, lSkelFile, lSource)
lPlayerControl = FBPlayerControl()
lPlayerControl.SnapMode = FBTransportSnapMode.kFBTransportSnapModeSnapAndPlayOnFrames
lPlayerControl.SetTransportFps(FBTimeMode.kFBTimeMode30Frames)
else:
FBMessageBox( "Error", "No Character is selected in the scene. Please select one in the Character Controls, and try again!", "OK")
def rs_LoadPropAnim():
lFileName = rs_SelectFile("PROP")
if lFileName: #Check to ensure a file name was selected and not cancelled
lFileArray = []
lSkelFile = None
lSource = "PROP"
lTake = FBSystem().CurrentTake.CopyTake(os.path.basename(lFileName.rpartition(".")[0]))
# The above line copies the animation data too, so if if the keys your adding is not as long as the copied take you have them behind, which is bad.
lTake.ClearAllProperties (False)
lFileArray = rs_TrackArray(lFileName, lSource)
if lFileArray != None:
rs_AnimToFBX(lFileArray, lSkelFile, lSource)
lPlayerControl = FBPlayerControl()
lPlayerControl.TransportTimeFormat = FBTransportTimeFormat.kFBTimeFormatFrame
lPlayerControl.SnapMode = FBTransportSnapMode.kFBTransportSnapModeSnapAndPlayOnFrames
lPlayerControl.SetTransportFps(FBTimeMode.kFBTimeMode30Frames)
def rs_LoadPropFolderAnims():
lFolderName = rs_SelectFolder()
if lFolderName: #Check to ensure a file name was selected and not cancelled
lFiles = RS.Utils.Path.Walk(lFolderName, pRecurse = 0, pPattern = '*.anim', pReturn_folders = 0 )
lSkelFile = None
for iFile in lFiles:
lFileArray = []
lSkelFile = None
lSource = "PROP"
lTake = FBSystem().CurrentTake.CopyTake(os.path.basename(iFile.rpartition(".")[0]))
# The above line copies the animation data too, so if if the keys your adding is not as long as the copied take you have them behind, which is bad.
lTake.ClearAllProperties (False)
lFileArray = rs_TrackArray(iFile, lSource)
if lFileArray != None:
rs_AnimToFBX(lFileArray, lSkelFile, lSource)
lPlayerControl = FBPlayerControl()
lPlayerControl.SnapMode = FBTransportSnapMode.kFBTransportSnapModeSnapAndPlayOnFrames
lPlayerControl.SetTransportFps(FBTimeMode.kFBTimeMode30Frames)
def rs_LoadCameraFileAnim():
#Get file user wants to open
lFileName = rs_SelectFile("CAMERA")
if lFileName == None:
return
#Copy take for new camera data. Use camera .anim name
lTake = FBSystem().CurrentTake.CopyTake(os.path.basename(lFileName.rpartition(".")[0]))
# The above line copies the animation data too, so if if the keys your adding is not as long as the copied take you have them behind, which is bad.
lTake.ClearAllProperties (False)
#Read in anim file into a new rs_AnimFile class. We use quaternion for rotations.
lAnimFile = RS.Utils.AnimFile.rs_AnimFile(lFileName, RS.Utils.AnimFile.rs_AnimFile.kQuaterion )
#Check we have everything we need to import camera data
if not lAnimFile.TrackExists_TypeString( "cameraTranslation" ) or not lAnimFile.TrackExists_TypeString( "cameraRotation" ) or not lAnimFile.TrackExists_TypeString( "cameraFOV" ):
#We have failed to read in camera data so let the user know and break
return
#Else we continue and start keying a new camera and setting relevant properties
#to be animatable
lCamera = FBCamera('ImportedCamera')
lCamera.Show = True
lCamera.Translation.SetAnimated( True )
lCamera.Rotation.SetAnimated( True )
lCamera.FieldOfView.SetAnimated( True )
#Translation
lCameraTranslationTrack = lAnimFile.GetTrack_TypeString( "cameraTranslation" )
lCameraTranslation = lCamera.Translation.GetAnimationNode()
if lCameraTranslation:
lKeyTimeIterator = 0
for lTrackValue in lCameraTranslationTrack.mTrackValues :
lKeyTime = FBTime( 0, 0, 0, lKeyTimeIterator )
#We swap the Y and Z, scale all values by 100 and then inverse the Z value.
#Not sure why we do this but the export does so we must reverse it.
lCameraTranslation.Nodes[0].KeyAdd( lKeyTime, lTrackValue[0] * 100 )
lCameraTranslation.Nodes[1].KeyAdd( lKeyTime, lTrackValue[2] * 100)
lCameraTranslation.Nodes[2].KeyAdd( lKeyTime, lTrackValue[1] * -100)
lKeyTimeIterator += 1
#Rotation - Using Quaternions
lCameraRotationTrack = lAnimFile.GetTrack_TypeString( "cameraRotation" )
lCameraRotation = lCamera.Rotation.GetAnimationNode()
if lCameraRotation:
lKeyTimeIterator = 0
for lTrackValue in lCameraRotationTrack.mTrackValues :
lKeyTime = FBTime( 0, 0, 0, lKeyTimeIterator )
lKeyEuler = FBVector3d()
#Alot of the below code is odd but reverses what the
#exporter does to transform MB camera data into game
#data. The order which this happens is critical
#Swizzle and negate some components of the input quaternion
lKeyQuat = FBVector4d( -lTrackValue[0], lTrackValue[2], lTrackValue[1], lTrackValue[3] )
#Get the input matrix from this
lInputMatrix = FBMatrix()
rs_FBQuaternionToFBMatrix( lKeyQuat, lInputMatrix )
#Create first adjustment matrix (unwind about the Y 180)
lAdjustmentMatrixA = FBMatrix()
FBRotationToMatrix( lAdjustmentMatrixA, FBVector3d( 0, -180, 0 ) )
#Multiple these matrices together to an intermediate matrix
lIntermediateMatrix = lInputMatrix
FBMatrixMult( lIntermediateMatrix, lAdjustmentMatrixA , lInputMatrix)
#Create first adjustment matrix (unwind by a further 90 in the Y axis)
#I don't know why we have to do this - there is nothing in the export
#code I could see which would require this.
lAdjustmentMatrixB = FBMatrix()
FBRotationToMatrix( lAdjustmentMatrixB, FBVector3d( 0, -90, 0 ) )
#Multiple these matrices together to get the final rotation matrix
lFinalMatrix = FBMatrix()
FBMatrixMult( lFinalMatrix, lIntermediateMatrix, lAdjustmentMatrixB)
#Set the matrix and update scene
lCamera.SetMatrix( lFinalMatrix )
FBSystem().Scene.Evaluate()
#Key the new rotation values. We will let the translation data be discarded here as
#we have already keyed this correctly earlier.
lCameraRotation.Nodes[0].KeyAdd( lKeyTime, lCamera.Rotation.Data[0] )
lCameraRotation.Nodes[1].KeyAdd( lKeyTime, lCamera.Rotation.Data[1] )
lCameraRotation.Nodes[2].KeyAdd( lKeyTime, lCamera.Rotation.Data[2] )
lKeyTimeIterator += 1
#FOV
lCameraFOVTrack = lAnimFile.GetTrack_TypeString( "cameraFOV" )
lCameraFOV = lCamera.FieldOfView.GetAnimationNode()
if lCameraFOV:
lKeyTimeIterator = 0
for lTrackValue in lCameraFOVTrack.mTrackValues :
lKeyTime = FBTime( 0, 0, 0, lKeyTimeIterator )
lCameraFOV.KeyAdd( lKeyTime, lTrackValue[0] )
lKeyTimeIterator += 1
def rs_FBQuaternionToFBMatrix(pInputFBQuaternion, pOutputFBMatrix):
pOutputFBMatrix.Identity()
RandomNumber = 1.4142135623730950488016887242097
tx = RandomNumber * pInputFBQuaternion[0]
ty = RandomNumber * pInputFBQuaternion[1]
tz = RandomNumber * pInputFBQuaternion[2]
tw = RandomNumber * pInputFBQuaternion[3]
# A - [ 0][ 1][ 2][ 3]
# B - [ 4][ 5][ 6][ 7]
# C - [ 8][ 9][10][11]
# D - [12][13][14][15]
#a.y
pOutputFBMatrix[1] = tx*ty + tz*tw;
#b.x
pOutputFBMatrix[4] = tx*ty - tz*tw;
#a.z
pOutputFBMatrix[2] = tx*tz - ty*tw;
#c.x
pOutputFBMatrix[8] = tx*tz + ty*tw;
#b.z
pOutputFBMatrix[6] = ty*tz + tx*tw;
#c.y
pOutputFBMatrix[9] = ty*tz - tx*tw;
ty *= ty; # need squares along diagonal
tz *= tz;
tx *= tx;
#a.x
pOutputFBMatrix[0] = 1.0 - (ty + tz)
#b.y
pOutputFBMatrix[5] = 1.0 - (tz + tx)
#c.z
pOutputFBMatrix[10] = 1.0 - (ty + tx)
###############################################################################################################
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
##
## Description: Delete the TEMPORARY skeleton from the file
##
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
###############################################################################################################
def DestroyModel(Model):
for child in Model.Children:
if len (child.Children) < 1:
child.FBDelete()
else:
DestroyModel(child)
def rs_DeleteTempSkel():
lDeleteArray = []
# Delete all the relation constraints associated with the old bones.
for iConstraint in FBSystem().Scene.Constraints:
if iConstraint.LongName.startswith("TEMPORARY:"):
lDeleteArray.append(iConstraint)
for iDeleteConstraint in lDeleteArray:
try:
iDeleteConstraint.FBDelete()
except:
pass
# Iterate thru the list, and delete each one of them...
lDummy01 = FBFindModelByLabelName("TEMPORARY:Dummy01")
if lDummy01:
for i in range(23):
DestroyModel(lDummy01)
lDummy01.FBDelete()
# 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 RS.Globals.gFolders:
if len(lFolder.Items) == 0:
lFolderList.append(lFolder)
map( FBComponent.FBDelete, lFolderList )
# 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("TEMPORARY", True)
# Deleting all the remaining components in the scene
lList = []
for lComp in FBSystem().Scene.Components:
if lComp != None and lComp.Selected:
# 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 TEMPORARY namespace
cl = RS.Utils.Scene.FindObjectsByNamespace("TEMPORARY")
for item in cl:
item.ProcessObjectNamespace(FBNamespaceAction.kFBRemoveAllNamespace, "TEMPORARY")
###############################################################################################################
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
##
## Description: Create a pose from the first frame an .Anim File. This will allow us to quickly create a pose
## straight from the exported assets, rather than the time consuming way of going to the source fbx.
##
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
###############################################################################################################
def rs_PoseFileAnim(pControl):
# Select Anim File For Character
lFileName = rs_SelectFile("POSE")
if lFileName: #Check to ensure a file name was selected and not cancelled
lSource = "POSE"
lFileArray = rs_TrackArray(lFileName,lSource)
if lFileArray != None: # Double Checks Selection was not cancelled.
if pControl.Name == "Male":
gFileName = "{0}\\etc\\config\\anim\\skeletons\\player.skel".format( RS.Config.Tool.Path.Root )
elif pControl.Name == "Female":
gFileName = "{0}\\etc\\config\\anim\\skeletons\\female.skel".format( RS.Config.Tool.Path.Root )
lSkelFile = open(gFileName, "r")
lSkelFile = lSkelFile.readlines()
if lSkelFile != None: # Double Checks Selection was not cancelled.
# Create one Skeleton for all the Poses:
if pControl.Name == "Male":
# I need to create a skeleton here
skelFile = '{0}\\Male Skeleton.fbx'.format( RS.Config.Script.Path.ToolImages )
elif pControl.Name == "Female":
# I need to create a skeleton here
skelFile = '{0}\\Female Skeleton.fbx'.format( RS.Config.Script.Path.ToolImages )
# Setup merge options, leave take start/end alone.
lOptions = FBFbxOptions( True, skelFile )
lOptions.Story = FBElementAction.kFBElementActionDiscard
lOptions.Video = FBElementAction.kFBElementActionDiscard
lOptions.ModelsAnimation = False
lOptions.TakeSpan = FBTakeSpanOnLoad.kFBLeaveAsIs
lOptions.NamespaceList = 'TEMPORARY'
lOptions.BaseCameras = False
lOptions.CameraSwitcherSettings = False
lOptions.CurrentCameraSettings = False
lOptions.CamerasAnimation = False
lOptions.TransportSettings = False
lOptions.Cameras = FBElementAction.kFBElementActionDiscard
# Make sure no takes are merged in from the skeleton file.
for lTakeIndex in range( lOptions.GetTakeCount() ):
lOptions.SetTakeSelect( lTakeIndex, False )
# Merge
app = FBApplication()
app.FileMerge( skelFile, False, lOptions)
for iCharacter in RS.Globals.gCharacters:
iCharacter.Active = False
lMover = FBFindModelByLabelName("TEMPORARY:mover")
if lMover:
lMover.PropertyList.Find("RotationActive").Data = False
lMover.PropertyList.Find("TranslationActive").Data = False
lMover.PropertyList.Find("TranslationActive").Data = False
lMover.PropertyList.Find("Enable Translation DOF").Data = False
for iConstraint in RS.Globals.gConstraints:
if iConstraint.LongName == "TEMPORARY:mover_toybox_Control":
iConstraint.Active = False
# This applies the pose to the character
rs_AnimToFBX(lFileArray, lSkelFile, lSource)
###########################################################################################################
# I realize this code looks ridiculous but I swear it's needed to make the UI refresh.........this took me forever to figure out :(
# BUG - If you don't move the time slidder then the pose will not be correct it will be the time slider.
lPlayerControl = FBPlayerControl()
lPlayerControl.Goto(FBTime(0, 0, 0, 5))
lPlayerControl.Goto(FBTime(0, 0, 0, 0))
lPlayerControl.Goto(FBTime(0, 0, 0, 10))
lPlayerControl.Goto(FBTime(0, 0, 0, 0))
# (!!!) Note: It is very important to invoke FBSystem().Scene.Evaluate()
# Otherwise, it is not guaranteed that MotionBuilder's evaluation thread
# will have translated the hips effector before pose2.CopyPose() is called.
FBSystem().Scene.Evaluate()
lPlayerControl.Goto(FBTime(0, 0, 0, 5))
lPlayerControl.Goto(FBTime(0, 0, 0, 0))
lPlayerControl.Goto(FBTime(0, 0, 0, 10))
lPlayerControl.Goto(FBTime(0, 0, 0, 0))
###########################################################################################################
# copy pose
targetPose = FBCharacterPose('FRAME_0_of_ANIM_'+ os.path.basename(lFileName.rpartition(".")[0]))
for lChar in FBSystem().Scene.Characters:
if pControl.Name == "Male":
if lChar.LongName == "TEMPORARY:A_M_Y_Skater_01":
targetPose.CopyPose(lChar)
break
elif pControl.Name == "Female":
if lChar.LongName == "TEMPORARY:IG_AmandaTownley":
targetPose.CopyPose(lChar)
break
# I need to delete a skeleton here
rs_DeleteTempSkel()
###############################################################################################################
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
##
## Description: Create a pose from the first frame for every .Anim file in a folder. This will allow us to quickly create a pose
## straight from the exported assets, rather than the time consuming way of going to the source fbx.
##
##* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
###############################################################################################################
def rs_PoseFolderAnims(pControl, pEvent):
# Select Anim Folder
lFolderName = rs_SelectFolder()
if lFolderName: #Check to ensure a file name was selected and not cancelled
lFiles = RS.Utils.Path.Walk(lFolderName, pRecurse = 0, pPattern = '*.anim', pReturn_folders = 0 )
if pControl.Name == "Male":
gFileName = "{0}\\etc\\config\\anim\\skeletons\\player.skel".format( RS.Config.Tool.Path.Root )
elif pControl.Name == "Female":
gFileName = "{0}\\etc\\config\\anim\\skeletons\\female.skel".format( RS.Config.Tool.Path.Root )
lSkelFile = open(gFileName, "r")
lSkelFile = lSkelFile.readlines()
if lSkelFile: #Check to ensure a file name was selected and not cancelled
# Create one Skeleton for all the Poses:
if pControl.Name == "Male":
# I need to create a skeleton here
skelFile = '{0}\\Male Skeleton.fbx'.format( RS.Config.Script.Path.ToolImages )
elif pControl.Name == "Female":
# I need to create a skeleton here
skelFile = '{0}\\Female Skeleton.fbx'.format( RS.Config.Script.Path.ToolImages )
# Setup merge options, leave take start/end alone.
lOptions = FBFbxOptions( True, skelFile )
lOptions.NamespaceList = 'TEMPORARY'
lOptions.BaseCameras = False
lOptions.CameraSwitcherSettings = False
lOptions.CurrentCameraSettings = False
lOptions.CamerasAnimation = False
# Make sure no takes are merged in from the skeleton file.
for lTakeIndex in range( lOptions.GetTakeCount() ):
lOptions.SetTakeSelect( lTakeIndex, False )
# Merge
app = FBApplication()
app.FileMerge( skelFile, False, lOptions)
for iCharacter in RS.Globals.gCharacters:
iCharacter.Active = False
lMover = FBFindModelByLabelName("TEMPORARY:mover")
if lMover:
lMover.PropertyList.Find("RotationActive").Data = False
lMover.PropertyList.Find("TranslationActive").Data = False
lMover.PropertyList.Find("TranslationActive").Data = False
lMover.PropertyList.Find("Enable Translation DOF").Data = False
for iConstraint in RS.Globals.gConstraints:
if iConstraint.LongName == "TEMPORARY:mover_toybox_Control":
iConstraint.Active = False
# Go through each file in the folder
for iFile in lFiles:
lFileArray = []
lSource = "POSE"
lFileArray = rs_TrackArray(iFile,lSource)
if lFileArray != None:
# This applies the pose to the character
rs_AnimToFBX(lFileArray, lSkelFile, lSource)
###########################################################################################################
# I realize this code looks ridiculous but I swear it's needed to make the UI refresh.........this took me forever to figure out :(
# BUG - If you don't move the time slidder then the pose will not be correct it will be the time slider.
lPlayerControl = FBPlayerControl()
lPlayerControl.Goto(FBTime(0, 0, 0, 5))
lPlayerControl.Goto(FBTime(0, 0, 0, 0))
lPlayerControl.Goto(FBTime(0, 0, 0, 10))
lPlayerControl.Goto(FBTime(0, 0, 0, 0))
# (!!!) Note: It is very important to invoke FBSystem().Scene.Evaluate()
# Otherwise, it is not guaranteed that MotionBuilder's evaluation thread
# will have translated the hips effector before pose2.CopyPose() is called.
FBSystem().Scene.Evaluate()
lPlayerControl.Goto(FBTime(0, 0, 0, 5))
lPlayerControl.Goto(FBTime(0, 0, 0, 0))
lPlayerControl.Goto(FBTime(0, 0, 0, 10))
lPlayerControl.Goto(FBTime(0, 0, 0, 0))
###########################################################################################################
# copy pose
targetPose = FBCharacterPose('FRAME_0_of_ANIM_'+ os.path.basename(iFile.rpartition(".")[0]))
for lChar in FBSystem().Scene.Characters:
if pControl.Name == "Male":
if lChar.LongName == "TEMPORARY:A_M_Y_Skater_01":
targetPose.CopyPose(lChar)
break
elif pControl.Name == "Female":
if lChar.LongName == "TEMPORARY:IG_AmandaTownley":
targetPose.CopyPose(lChar)
break
# I need to delete a skeleton here
rs_DeleteTempSkel()