I have about 2000+ files to parse that are xml and look like OGRE files.
the MaxScript code that I wrote that processes max files is as follows
--<><
--Name: 'Psuedo OGRE'
--3DSMax: 9
--Author: jayr@hourglass3d.com
--This script exports a skeleton and animation XML file in the same directory as the 3DSMax file.
--Exporting xML based on OGRE file fromat
--Still WIP
-- ***** BEGIN GPL LICENSE BLOCK *****
--
-- Script copyright (C) Bob Holcomb
--
-- This program is free software; you can redistribute it and/or
-- modify it under the terms of the GNU General Public License
-- as published by the Free Software Foundation; either version 2
-- of the License, or (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software Foundation,
-- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
--
-- ***** END GPL LICENCE BLOCK *****
-- --------------------------------------------------------------------------
--######################################################
--# Set working files
--######################################################
tmpDir= "C:\\maxtemp\\"
oAnimXML = tmpDir + "tempAnim.xml"
--######################################################
--# Create temp directory
--# May need to move it to ~\Local Settings\Temp
--######################################################
try (makeDir tmpDir)
catch()
--######################################################
--# Spits out animation data to a temporary directory
--######################################################
fn createTemporaryAnims tmpDir =
(
select(for o in helpers where classof o == bone collect o)
oSelection = selection as array
for i = 1 to oSelection.count do
(
tmpfile= tmpDir + (oSelection[i].name) + ".tmp"
createfile tmpfile
)
for t = animationrange.start to animationrange.end do
(
sliderTime = t
for i = 1 to oSelection.count do
(
oTMP= tmpDir + (oSelection[i].name) + ".tmp"
obj = oSelection[i]
outputFile = openFile oTMP mode:"a"
format " <keyframe frame=\"%\">
" (t.frame as integer) to:outputFile
format " <translate x=\"%\" y=\"%\" z=\"%\" />
" obj.pos.x obj.pos.y obj.pos.z to:outputFile
format " <rotate w=\"%\" x=\"%\" y=\"%\" z=\"%\" />
" obj.rotation.w obj.rotation.x obj.rotation.y obj.rotation.z to:outputFile
format " </keyframe>
" to:outputFile
close outputFile
)
)
)
--######################################################
--# Merges the temp file animations together and names
--# the track bone based on tmpfile
--######################################################
fn mergeAnimTempFiles tmpDir =
(
oFiles = getFiles (tmpDir + "*")
outputFile = createfile oAnimXML
format " <animation name=\"%\" length=\"%\">
" (getFilenameFile maxFileName) (((animationrange.end as float)/TicksPerFrame)/30) to:outputFile
for i in oFiles do
(
if i == oAnimXML then
(
--print ("not proccessing " + oAnimXML)
)
else
(
format " <track bone=\"%\">
" (getFilenameFile i) to:outputFile
oFile = openFile i mode:"r"
while not eof oFile do
(
oLine = readLine oFile
line = oLine + "
"
format line to:outputFile
)
format " </track>
" to:outputFile
)
)
format " </animation>
" to:outputFile
)
--######################################################
--# Writes the final animation xml file
--######################################################
fn writeAnimations tmpDir outputFile =
(
createTemporaryAnims tmpDir -- create temporay files of animations
mergeAnimTempFiles tmpDir -- merge all the temporary files ang create a temporary animation xml file
oFile = openFile oAnimXML mode:"r" --- merge the temporary animation xml file to the final output
while not eof oFile do
(
oLine = readLine oFile
line = oLine + "
"
format line to:outputFile
)
)
--######################################################
--# Creates the skeleton file
--######################################################
fn writeSkeleton outputFile =
(
select(for o in helpers where classof o == bone collect o)
oSelection = selection as array
sliderTime = 0
format " <skeleton>
" to:outputFile
for obj in oSelection do
(
boneRot = obj.rotation as eulerAngles
format " <bone name=\"%\">
" obj.name to:outputFile
if obj.parent == undefined then
(
format " <headpos x=\"%\" y=\"%\" z=\"%\" />
" .0 .0 .5 to:outputFile
)
else
(
format " <headpos x=\"%\" y=\"%\" z=\"%\" />
" (obj.parent.pos).x (obj.parent.pos).y (obj.parent.pos).z to:outputFile
)
format " <tailpos x=\"%\" y=\"%\" z=\"%\" />
" obj.pos.x obj.pos.y obj.pos.z to:outputFile
format " <rotation x=\"%\" y=\"%\" z=\"%\" />
" boneRot.x boneRot.y boneRot.z to:outputFile
if obj.parent == undfined then
(
format " <boneparent parent=\"%\" />
" "None" to:outputFile
)
else
(
format " <boneparent parent=\"%\" />
" obj.parent.name to:outputFile
)
format " </bone>
" to:outputFile
)
format " </skeleton>
" to:outputFile
)
fn removeTempFiles tmpDir =
(
oFiles = getFiles (tmpDir + "*.*")
for phile in oFiles do
(
deleteFile phile -- Delet all files in the temp directory
)
)
--######################################################
--# Merges the Skeleton and the animation
--# xml files together
--######################################################
fn createXMLanim phileName =
(
if phileName != undefined then
(
xmlOutput = (maxFilePath + (getFilenameFile maxFileName) + ".xml")
print xmlOutput
outputFile = createfile xmlOutput
format "<armature name=\"%\">
" (getFilenameFile maxFileName) to:outputFile
writeSkeleton (outputFile)
writeAnimations tmpDir outputFile
format "</armature>
" to:outputFile
close outputFile
)
)
--######################################################
--# Main function.
--# Also spits OBJ files if there poly object(s)
--######################################################
fn main =
(
files = getFiles "C:\ mp\\w3d\\archer\\*.max"
for i in files do
(
sliderTime = 0
loadMaxFile i quiet: True;
oBoneArr = (for o in helpers where classof o == bone collect o)
oObjArr = (for o in Geometry where (classof o == Editable_mesh or classof o == Editable_poly) collect o)
if oBoneArr.count > 1 then
(
print "Exporting XML FIle"
createXMLanim i
)
if oObjArr.count > 0 then
(
print "Exporint OBJ file "
select oObjArr
outputFile = (getFilenamePath i) + (getFilenameFile maxFileName) + ".obj"
exportFile outputFile #noPrompt
)
resetMaxFile #noPrompt
removeTempFiles tmpDir
)
)
main()
The blender code looks like this but it is still WIP:
#<><
#Name: 'Psuedo OGRE'
#Blender: 2.49
#Author: jayr@hourglass3d.com
#This script imports a skeleton and animation XML file supplied by a string.
#Importing XML based on OGRE file fromat
#Still WIP
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Script copyright (C) Bob Holcomb
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# #####################################
######################################################
# Importing modules
######################################################
from Blender.Mathutils import *
from Blender import Armature
from Blender import *
import Blender, math
import xml.dom.minidom
from xml.dom.minidom import Node
doc = xml.dom.minidom.parse('D:\ emp\\w3d_temp.xml')
######################################################
# gets the bone Head postion from XML
######################################################
def getHeadPos (documentStr):
boneHeadPos = []
getElements = documentStr.getElementsByTagName
for boneNode in getElements('bone'):
for child in boneNode.childNodes:
if child.nodeName == 'headpos':
bonePosX = child.getAttribute("x")
bonePosY = child.getAttribute("y")
bonePosZ = child.getAttribute("z")
boneVectorPos = float(bonePosX), float(bonePosY), float(bonePosZ)
boneHeadPos.append(boneVectorPos)
#print 'Head: Vector(%s, %s, %s)' % (bonePosX, bonePosY, bonePosZ)
return boneHeadPos
######################################################
# gets the bone Tail postion from XML
######################################################
def getTailPos (documentStr):
boneTailPos = []
getElements = documentStr.getElementsByTagName
for boneNode in getElements('bone'):
for child in boneNode.childNodes:
if child.nodeName == 'tailpos':
boneTailPosX = child.getAttribute("x")
boneTailPosY = child.getAttribute("y")
boneTailPosZ = child.getAttribute("z")
boneVectorPos = float(boneTailPosX), float(boneTailPosY), float(boneTailPosZ)
boneTailPos.append(boneVectorPos)
#print 'Rot: Vector(%s, %s, %s)' % (boneRotX, boneRotY, boneRotZ)
return boneTailPos
######################################################
#gets the bone rotation from XML
######################################################
def getBoneRot (documentStr):
boneRot = []
getElements = documentStr.getElementsByTagName
for boneNode in getElements('bone'):
for child in boneNode.childNodes:
if child.nodeName == 'rotation':
boneRotX = child.getAttribute("x")
boneRotY = child.getAttribute("y")
boneRotZ = child.getAttribute("z")
boneVectorRot = float(boneRotX), float(boneRotY), float(boneRotZ)
boneRot.append(boneVectorRot)
#print 'Rot: Vector(%s, %s, %s)' % (boneRotX, boneRotY, boneRotZ)
return boneRot
######################################################
#gets the bone name from XML
######################################################
def getBoneName (documentStr):
boneName = []
getElements = documentStr.getElementsByTagName
for boneNode in getElements('bone'):
boneNodeName = boneNode.getAttribute("name")
boneName.append(boneNodeName)
#print boneNodeName
return boneName
######################################################
# gets bone parent
######################################################
def getBoneParent (documentStr):
boneParentName = []
getElements = documentStr.getElementsByTagName
for boneNode in getElements('bone'):
for child in boneNode.childNodes:
if child.nodeName == 'boneparent':
boneNodeParent= child.getAttribute("parent")
boneParentName.append(boneNodeParent)
#print boneNodeParent
return boneParentName
######################################################
# creates an empty armature
######################################################
def createArmature (armName = None): #creates an empty armature
arm = ''
if armName == None:
arm = 'Armature'
else:
arm = armName
print 'creating armature by the name of %s' % arm
armature = Blender.Object.New('Armature', arm)
armatureName = armature.name
scene = Blender.Scene.GetCurrent()
scene.link(armature)
return armatureName
######################################################
# Adds bones to the selected Armature
######################################################
def addBone (armObjStr, bHead, bTail, bName, bParent):
armObj = Blender.Object.Get(armObjStr)
armObjDataBlock = armObj.getData(name_only = 1)
arm = Armature.Get(armObjDataBlock)
arm.makeEditable()
eb = Armature.Editbone()
eb.head = Vector(bHead)
eb.tail = Vector(bTail)
if bParent != 'None':
eb.parent = arm.bones[bParent]
eb.options = [Armature.HINGE, Armature.CONNECTED]
arm.bones[bName] = eb
arm.update()
######################################################
# creates empties for every Tail Postion
######################################################
def addEmpty (emptyName,locVector ):
nullObj = Blender.Object.New('Empty', emptyName)
emptyName = nullObj.name
scene = Blender.Scene.GetCurrent()
scene.link(nullObj)
oObj = Blender.Object.Get(emptyName)
oObj.setLocation(locVector)
return emptyName
######################################################
# Animates the empties
######################################################
def animateEmpties (documentStr):
getElements = documentStr.getElementsByTagName
for trackNode in getElements('track'):
oObjName= trackNode.getAttribute('bone')
#print oObjName
oObj = Blender.Object.Get(oObjName) #Select the object that cooralates to bone/null name
for keyframeNode in trackNode.childNodes:
if keyframeNode.nodeName == 'keyframe':
oFrame = keyframeNode.getAttribute('frame')
Blender.Set('curframe',int(oFrame))#move timer to the frame int(key)
for keychildNode in keyframeNode.childNodes:
if keychildNode.nodeName == 'translate':
boneTransX = keychildNode.getAttribute("x")
boneTransY = keychildNode.getAttribute("y")
boneTransZ = keychildNode.getAttribute("z")
oVectorTrans = float(boneTransX), float(boneTransY), float(boneTransZ)
oObj.setLocation(Vector(oVectorTrans)) #Moves null to location
oObj.insertIpoKey(Blender.Object.LOC) #Sets a key for the location of the null
#if keychildNode.nodeName == 'rotate':
#boneRotW = keychildNode.getAttribute("w")
#boneRotX = keychildNode.getAttribute("x")
#boneRotY = keychildNode.getAttribute("y")
#boneRotZ = keychildNode.getAttribute("z")
#boneQuatRot = float(boneRotW), float(boneRotX), float(boneRotY), float(boneRotZ)
#TODO: rotate the null
#TODO: insert LOC ROT keys
Blender.Set('curframe',0) #puts the scene frame back to zero
######################################################
# adds constraints to the Empty objects
######################################################
def addConstraints (armObjStr):
ob = Blender.Object.Get(armObjStr)
pose = ob.getPose()
for bonename in pose.bones.keys():
bone = pose.bones[bonename]
constTarget = oObj = Blender.Object.Get(bone.name)
if (bone.parent) != None:
#print bone.parent.name
const = bone.constraints.append(2) #trackto constraint
const[Constraint.Settings.TARGET] = constTarget
else:
#print 'None'
const = bone.constraints.append(2) #trackto constraint
const[Constraint.Settings.TARGET] = constTarget
const = bone.constraints.append(9) #copylocation constriant
const[Constraint.Settings.TARGET] = constTarget
######################################################
# Generates the skeleton of of XML
######################################################
def createSkeleton ():
armObjStr = ''
boneNames = getBoneName (doc)
boneHead = getHeadPos (doc)
boneTail = getTailPos (doc)
boneParent = getBoneParent (doc)
lenght = len(boneNames)
count = 0
arm_ob = 'TestRig'
armObjStr = createArmature (arm_ob)
for i in range(0,lenght):
bName = boneNames[i]
bHead = boneHead[i]
bTail = boneTail[i]
bParent = boneParent[i]
addEmpty (bName,bTail )
if bParent == 'None':
bHead = Vector(bTail)*0.95
#print bHead
elif bTail == (0.0, 0.0, 0.0):
bTail = Vector(boneHead[i])*2
#print bTail
#print bName
addBone (armObjStr, bHead, bTail, bName, bParent)
#print armObjStr, '
', bHead, '
', bTail, '
', bName, '
', bParent '
'
#print '
#########
', 'Head', bHead , '
Tail', bTail, '
#########
'
count +=1
return armObjStr
######################################################
# main function
######################################################
def main ():
oArm = createSkeleton()
animateEmpties (doc)
addConstraints (oArm)
main()
Blender.Redraw
WIP Help: My armature doesn’t follow the constraints unless I create a LOCROT key for a random bone. Or create a new scene and the open the original scene back. I would like to have that done via script. Like a Redraw or something
Also I want to set the scene end frame and grab the variable off the XML file.
Finally, the biggest problem I want solve is I want to batch the 2000 XML files. Preferably would like to do it via COM/OLE, so that I can use win32com.client and do everything from Pythong.
Any suggestions, comments, help is appreciated
Any maxscript suggestions, feedback are welcome too