Tasks/ExportAnimationLibrary.py

Tasks/ExportAnimationLibrary.py
1 # Copyright 2009 Autodesk, Inc. All rights reserved.
2 # Use of this software is subject to the terms of the Autodesk license agreement
3 # provided at the time of installation or download, or which otherwise accompanies
4 # this software in either electronic or hard copy form.
5 #
6 # This script is to demonstrate Export the animation for list of models for the given take.
7 #
8 # Topic: FBApplication, FBSystem, FBFindModelByLabelName, FBBodyNodeId, FBTime, FBTake
9 #
10 
11 from pyfbsdk import FBApplication, FBSystem, FBFindModelByLabelName, FBBodyNodeId, FBTime, FBTake
12 import math
13 import sys
14 import os
15 import tempfile
16 
17 # ************************************************************* #
18 # #
19 # Export Library #
20 # #
21 # ************************************************************* #
22 
23 def loadScene(sceneFile):
24  application = FBApplication()
25  if (not application.FileOpen(sceneFile, False)):
26  return False
27  return True
28 
29 def getFullPrefix(name):
30  if len( name.split(":") )>1:
31  lastPref = name.split(":")[-2]
32  firstPref = name.split(lastPref)[0]
33  fullPrefix = firstPref+lastPref
34  return fullPrefix
35  else:
36  return None
37 
38 def addAllGroupMembers(group, members):
39  for member in group.Items:
40  if member.ClassName() == str("FBGroup"):
41  addAllGroupMembers(member, members)
42  else:
43  members.append(member)
44 
45 def addAllSetMembers(set, members):
46  for member in set.Items:
47  if member.ClassName() == str("FBGroup"):
48  addAllGroupMembers(member, members)
49  elif member.ClassName() == str("FBSet"):
50  addAllSetMembers(member, members)
51  else:
52  members.append(member)
53 
54 def getGroupMembers(groupName, members):
55  for group in FBSystem().Scene.Groups:
56  if group.Name == groupName.split(":")[-1]:
57  for item in group.Items:
58  if not getFullPrefix(item.LongName):
59  continue
60  elif getFullPrefix(item.LongName) == groupName.split(":")[-2]:
61  addAllGroupMembers(group, members)
62  return
63  else:
64  members.append(item)
65  return
66 
67 def getSetMembers(setName, members):
68  for set in FBSystem().Scene.Sets:
69  if set.Name == setName.split(":")[-1]:
70  for item in set.Items:
71  if not getFullPrefix(item.LongName):
72  continue
73  elif getFullPrefix(item.LongName) == setName.split(":")[-2]:
74  addAllSetMembers(set, members)
75  return
76  return
77 
78 def getHierarchy (modelName, rotationModels, translationModels):
79  model = FBFindModelByLabelName(modelName)
80 
81  if not model == None:
82  if not model.ClassName() == str("FBModel"):
83  #print "0. Add to rotation model list: ", model.FullName
84  rotationModels.append(model)
85  for child in model.Children:
86  getHierarchy(child.LongName, rotationModels, None)
87 
88  if not translationModels == None:
89  translationModels.append(model)
90  #print "0. Add to translation model list: ", model.FullName
91 
92 
93 def getCharacterModels(character, models, transModels):
94  chars = FBSystem().Scene.Characters
95  count = 0
96  countTrans = 0
97  for char in chars:
98  if char.Name == character:
99  for nodeID in FBBodyNodeId.values.values():
100  mod = char.GetModel(nodeID)
101  if mod != None:
102  count = count + 1
103  models.append(mod)
104  if nodeID == FBBodyNodeId.kFBHipsNodeId:
105  transModels.append(mod)
106  countTrans = countTrans + 1
107  #print "0. Get ", count, " models from character for rotation", character
108  #print "0. Get ", countTrans, " hip models from character for translation", character, " \n"
109  return
110 
111 def getModel(modelName, models):
112  mod = FBFindModelByLabelName(modelName)
113  if not mod == None:
114  models.append(mod)
115 
116 def mineCurve(start, end, fcurve, modifier):
117  curveData = dict()
118  counter = start
119  while counter <= end:
120  frameTime = FBTime(0,0,0,counter)
121  value = fcurve.Evaluate(frameTime) * modifier
122  curveData[frameTime.GetFrame()] = value
123  counter = counter + 1
124  return curveData
125 
126 def exportAnimData(animNodes, prefix, start, end, outData, modifier = 1.0):
127  if animNodes == None:
128  return
129 
130  for animNode in animNodes:
131  curveName = prefix + animNode.Name
132  curveData = mineCurve(start, end, animNode.FCurve, modifier)
133  outData[curveName] = curveData
134  # Export any animation below this animNode
135  exportAnimData(animNode.Nodes, prefix, start, end, outData)
136 
137 
138 def PlotModels(models, start, end):
139  # Mark the members as selected and plot them.
140  # For now, don't worry about backing up and restoring the current selection.
141  print "1.Plot the models!"
142  print "1.1. Select the models:"
143  for mod in models:
144  mod.Selected = True
145 
146  take = FBSystem().CurrentTake
147  # Set the current layer to the Base Layer.
148  # NOTE: This will crash MotionBuilder for versions prior to 2009.g. In version 2010,
149  # the Base Layer index has been changed to 0 instead of -1.
150  take.SetCurrentLayer(0)
151 
152  # Perform the plot of all the selected models with plot rate 30, or say "plot for every frame"!
153  print "1.2. Plot models from frame", start, "to frame", end
154  period = FBTime(0,0,0,1)
155  #period.SetSecondDouble( 1.0 / 30.0 ); # also works
156  take.PlotTakeOnSelected(period)
157 
158  # Unselect the model
159  print "1.3. Unselect all ploted models!"
160  for mod in models:
161  mod.Selected = False
162 
163 
164 def GetRotationAnimation(models, start, end, allData):
165  print "2. Rotation models has: ", len( rotationModels), "models."
166  count = 0
167  for mod in models:
168  if mod != None:
169  nodeAnim = mod.AnimationNode
170  for nodeAnimNode in nodeAnim.Nodes:
171  if "Lcl Rotation" in nodeAnimNode.Name:
172  if len(nodeAnimNode.Nodes) > 0:
173  exportAnimData(nodeAnimNode.Nodes, mod.FullName + "__Rotation", start, end, allData, math.pi/180.0)
174  count = count + 1
175  #print mod.FullName
176  print "2. Get valid rotation animation from: ", count, " models."
177 
178 def GetTranslationAnimation(models, start, end, allData):
179  print "2. Translation models has: ", len( translationModels), "models."
180  count = 0
181  for mod in models:
182  if mod != None:
183  #print mod.FullName
184  nodeAnim = mod.AnimationNode
185  for nodeAnimNode in nodeAnim.Nodes:
186  if "Lcl Translation" in nodeAnimNode.Name:
187  if len(nodeAnimNode.Nodes) > 0:
188  exportAnimData(nodeAnimNode.Nodes, mod.FullName + "__Translation", start, end, allData)
189  count = count + 1
190  #print mod.FullName
191  print "2. Get valid translation animation from: ", count, " models."
192 
193 def ExportAnimationData(outFile, allData):
194  print "3. Output animation data into file: ", outFile, "\n"
195 
196  # Output the data.
197  output = open (outFile, 'w')
198  output.write('########### Animation Data ###########\n')
199  for keyModelName,curveDict in allData.items():
200  output.write('%s\n'%(keyModelName))
201  #Sort curve dict
202  keylist = curveDict.keys()
203  keylist.sort()
204  for keyFrame in keylist:
205  output.write('%s: %s\n'%(keyFrame, curveDict[keyFrame]))
206  output.write('\n')
207  output.close()
208 
209 def ExportModelsAnimation(outFile, rotationModels, translationModels, start, end):
210  PlotModels( rotationModels, start, end )
211  PlotModels( translationModels, start, end )
212 
213  allData = dict()
214  GetRotationAnimation( rotationModels, start, end, allData )
215  GetTranslationAnimation( translationModels, start, end, allData )
216 
217  ExportAnimationData( outFile, allData )
218 
219 
220 # ************************************************************* #
221 # #
222 # File Specific Code #
223 # #
224 # ************************************************************* #
225 
226 # Attention: This script use the StoryExample.fbx as an example, but you may want to replace the file with your own.
227 # Meanwhile, you should also change the parameters below according to your own file before using them.
228 
229 # Specify the export parameters.
230 start = 120
231 end = 130
232 inFile = os.path.realpath(os.path.abspath(os.path.join( FBSystem().ApplicationPath, "../../OpenRealitySDK/Scenes/StoryExample.fbx" )))
233 outFile = os.path.realpath(os.path.abspath(os.path.join( tempfile.gettempdir(), "StoryExample_output.txt" )))
234 
235 # Load the scene to be exported.
236 if not loadScene(inFile):
237  sys.stderr.write('Could not load file %s' % inFile)
238  raise Exception('quitting')
239 
240 
241 # Initialize a list to contain the accumulated models.
242 # Rotation information will be generated for each of these models in rotationModels list.
243 # Additional model list, translationModels, is to contain models which should have translations exported for them.
244 rotationModels = list()
245 translationModels = list()
246 
247 # If exporting characters, get the models in the named characters.
248 # Characters may contain their own hips unknown at export time.
249 # Add any hips found in the character to the list of transModels
250 # so they will have translations exported for them.
251 getCharacterModels("Skeleton_Model", rotationModels, translationModels)
252 
253 # If exporting hierarchies, get the models in the named hierarchies.
254 # The root model of the hierarchy will be added to the transModels list.
255 getHierarchy ("Skeleton_Model:Hips", rotationModels, translationModels)
256 getHierarchy ("Character_Ctrl:HipsEffector", rotationModels, translationModels)
257 
258 # If exporting groups, get the models in the named groups. For groups
259 # containing root models, add those models to the list of transModels.
260 getGroupMembers("KNIGHT:RightThighArmorLowBeltBuckle", rotationModels)
261 
262 # If exporting sets, get the models in the named sets. For sets
263 # containing root models, add those models to the list of transModels.
264 # Attention: Here we just show how to get SetMembers, and MyNamespace:MySet doesn't really exist.
265 '''
266 getSetMembers("MyNamespace:MySet", models)
267 '''
268 
269 # Finally, add any additional models which should have translations
270 # and rotations exported for them.
271 getModel("KNIGHT:Hips", rotationModels)
272 getModel("KNIGHT:Hips", translationModels)
273 getModel("Character_Ctrl:HipsEffector", translationModels)
274 
275 
276 print "0. Totally get", len(rotationModels), "models to export their rotation."
277 #for model in rotationModels:
278 # print model.FullName
279 print "0. Totally get", len(translationModels), "models to export their translations."
280 #for model in translationModels:
281 # print model.FullName
282 
283 # If no models have been found, raise an exception
284 if len(rotationModels) == 0 & len(translationModels) == 0:
285  sys.stderr.write('No models were found.')
286  raise Exception('quitting')
287 
288 # Export the animation for the given list of models for the given takes.
289 ExportModelsAnimation(outFile, rotationModels, translationModels, start, end)
290 
291 print "The animation data for from frame ", start, " to frame ", end, " have been exported to file: \n", outFile