Archive for March, 2011
If you know where to find the information it becomes quite straight forward if you are not doing anything complex. With python you can use xml.dom.minidom, while with maxscript you can use either .NET Object “System.Xml.XmlDocument” or Class “System.Xml.XmlReader“.
With python you create a root element and append child elements from there. A very good sample can be found on: http://www.postneo.com/projects/pyxml/ To read you have getElementsByTagName on both python and dotnet XmlDocument. XmlReader might be a bit faster, but you have to parse elements by yourself.
There’s an issue with minidom’s toprettyprintxml, it adds whitespace and tabs between tags, around textNodes. And they are obviously read afterwards. A couple of different solutions are discussed on Ron Rothman’s blog, the easiest one using xml.dom.ext.PrettyPrint.
It’s quite easy. Basically you need to:
- plot to the skeleton;
- save one animation;
- turn on Mirror Animation for the character;
- plot back to the control rig, which then mirrors the animation;
- rotate the Character Reference model 180 degrees;
- plot back to the skeleton;
- save mirrored animation.
The tricky part is just number 5 where you need to do some matrix rotation. Python for this would be something like:
from pyfbsdk import * app = FBApplication() char = app.CurrentCharacter savePath = r"C:\" filename = app.FBXFileName skeleton = FBCharacterPlotWhere.kFBCharacterPlotOnSkeleton ctrlrig = FBCharacterPlotWhere.kFBCharacterPlotOnControlRig # plot to skeleton, see bellow plotAnim(char, skeleton) # save left animation sOptions = FBFbxOptions(False) # false = save options sOptions.SaveCharacter = True sOptions.SaveControlSet = False sOptions.SaveCharacterExtension = False sOptions.ShowFileDialog = False sOptions.ShowOptionsDialog = False app.SaveCharacterRigAndAnimation(savePath + "\\" + filename + "_L", char, sOptions) # activate mirror and plot char.MirrorMode = True plotAnim(char, ctrlrig) # get reference model refModel = FBFindModelByName("Character_Ctrl:Reference") # rotating 180, the tricky part # http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q28 rotateY180 = FBMatrix() rotateY180 = math.cos((180*0.017453292519943295769236907684886)) rotateY180 = math.sin((180*0.017453292519943295769236907684886)) rotateY180 = -math.sin((180*0.017453292519943295769236907684886)) rotateY180 = math.cos((180*0.017453292519943295769236907684886)) refMT = FBMatrix() refModel.GetMatrix(refMT) refModel.SetMatrix( MatrixMult(rotateY180, refMT) ) scene.Evaluate() # plot back to skeleton plotAnim(char, skeleton) # save again app.SaveCharacterRigAndAnimation(savePath + "\\" + filename + "_R", char, sOptions)
The plot and multiplication functions are:
# This is from Neil3d: http://neill3d.com/mobi-skript-raschet-additivnoj-animacii?langswitch_lang=en def MatrixMult(Ma, Mb): res = FBMatrix() for i in range(0,4): for j in range(0,4): sum=0 for k in range(0,4): sum += Ma[i*4+k] * Mb[k*4+j] res[i*4+j] = sum return res def plotAnim(char, where): if char.GetCharacterize: switchOn = char.SetCharacterizeOn(True) plotoBla = FBPlotOptions() plotoBla.ConstantKeyReducerKeepOneKey = True plotoBla.PlotAllTakes = True plotoBla.PlotOnFrame = True plotoBla.PlotPeriod = FBTime( 0, 0, 0, 1 ) #plotoBla.PlotTranslationOnRootOnly = True plotoBla.PreciseTimeDiscontinuities = True #plotoBla.RotationFilterToApply = FBRotationFilter.kFBRotationFilterGimbleKiller plotoBla.UseConstantKeyReducer = False plotoBla.ConstantKeyReducerKeepOneKey = True if (not char.PlotAnimation(where, plotoBla)): FBMessageBox( "Something went wrong", "Plot animation returned false, cannot continue", "OK", None, None ) return False return char
If you are exporting the character to a game, pay attention to the root node rotation. If you used it in the characterization, chances are it might also be rotated, and you might not want that to happen. You can also establish a convention on the name of the files, and easily detect if the animation currently open ends with _L or _R, and adapt the filename correctly.
FBApplication().SaveCharacterRigAndAnimation() is the equivalent of the Save Character Animation on the Character Controls window, which saves only the animation, without mesh. I prefer to use this when exporting only the animation from Motionbuilder to some other software, since it’s cleaner, faster and file sizes are smaller, but you could use any other function also.