eduardo simioni

Archive for March, 2011

reading/writing xml with python and maxscript

by on Mar.09, 2011, under pipeline

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.

Leave a Comment :, , , , more...

exporting mirrored animations from Motionbuilder

by on Mar.06, 2011, under MotionBuilder, pipeline

It’s quite easy. Basically you need to:

  1. plot to the skeleton;
  2. save one animation;
  3. turn on Mirror Animation for the character;
  4. plot back to the control rig, which then mirrors the animation;
  5. rotate the Character Reference model 180 degrees;
  6. plot back to the skeleton;
  7. 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[0] = math.cos((180*0.017453292519943295769236907684886))
rotateY180[2] = math.sin((180*0.017453292519943295769236907684886))
rotateY180[8] = -math.sin((180*0.017453292519943295769236907684886))
rotateY180[10] = 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.

Leave a Comment :, , , , , , more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!