1526 lines
83 KiB
Python
Executable File
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()
|