Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWillian Padovani Germano <wpgermano@gmail.com>2004-06-08 09:43:00 +0400
committerWillian Padovani Germano <wpgermano@gmail.com>2004-06-08 09:43:00 +0400
commit25a0df8b711c4b7841342a069975681cba14fb33 (patch)
tree316801ac8f901c26e58949d7a2f161950200f510 /release
parenta15b430d716b1cba7c07af7b14959e6061d001cc (diff)
Scripts: Campbell (ideasman) donated two more scripts: bvh motion capture import/export (thanks!).
Diffstat (limited to 'release')
-rw-r--r--release/scripts/bvh_export.py384
-rw-r--r--release/scripts/bvh_import.py442
2 files changed, 826 insertions, 0 deletions
diff --git a/release/scripts/bvh_export.py b/release/scripts/bvh_export.py
new file mode 100644
index 00000000000..8c0f95fdc25
--- /dev/null
+++ b/release/scripts/bvh_export.py
@@ -0,0 +1,384 @@
+#!BPY
+
+"""
+Name: 'Motion Capture (*.bvh)'
+Blender: 232
+Group: 'Export'
+Tip: 'Export a (*.bvh) motion capture file'
+"""
+#===============================================#
+# BVH Export script 1.0 by Campbell Barton #
+# Copyright MetaVR 30/03/2004, #
+# if you have any questions about this script #
+# email me ideasman@linuxmail.org #
+# #
+#===============================================#
+
+# --------------------------------------------------------------------------
+# BVH Export v0.9 by Campbell Barton (AKA Ideasman)
+# --------------------------------------------------------------------------
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# 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 *****
+# --------------------------------------------------------------------------
+
+import Blender
+from Blender import Scene, Object
+import math
+from math import *
+
+# Get the current scene.
+scn = Scene.GetCurrent()
+context = scn.getRenderingContext()
+
+frameRate = 0.3333 # 0.04 = 25fps
+scale = 1
+
+indent = ' ' # 2 space indent per object
+prefixDelimiter = '_'
+
+# Vars used in eular rotation funtcion
+RAD_TO_DEG = 180.0/3.14159265359
+
+
+
+#====================================================#
+# Search for children of this object and return them #
+#====================================================#
+def getChildren(parent):
+ children = [] # We'll assume none.
+ for child in Object.Get():
+ if child.getParent() == Object.Get(parent):
+ children.append( child.getName() )
+ return children
+
+#====================================================#
+# MESSY BUT WORKS: Make a string that shows the #
+# hierarchy as a list and then eval it #
+#====================================================#
+def getHierarchy(root, hierarchy):
+ hierarchy = hierarchy + '["' + root + '",'
+ for child in getChildren(root):
+ hierarchy = getHierarchy(child, hierarchy)
+ hierarchy += '],'
+ return hierarchy
+
+
+#====================================================#
+# Strips the prefix off the name before writing #
+#====================================================#
+def stripName(name): # name is a string
+
+ # WARNING!!! Special case for a custom RIG for output
+ # for MetaVR's HPX compatable RIG.
+ print 'stripname', name[0:10]
+ if name[0:10] == 'Transform(':
+ name = name[10:]
+ while name[-1] != ')':
+ name = name[0:-1]
+ print name
+ name = name[:-1]
+
+
+ return name[1+name.find(prefixDelimiter): ]
+
+
+#====================================================#
+# Return a 6 deciaml point floating point value #
+# as a string that dosent have any python chars #
+#====================================================#
+def saneFloat(float):
+ #return '%(float)b' % vars() # 6 fp as house.hqx
+ return str('%f' % float) + ' '
+
+
+
+#====================================================#
+# Recieves an object name, gets all the data for that#
+# node from blender and returns it for formatting #
+# and writing to a file. #
+#====================================================#
+def getNodeData(nodeName):
+ Object.Get(nodeName)
+ # Get real location
+ offset = Object.Get(nodeName).getLocation()
+ offset = (offset[0]*scale, offset[1]*scale, offset[2]*scale,)
+
+ #=========================#
+ # Test for X/Y/Z IPO's #
+ #=========================#
+ obipo = Object.Get(nodeName).getIpo()
+
+ # IF we dont have an IPO then dont check the curves.
+ # This was added to catch end nodes that never have an IPO, only an offset.
+ if obipo == None:
+ xloc=yloc=zloc=xrot=yrot=zrot = 0
+
+ else: # Do have an IPO, checkout which curves are in use.
+ # Assume the rot's/loc's exist until proven they dont
+ xloc=yloc=zloc=xrot=yrot=zrot = 1
+ if obipo.getCurve('LocX') == None:
+ xloc = 0
+ if obipo.getCurve('LocY') == None:
+ yloc = 0
+ if obipo.getCurve('LocZ') == None:
+ zloc = 0
+
+ # Now for the rotations, Because of the conversion of rotation coords
+ # if there is one rotation er need to store all 3
+ if obipo.getCurve('RotX') == None and \
+ obipo.getCurve('RotY') == None and \
+ obipo.getCurve('RotZ') == None:
+ xrot=yrot=zrot = 0
+
+ # DUMMY channels xloc, yloc, zloc, xrot, yrot, zrot
+ # [<bool>, <bool>, <bool>, <bool>, <bool>, <bool>]
+ channels = [xloc, yloc, zloc, xrot, yrot, zrot]
+
+ return offset, channels
+
+
+#====================================================#
+# Return the BVH hierarchy to a file from a list #
+# hierarchy: is a list of the empty hierarcht #
+# bvhHierarchy: a string, in the bvh format to write #
+# level: how many levels we are down the tree, #
+# ...used for indenting #
+# Also gathers channelList , so we know the order to #
+# write the motiondata in #
+#====================================================#
+def hierarchy2bvh(hierarchy, bvhHierarchy, level, channelList, nodeObjectList):
+ nodeName = hierarchy[0]
+
+ # Add object to nodeObjectList
+ nodeObjectList.append(Object.Get(nodeName))
+
+ #============#
+ # JOINT NAME #
+ #============#
+ bvhHierarchy += level * indent
+ if level == 0:
+ # Add object to nodeObjectList
+ nodeObjectList.append(Object.Get(nodeName))
+ bvhHierarchy+= 'ROOT '
+ bvhHierarchy += stripName(nodeName) + '\n'
+ # If this is the last object in the list then we
+ # dont bother withwriting its real name, use "End Site" instead
+ elif len(hierarchy) == 1:
+ bvhHierarchy+= 'End Site\n'
+ # Ok This is a normal joint
+ else:
+ # Add object to nodeObjectList
+ nodeObjectList.append(Object.Get(nodeName))
+ bvhHierarchy+= 'JOINT '
+ bvhHierarchy += stripName(nodeName) + '\n'
+ #================#
+ # END JOINT NAME #
+ #================#
+
+ # Indent again, this line is just for the brackets
+ bvhHierarchy += level * indent + '{' + '\n'
+
+ # Indent
+ level += 1
+
+ #================================================#
+ # Data for writing to a file offset and channels #
+ #================================================#
+ offset, channels = getNodeData(nodeName)
+
+ #============#
+ # Offset #
+ #============#
+ bvhHierarchy += level * indent + 'OFFSET ' + saneFloat(scale * offset[0]) + ' ' + saneFloat(scale * offset[1]) + ' ' + saneFloat(scale * offset[2]) + '\n'
+
+ #============#
+ # Channels #
+ #============#
+ if len(hierarchy) != 1:
+ # Channels, remember who is where so when we write motiondata
+ bvhHierarchy += level * indent + 'CHANNELS '
+ # Count the channels
+ chCount = 0
+ for chn in channels:
+ chCount += chn
+ bvhHierarchy += str(chCount) + ' '
+ if channels[0]:
+ bvhHierarchy += 'Xposition '
+ channelList.append([len(nodeObjectList)-1, 0])
+ if channels[1]:
+ bvhHierarchy += 'Yposition '
+ channelList.append([len(nodeObjectList)-1, 1])
+ if channels[2]:
+ bvhHierarchy += 'Zposition '
+ channelList.append([len(nodeObjectList)-1, 2])
+ if channels[5]:
+ bvhHierarchy += 'Zrotation '
+ channelList.append([len(nodeObjectList)-1, 5])
+ if channels[3]:
+ bvhHierarchy += 'Xrotation '
+ channelList.append([len(nodeObjectList)-1, 3])
+ if channels[4]:
+ bvhHierarchy += 'Yrotation '
+ channelList.append([len(nodeObjectList)-1, 4])
+
+ bvhHierarchy += '\n'
+
+ # Loop through children if any and run this function (recursively)
+ for hierarchyIdx in range(len(hierarchy)-1):
+ bvhHierarchy, level, channelList, nodeObjectList = hierarchy2bvh(hierarchy[hierarchyIdx+1], bvhHierarchy, level, channelList, nodeObjectList)
+ # Unindent
+ level -= 1
+ bvhHierarchy += level * indent + '}' + '\n'
+
+ return bvhHierarchy, level, channelList, nodeObjectList
+
+# added by Ben Batt 30/3/2004 to make the exported rotations correct
+def ZYXToZXY(x, y, z):
+ '''
+ Converts a set of Euler rotations (x, y, z) (which are intended to be
+ applied in z, y, x order) into a set which are intended to be applied in
+ z, x, y order (the order expected by .bvh files)
+ '''
+ A,B = cos(x),sin(x)
+ C,D = cos(y),sin(y)
+ E,F = cos(z),sin(z)
+
+ x = asin(-B*C)
+ y = atan2(D, A*C)
+ z = atan2(-B*D*E + A*F, B*D*F + A*E)
+
+ # this seems to be necessary - not sure why (right/left-handed coordinates?)
+ x = -x
+ return x*RAD_TO_DEG, y*RAD_TO_DEG, z*RAD_TO_DEG
+
+
+
+def getIpoLocation(object, frame):
+ x = y = z = 0
+ obipo = object.getIpo()
+ for i in range(object.getIpo().getNcurves()):
+ if obipo.getCurves()[i].getName() =='LocX':
+ x = object.getIpo().EvaluateCurveOn(i,frame)
+ elif obipo.getCurves()[i].getName() =='LocY':
+ y = object.getIpo().EvaluateCurveOn(i,frame)
+ elif obipo.getCurves()[i].getName() =='LocZ':
+ z = object.getIpo().EvaluateCurveOn(i,frame)
+ return x, y, z
+
+
+#====================================================#
+# Return the BVH motion for the spesified frame #
+# hierarchy: is a list of the empty hierarcht #
+# bvhHierarchy: a string, in the bvh format to write #
+# level: how many levels we are down the tree, #
+# ...used for indenting #
+#====================================================#
+def motion2bvh(frame, chennelList, nodeObjectList):
+
+ motionData = '' # We'll append the frames to the string.
+
+ for chIdx in chennelList:
+ ob = nodeObjectList[chIdx[0]]
+ chType = chIdx[1]
+
+ # Get object rotation
+ x, y, z = ob.getEuler()
+
+ # Convert the rotation from ZYX order to ZXY order
+ x, y, z = ZYXToZXY(x, y, z)
+
+
+ # Using regular Locations stuffs upIPO locations stuffs up
+ # Get IPO locations instead
+ xloc, yloc, zloc = getIpoLocation(ob, frame)
+
+ # WARNING non standard Location
+ xloc, zloc, yloc = -xloc, yloc, zloc
+
+
+ if chType == 0:
+ motionData += saneFloat(scale * (xloc))
+ if chType == 1:
+ motionData += saneFloat(scale * (yloc))
+ if chType == 2:
+ motionData += saneFloat(scale * (zloc))
+ if chType == 3:
+ motionData += saneFloat(x)
+ if chType == 4:
+ motionData += saneFloat(y)
+ if chType == 5:
+ motionData += saneFloat(z)
+
+ motionData += ' '
+
+ motionData += '\n'
+ return motionData
+
+def saveBVH(filename):
+
+ # Here we store a serialized list of blender objects as they appier
+ # in the hierarchy, this is refred to when writing motiondata
+ nodeObjectList = []
+
+ # In this list we store a 2 values for each node
+ # 1) An index pointing to a blender object
+ # in objectList
+ # 2) The type if channel x/y/z rot:x/y/z - Use 0-5 to indicate this
+ chennelList = []
+
+ print ''
+ print 'BVH 1.0 by Campbell Barton (Ideasman) - ideasman@linuxmail.org'
+
+ # Get the active object and recursively traverse its kids to build
+ # the BVH hierarchy, then eval the string to make a hierarchy list.
+ hierarchy = eval(getHierarchy(Object.GetSelected()[0].getName(),''))[0] # somhow this returns a tuple with one list in it.
+
+ # Put all data in the file we have selected file.
+ file = open(filename, "w")
+ file.write('HIERARCHY\n') # all bvh files have this on the first line
+
+ # Write the whole hirarchy to a list
+ bvhHierarchy, level, chennelList, nodeObjectList = hierarchy2bvh(hierarchy, '', 0, chennelList, nodeObjectList)
+ file.write( bvhHierarchy ) # Rwite the var fileBlock to the output.
+ bvhHierarchy = None # Save a tit bit of memory
+
+ #====================================================#
+ # MOTION: Loop through the frames ande write out #
+ # the motion data for each #
+ #====================================================#
+ # Do some basic motion file header stuff
+ file.write('MOTION\n')
+ file.write( 'Frames: ' + str(1 + context.endFrame() - context.startFrame()) + '\n' )
+ file.write( 'Frame Time: ' + saneFloat(frameRate) + '\n' )
+
+ #print 'WARNING- exact frames might be stuffed up- inclusive whatever, do some tests later on.'
+ frames = range(context.startFrame(), context.endFrame()+1)
+ print 'exporting ' + str(len(frames)) + ' of motion...'
+
+ for frame in frames:
+ context.currentFrame(frame)
+ scn.update(1) # Update locations so we can write the new locations
+ #Blender.Window.RedrawAll() # causes crash
+
+ file.write( motion2bvh(frame, chennelList, nodeObjectList) )
+
+ file.write('\n') # newline
+ file.close()
+ print 'done'
+
+Blender.Window.FileSelector(saveBVH, 'SELECT NEW BVH FILE') \ No newline at end of file
diff --git a/release/scripts/bvh_import.py b/release/scripts/bvh_import.py
new file mode 100644
index 00000000000..c677906f79e
--- /dev/null
+++ b/release/scripts/bvh_import.py
@@ -0,0 +1,442 @@
+#!BPY
+
+"""
+Name: 'Motion Capture (*.bvh)'
+Blender: 232
+Group: 'Import'
+Tip: 'Import a (*.bvh) motion capture file'
+"""
+
+#===============================================#
+# BVH Import script 1.0 by Campbell Barton #
+# 25/03/2004, euler rotation code taken from #
+# Reevan Mckay's BVH import script v1.1 #
+# if you have any questions about this script #
+# email me ideasman@linuxmail.org #
+#===============================================#
+
+#===============================================#
+# TODO: #
+# * Create bones when importing #
+# * Make an IPO jitter removal script #
+# * Work out a better naming system #
+#===============================================#
+
+# --------------------------------------------------------------------------
+# BVH Import v0.9 by Campbell Barton (AKA Ideasman)
+# --------------------------------------------------------------------------
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# 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 *****
+# --------------------------------------------------------------------------
+
+
+import string
+import math
+import Blender
+from Blender import Window, Object, Scene, Ipo
+from Blender.Scene import Render
+
+
+# # PSYCO IS CRASHING ON MY SYSTEM
+# # Attempt to load psyco, speed things up
+# try:
+# print 'using psyco to speed up BVH importing'
+# import psyco
+# psyco.full()
+#
+# except:
+# print 'psyco is not present on this system'
+
+
+# Update as we load?
+debug = 0
+
+# Global scale facctor # sHOULD BE 1 BY DEFAULT
+scale = 1
+
+# Get the current scene.
+scn = Scene.GetCurrent()
+context = scn.getRenderingContext()
+
+# Here we store the Ipo curves in the order they load.
+channelCurves = []
+
+# Object list
+# We need this so we can loop through the objects and edit there IPO's
+# Chenging there rotation to EULER rotation
+objectList = []
+
+def MAT(m):
+ if len(m) == 3:
+ return Blender.Mathutils.Matrix(m[0], m[1], m[2])
+ elif len(m) == 4:
+ return Blender.Mathutils.Matrix(m[0], m[1], m[2], m[3])
+
+
+
+#===============================================#
+# eulerRotation: converts X, Y, Z rotation #
+# to eular Rotation. This entire function #
+# is copied from Reevan Mckay's BVH script #
+#===============================================#
+# Vars used in eular rotation funtcion
+DEG_TO_RAD = math.pi/180.0
+RAD_TO_DEG = 180.0/math.pi
+PI=3.14159
+
+def eulerRotate(x,y,z):
+ #=================================
+ def RVMatMult3 (mat1,mat2):
+ #=================================
+ mat3=[[0.0,0.0,0.0],[0.0,0.0,0.0],[0.0,0.0,0.0]]
+ for i in range(3):
+ for k in range(3):
+ for j in range(3):
+ mat3[i][k]=mat3[i][k]+mat1[i][j]*mat2[j][k]
+ mat1 = mat2 = i = k = j = None # Save memory
+ return mat3
+
+
+ #=================================
+ def RVAxisAngleToMat3 (rot4):
+ # Takes a direction vector and
+ # a rotation (in rads) and
+ # returns the rotation matrix.
+ # Graphics Gems I p. 466:
+ #=================================
+ mat3=[[0.0,0.0,0.0],[0.0,0.0,0.0],[0.0,0.0,0.0]]
+ if math.fabs(rot4[3])>0.01:
+ s=math.sin(rot4[3])
+ c=math.cos(rot4[3])
+ t=1.0-math.cos(rot4[3])
+ else:
+ s=rot4[3]
+ c=1.0
+ t=0.0
+
+ x=rot4[0]; y=rot4[1]; z=rot4[2]
+
+ mat3[0][0]=t*x*x+c
+ mat3[0][1]=t*x*y+s*z
+ mat3[0][2]=t*x*z-s*y
+
+ mat3[1][0]=t*x*y-s*z
+ mat3[1][1]=t*y*y+c
+ mat3[1][2]=t*y*z+s*x
+
+ mat3[2][0]=t*x*z+s*y
+ mat3[2][1]=t*y*z-s*x
+ mat3[2][2]=t*z*z+c
+
+ rot4 = s = c = t = x = y = z = None # Save some memory
+ return mat3
+
+ eul = [x,y,z]
+
+ for jj in range(3):
+ while eul[jj] < 0:
+ eul[jj] = eul[jj] + 360.0
+ while eul[jj] >= 360.0:
+ eul[jj] = eul[jj] - 360.0
+
+ eul[0] = eul[0]*DEG_TO_RAD
+ eul[1] = eul[1]*DEG_TO_RAD
+ eul[2] = eul[2]*DEG_TO_RAD
+
+ xmat=RVAxisAngleToMat3([1,0,0,eul[0]])
+ ymat=RVAxisAngleToMat3([0,1,0,eul[1]])
+ zmat=RVAxisAngleToMat3([0,0,1,eul[2]])
+
+ mat=[[1.0,0.0,0.0],[0.0,1.0,0.0],[0.0,0.0,1.0]]
+
+ # Standard BVH multiplication order
+ mat=RVMatMult3 (zmat,mat)
+ mat=RVMatMult3 (xmat,mat)
+ mat=RVMatMult3 (ymat,mat)
+
+
+ '''
+ # Screwy Animation Master BVH multiplcation order
+ mat=RVMatMult3 (ymat,mat)
+ mat=RVMatMult3 (xmat,mat)
+ mat=RVMatMult3 (zmat,mat)
+ '''
+ mat = MAT(mat)
+
+ eul = mat.toEuler()
+ x =- eul[0]/-10
+ y =- eul[1]/-10
+ z =- eul[2]/-10
+
+
+ eul = mat = zmat = xmat = ymat = jj = None
+ return x, y, z # Returm euler roration values.
+
+
+
+#===============================================#
+# makeJoint: Here we use the node data #
+# from the BVA file to create an empty #
+#===============================================#
+def makeJoint(name, parent, prefix, offset, channels):
+ # Make Empty, with the prefix in front of the name
+ ob = Object.New('Empty', prefix + name) # New object, ob is shorter and nicer to use.
+ scn.link(ob) # place the object in the current scene
+
+ # Offset Empty
+ ob.setLocation(offset[0]*scale, offset[1]*scale, offset[2]*scale)
+
+ # Make me a child of another empty.
+ # Vale of None will make the empty a root node (no parent)
+ if parent[-1] != None:
+ obParent = Object.Get(prefix + parent[-1]) # We use this a bit so refrence it here.
+ obParent.makeParent([ob], 0, 1) #ojbs, noninverse, 1 = not fast.
+
+ # Add Ipo's for necessary channels
+ newIpo = Ipo.New('Object', prefix + name)
+ ob.setIpo(newIpo)
+ for channelType in channels:
+ if channelType == 'Xposition':
+ newIpo.addCurve('LocX')
+ newIpo.getCurve('LocX').setInterpolation('Linear')
+ if channelType == 'Yposition':
+ newIpo.addCurve('LocY')
+ newIpo.getCurve('LocY').setInterpolation('Linear')
+ if channelType == 'Zposition':
+ newIpo.addCurve('LocZ')
+ newIpo.getCurve('LocZ').setInterpolation('Linear')
+
+ if channelType == 'Zrotation':
+ newIpo.addCurve('RotZ')
+ newIpo.getCurve('RotZ').setInterpolation('Linear')
+ if channelType == 'Yrotation':
+ newIpo.addCurve('RotY')
+ newIpo.getCurve('RotY').setInterpolation('Linear')
+ if channelType == 'Xrotation':
+ newIpo.addCurve('RotX')
+ newIpo.getCurve('RotX').setInterpolation('Linear')
+
+ # Add to object list
+ objectList.append(ob)
+
+ ob = newIpo = opParent = None
+
+ # Redraw if debugging
+ if debug: Blender.Redraw()
+
+
+#===============================================#
+# makeEnd: Here we make an end node #
+# This is needed when adding the last bone #
+#===============================================#
+def makeEnd(parent, prefix, offset):
+ # Make Empty, with the prefix in front of the name, end nodes have no name so call it its parents name+'_end'
+ ob = Object.New('Empty', prefix + parent[-1] + '_end') # New object, ob is shorter and nicer to use.
+ scn.link(ob)
+
+ # Dont check for a parent, an end node MUST have a parent
+ obParent = Object.Get(prefix + parent[-1]) # We use this a bit so refrence it here.
+ obParent.makeParent([ob], 0, 1) #ojbs, noninverse, 1 = not fast.
+
+ # Offset Empty
+ ob.setLocation(offset[0]*scale, offset[1]*scale, offset[2]*scale)
+
+ # Redraw if debugging
+ if debug: Blender.Redraw()
+
+
+
+#===============================================#
+# MAIN FUNCTION - All things are done from here #
+#===============================================#
+def loadBVH(filename):
+ print ''
+ print 'BVH Importer 1.0 by Campbell Barton (Ideasman) - ideasman@linuxmail.org'
+
+ # File loading stuff
+ # Open the file for importing
+ file = open(filename, 'r')
+ fileData = file.readlines()
+ # Make a list of lines
+ lines = []
+ for fileLine in fileData:
+ newLine = string.split(fileLine)
+ if newLine != []:
+ lines.append(string.split(fileLine))
+ fileData = None
+ # End file loading code
+
+ # Call object names with this prefix, mainly for scenes with multiple BVH's - Can imagine most partr names are the same
+ # So in future
+ #prefix = str(len(lines)) + '_'
+
+ prefix = '_'
+
+ # Create Hirachy as empties
+ if lines[0][0] == 'HIERARCHY':
+ print 'Importing the BVH Hierarchy for:', filename
+ else:
+ return 'ERROR: This is not a BVH file'
+
+ # A liniar list of ancestors to keep track of a single objects heratage
+ # at any one time, this is appended and removed, dosent store tree- just a liniar list.
+ # ZERO is a place holder that means we are a root node. (no parents)
+ parent = [None]
+
+ #channelList [(<objectName>, [channelType1, channelType2...]), (<objectName>, [channelType1, channelType2...)]
+ channelList = []
+ channelIndex = -1
+
+ lineIdx = 1 # An index for the file.
+ while lineIdx < len(lines) -1:
+ #...
+ if lines[lineIdx][0] == 'ROOT' or lines[lineIdx][0] == 'JOINT':
+ # MAY NEED TO SUPPORT MULTIPLE ROOT's HERE!!!, Still unsure weather multiple roots are possible.??
+
+ print len(parent) * ' ' + 'node:',lines[lineIdx][1],' parent:',parent[-1]
+
+ name = lines[lineIdx][1]
+ lineIdx += 2 # Incriment to the next line (Offset)
+ offset = ( eval(lines[lineIdx][1]), eval(lines[lineIdx][2]), eval(lines[lineIdx][3]) )
+ lineIdx += 1 # Incriment to the next line (Channels)
+
+ # newChannel[Xposition, Yposition, Zposition, Xrotation, Yrotation, Zrotation]
+ # newChannel has Indecies to the motiondata,
+ # -1 refers to the last value that will be added on loading at a value of zero
+ # We'll add a zero value onto the end of the MotionDATA so this is always refers to a value.
+ newChannel = [-1, -1, -1, -1, -1, -1]
+ for channel in lines[lineIdx][2:]:
+ channelIndex += 1 # So the index points to the right channel
+ if channel == 'Xposition':
+ newChannel[0] = channelIndex
+ elif channel == 'Yposition':
+ newChannel[1] = channelIndex
+ elif channel == 'Zposition':
+ newChannel[2] = channelIndex
+ elif channel == 'Xrotation':
+ newChannel[3] = channelIndex
+ elif channel == 'Yrotation':
+ newChannel[4] = channelIndex
+ elif channel == 'Zrotation':
+ newChannel[5] = channelIndex
+
+ channelList.append(newChannel)
+
+ channels = lines[lineIdx][2:]
+
+ # Call funtion that uses the gatrhered data to make an empty.
+ makeJoint(name, parent, prefix, offset, channels)
+
+ # If we have another child then we can call ourselves a parent, else
+ parent.append(name)
+
+ # Account for an end node
+ if lines[lineIdx][0] == 'End' and lines[lineIdx][1] == 'Site': # There is somtimes a name afetr 'End Site' but we will ignore it.
+ lineIdx += 2 # Incriment to the next line (Offset)
+ offset = ( eval(lines[lineIdx][1]), eval(lines[lineIdx][2]), eval(lines[lineIdx][3]) )
+ makeEnd(parent, prefix, offset)
+
+ # Just so we can remove the Parents in a uniform way- End end never has kids
+ # so this is a placeholder
+ parent.append(None)
+
+ if lines[lineIdx] == ['}']:
+ parent = parent[:-1] # Remove the last item
+
+
+ #=============================================#
+ # BVH Structure loaded, Now import motion #
+ #=============================================#
+ if lines[lineIdx] == ['MOTION']:
+ print '\nImporting motion data'
+ lineIdx += 3 # Set the cursor to the forst frame
+
+ #=============================================#
+ # Loop through frames, each line a frame #
+ #=============================================#
+ currentFrame = 1
+ print 'frames: ',
+
+
+ #=============================================#
+ # Add a ZERO keyframe, this keeps the rig #
+ # so when we export we know where all the #
+ # joints start from #
+ #=============================================#
+ obIdx = 0
+ while obIdx < len(objectList) -1:
+ if channelList[obIdx][0] != -1:
+ objectList[obIdx].getIpo().getCurve('LocX').addBezier((currentFrame,0))
+ if channelList[obIdx][1] != -1:
+ objectList[obIdx].getIpo().getCurve('LocY').addBezier((currentFrame,0))
+ if channelList[obIdx][2] != -1:
+ objectList[obIdx].getIpo().getCurve('LocZ').addBezier((currentFrame,0))
+ if channelList[obIdx][3] != '-1' or channelList[obIdx][4] != '-1' or channelList[obIdx][5] != '-1':
+ objectList[obIdx].getIpo().getCurve('RotX').addBezier((currentFrame,0))
+ objectList[obIdx].getIpo().getCurve('RotY').addBezier((currentFrame,0))
+ objectList[obIdx].getIpo().getCurve('RotZ').addBezier((currentFrame,0))
+ obIdx += 1
+
+ while lineIdx < len(lines):
+
+ # Exit loop if we are past the motiondata.
+ # Some BVH's have extra tags like 'CONSTRAINTS and MOTIONTAGS'
+ # I dont know what they do and I dont care, they'll be ignored here.
+ if len(lines[lineIdx]) < len(objectList):
+ print '...ending on unknown tags'
+ break
+
+
+ currentFrame += 1 # Incriment to next frame
+
+ #=============================================#
+ # Import motion data and assign it to an IPO #
+ #=============================================#
+ lines[lineIdx].append('0') # Use this as a dummy var for objects that dont have a rotate channel.
+ obIdx = 0
+ if debug: Blender.Redraw()
+ while obIdx < len(objectList) -1:
+ if channelList[obIdx][0] != -1:
+ objectList[obIdx].getIpo().getCurve('LocX').addBezier((currentFrame, scale * eval(lines[lineIdx][channelList[obIdx][0]])))
+ if channelList[obIdx][1] != -1:
+ objectList[obIdx].getIpo().getCurve('LocY').addBezier((currentFrame, scale * eval(lines[lineIdx][channelList[obIdx][1]])))
+ if channelList[obIdx][2] != -1:
+ objectList[obIdx].getIpo().getCurve('LocZ').addBezier((currentFrame, scale * eval(lines[lineIdx][channelList[obIdx][2]])))
+
+ if channelList[obIdx][3] != '-1' or channelList[obIdx][4] != '-1' or channelList[obIdx][5] != '-1':
+ x, y, z = eulerRotate(eval(lines[lineIdx][channelList[obIdx][3]]), eval(lines[lineIdx][channelList[obIdx][4]]), eval(lines[lineIdx][channelList[obIdx][5]]))
+ objectList[obIdx].getIpo().getCurve('RotX').addBezier((currentFrame, x))
+ objectList[obIdx].getIpo().getCurve('RotY').addBezier((currentFrame, y))
+ objectList[obIdx].getIpo().getCurve('RotZ').addBezier((currentFrame, z))
+ obIdx += 1
+ # Done importing motion data #
+
+ lines[lineIdx] = None # Scrap old motion data, save some memory?
+ lineIdx += 1
+ # We have finished now
+ print currentFrame, 'done.'
+
+ # No point in looking further, when this loop is done
+ # There is nothine else left to do
+ print 'Imported ', currentFrame, ' frames'
+ break
+
+ # Main file loop
+ lineIdx += 1
+
+Blender.Window.FileSelector(loadBVH) \ No newline at end of file