Updated bvh importer. tested on over 100 bvh files.

* Modified to use Mathutils for matrix math,
* Fixed possible joint naming bug,
* Imports BVH's with bad EOF gracefully
* Fixed duplicate joint names, make them unique
* Use \r as well as \n for newlines
* Added suppot for nodes with 0 motion channels
* Rotation IPOs never cross more then 180d
   fixes sub frame tweening and time scaling
* 5x overall speedup.
This commit is contained in:
Campbell Barton 2005-12-06 03:53:35 +00:00
parent 2d19c4f208
commit 9497b6dfb6

@ -2,14 +2,14 @@
"""
Name: 'Motion Capture (.bvh)...'
Blender: 236
Blender: 239
Group: 'Import'
Tip: 'Import a (.bvh) motion capture file'
"""
__author__ = "Campbell Barton"
__url__ = ("blender", "elysiun", "http://jmsoler.free.fr/util/blenderfile/py/bvh_import.py")
__version__ = "1.0.2 04/12/28"
__url__ = ("blender", "elysiun")
__version__ = "1.0.4 05/12/04"
__bpydoc__ = """\
This script imports BVH motion capture data to Blender.
@ -29,6 +29,26 @@ Empties created by this importer, it's in the Scripts window -> Scripts -> Anima
# $Id$
#
#===============================================#
# BVH Import script 1.05 patched by Campbell #
# Modified to use Mathutils for matrix math, #
# Fixed possible joint naming bug, #
# Imports BVH's with bad EOF gracefully #
# Fixed duplicate joint names, make them unique #
# Use \r as well as \n for newlines #
# Added suppot for nodes with 0 motion channels #
# Rotation IPOs never cross more then 180d #
# fixes sub frame tweening and time scaling #
# 5x overall speedup. #
# 06/12/2005, #
#===============================================#
#===============================================#
# BVH Import script 1.04 patched by jms #
# Small modif for blender 2.40 #
# 04/12/2005, #
#===============================================#
#===============================================#
# BVH Import script 1.03 patched by Campbell #
# Small optimizations and scale input #
@ -45,8 +65,8 @@ Empties created by this importer, it's in the Scripts window -> Scripts -> Anima
# 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 #
# if you have any questions about this scrip. #
# email me cbarton@metavr.com #
#===============================================#
#===============================================#
@ -57,7 +77,7 @@ Empties created by this importer, it's in the Scripts window -> Scripts -> Anima
#===============================================#
# --------------------------------------------------------------------------
# BVH Import v0.9 by Campbell Barton (AKA Ideasman)
# BVH Import v1.05 by Campbell Barton (AKA Ideasman)
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
@ -78,191 +98,117 @@ Empties created by this importer, it's in the Scripts window -> Scripts -> Anima
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
import string
import math
import Blender
from Blender import Window, Object, Scene, Ipo, Draw
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'
# Attempt to load psyco, speed things up
try:
import psyco
psyco.full()
print 'using psyco to speed up BVH importing'
except:
#print 'psyco is not present on this system'
pass
# Default scale
scale = 0.01
# Update as we load?
debug = 0
# Get the current scene.
scn = Scene.GetCurrent()
context = scn.getRenderingContext()
def main():
global scale
scale = None
# Here we store the Ipo curves in the order they load.
channelCurves = []
# Update as we load?
debug = 0
# 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 getScale():
def getScale():
return Draw.PupFloatInput('BVH Scale: ', 0.01, 0.001, 10.0, 0.1, 3)
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]
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
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
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):
#===============================================#
# MAIN FUNCTION - All things are done from here #
#===============================================#
def loadBVH(filename):
global scale
# 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
print '\nBVH Importer 1.05 by Campbell Barton (Ideasman) - cbarton@metavr.com'
# Offset Empty
ob.setLocation(offset[0]*scale, offset[1]*scale, offset[2]*scale)
objectCurveMapping = {}
objectNameMapping = {}
objectMotiondataMapping = {}
# 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 = []
if scale == None:
tempscale = getScale()
if tempscale:
scale = tempscale
else:
scale = 0.01
Window.WaitCursor(1)
# Unique names, dont reuse any of these names.
uniqueObNames = [ob.name for ob in Object.Get()]
# FUNCTIONS ====================================#
def getUniqueObName(name):
i = 0
newname = name[:min(len(name), 12)] # Concatinate to 12 chars
while newname in uniqueObNames:
newname = name + str(i)
i+=1
return newname
# Change the order rotation is applied.
RotationMatrix = Blender.Mathutils.RotationMatrix
MATRIX_IDENTITY_3x3 = Blender.Mathutils.Matrix([1.0,0.0,0.0],[0.0,1.0,0.0],[0.0,0.0,1.0])
def eulerRotate(x,y,z):
x,y,z = x%360,y%360,z%360 # Clamp all values between 0 and 360, values outside this raise an error.
xmat = RotationMatrix(x,3,'x')
ymat = RotationMatrix(y,3,'y')
zmat = RotationMatrix(z,3,'z')
# Standard BVH multiplication order, apply the rotation in the order Z,X,Y
return (ymat*(xmat * (zmat * MATRIX_IDENTITY_3x3))).toEuler()
currentFrame = 1 # Set the initial frame to import all data to.
#===============================================#
# makeJoint: Here we use the node data #
# from the BVA file to create an empty #
#===============================================#
BVH2BLEND_TX_NAME = {'Xposition':'LocX','Yposition':'LocY','Zposition':'LocZ','Xrotation':'RotX','Yrotation':'RotY','Zrotation':'RotZ'}
def makeJoint(name, parent, offset, channels):
ob = Object.New('Empty', name) # New object, ob is shorter and nicer to use.
objectNameMapping[name] = ob
scn.link(ob) # place the object in the current scene
ob.sel = 1
# 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.
if parent[-1]: # != None
obParent = objectNameMapping[parent[-1]] # We use this a bit so refrence it here.
obParent.makeParent([ob], 1, 0) #ojbs, noninverse, 1 = not fast.
# Offset Empty from BVH's initial joint location.
ob.setLocation(offset[0]*scale, offset[1]*scale, offset[2]*scale)
# Add Ipo's for necessary channels
newIpo = Ipo.New('Object', prefix + name)
newIpo = Ipo.New('Object', name)
ob.setIpo(newIpo)
obname = ob.name
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')
channelType = BVH2BLEND_TX_NAME[channelType]
curve = newIpo.addCurve(channelType)
curve.setInterpolation('Linear')
objectCurveMapping[(obname, channelType)] = curve
# Add to object list
objectList.append(ob)
@ -271,70 +217,56 @@ def makeJoint(name, parent, prefix, offset, channels):
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.
#===============================================#
# makeEnd: Here we make an end node #
# This is needed when adding the last bone #
#===============================================#
def makeEnd(parent, offset):
new_name = parent[-1] + '_end'
ob = Object.New('Empty', new_name) # New object, ob is shorter and nicer to use.
objectNameMapping[new_name] = ob
scn.link(ob)
ob.sel = 1
# 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.
obParent = objectNameMapping[parent[-1]] # We use this a bit so refrence it here.
obParent.makeParent([ob], 1, 0) #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()
# END FUNCTION DEFINITIONS ====================================#
#===============================================#
# MAIN FUNCTION - All things are done from here #
#===============================================#
def loadBVH(filename):
global scale
print ''
print 'BVH Importer 1.0 by Campbell Barton (Ideasman) - ideasman@linuxmail.org'
alpha='abcdefghijklmnopqrstuvewxyz'
ALPHA=alpha+alpha.upper()
ALPHA+=' 0123456789+-{}. '
time1 = Blender.sys.time()
tmpScale = getScale()
if tmpScale != None:
scale = tmpScale
# Get the current scene.
scn = Scene.GetCurrent()
#context = scn.getRenderingContext()
# DeSelect All
for ob in scn.getChildren():
ob.sel = 0
# 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:
fileLine=fileLine.replace('..','.')
newLine = string.split(fileLine)
if newLine != []:
t=[]
for n in newLine:
for n0 in n:
if n0 not in ALPHA:
n=n.replace(n0,'')
t.append(n)
lines.append(t)
# Seperate into a list of lists, each line a list of words.
lines = file.readlines()
# Non standard carrage returns?
if len(lines) == 1:
lines = lines[0].split('\r')
del fileData
# Split by whitespace.
lines =[ll for ll in [ [w for w in l.split() if w != '\n' ] for l in lines] if ll]
# 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':
@ -347,33 +279,35 @@ def loadBVH(filename):
# ZERO is a place holder that means we are a root node. (no parents)
parent = [None]
#channelList [(<objectName>, [channelType1, channelType2...]), (<objectName>, [channelType1, channelType2...)]
#channelList, sync with objectList: [[channelType1, channelType2...], [channelType1, channelType2...)]
channelList = []
channelIndex = -1
lineIdx = 1 # An index for the file.
lineIdx = 0 # An index for the file.
while lineIdx < len(lines) -1:
#...
if lines[lineIdx][0] == 'ROOT' or lines[lineIdx][0] == 'JOINT':
if lines[lineIdx][0] == 'JOINT' and len(lines[lineIdx])>2:
for j in range(2,len(lines[lineIdx])) :
lines[lineIdx][1]+='_'+lines[lineIdx][j]
# Join spaces into 1 word with underscores joining it.
if len(lines[lineIdx]) > 2:
lines[lineIdx][1] = '_'.join(lines[lineIdx][1:])
lines[lineIdx] = lines[lineIdx][:2]
# 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]
print lineIdx
name = lines[lineIdx][1]
print name,lines[lineIdx+1],lines[lineIdx+2]
# Make sure the names are unique- Object names will match joint names exactly and both will be unique.
name = getUniqueObName(lines[lineIdx][1])
uniqueObNames.append(name)
print '%snode: %s, parent: %s' % (len(parent) * ' ', name, parent[-1])
lineIdx += 2 # Incriment to the next line (Offset)
offset = ( float(lines[lineIdx][1]), float(lines[lineIdx][2]), float(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
# newChannel references indecies to the motiondata,
# if not assigned then -1 refers to the last value that will be added on loading at a value of zero, this is appended
# 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:]:
@ -396,64 +330,70 @@ def loadBVH(filename):
channels = lines[lineIdx][2:]
# Call funtion that uses the gatrhered data to make an empty.
makeJoint(name, parent, prefix, offset, channels)
makeJoint(name, parent, 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.
if lines[lineIdx][0] == 'End' and lines[lineIdx][1] == 'Site': # There is somtimes a name after 'End Site' but we will ignore it.
lineIdx += 2 # Incriment to the next line (Offset)
offset = ( float(lines[lineIdx][1]), float(lines[lineIdx][2]), float(lines[lineIdx][3]) )
makeEnd(parent, prefix, offset)
makeEnd(parent, 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
if len(lines[lineIdx]) == 1 and lines[lineIdx][0] == '}': # == ['}']
parent.pop() # Remove the last item
#=============================================#
# BVH Structure loaded, Now import motion #
#=============================================#
if lines[lineIdx] == ['MOTION']:
if len(lines[lineIdx]) == 1 and lines[lineIdx][0] == '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: ',
lineIdx += 3 # Set the cursor to the first frame
#=============================================#
# 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
for obIdx, ob in enumerate(objectList):
obname = ob.name
if channelList[obIdx][0] != -1:
objectCurveMapping[obname, 'LocX'].addBezier((currentFrame,0))
objectMotiondataMapping[obname, 'LocX'] = []
if channelList[obIdx][1] != -1:
objectCurveMapping[obname, 'LocY'].addBezier((currentFrame,0))
objectMotiondataMapping[obname, 'LocY'] = []
if channelList[obIdx][2] != -1:
objectCurveMapping[obname, 'LocZ'].addBezier((currentFrame,0))
objectMotiondataMapping[obname, 'LocZ'] = []
if\
channelList[obIdx][3] != -1 or\
channelList[obIdx][4] != -1 or\
channelList[obIdx][5] != -1:
objectMotiondataMapping[obname, 'RotX'] = []
objectMotiondataMapping[obname, 'RotY'] = []
objectMotiondataMapping[obname, 'RotZ'] = []
#=============================================#
# Loop through frames, each line a frame #
#=============================================#
MOTION_DATA_LINE_LEN = len(lines[lineIdx])
while lineIdx < len(lines):
line = lines[lineIdx]
if MOTION_DATA_LINE_LEN != len(line):
print 'ERROR: Incomplete motion data on line %i, finishing import.' % lineIdx
break
# 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):
if len(line) < len(objectList):
print '...ending on unknown tags'
break
@ -463,62 +403,95 @@ def loadBVH(filename):
#=============================================#
# 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
line.append(0.0) # Use this as a dummy var for objects that dont have a loc/rotate channel.
if debug: Blender.Redraw()
while obIdx < len(objectList) -1:
for obIdx, ob in enumerate(objectList):
obname = ob.name
obChannel = channelList[obIdx]
if channelList[obIdx][0] != -1:
VAL0=lines[lineIdx][channelList[obIdx][0]]
if VAL0.find('.')==-1:
VAL0=VAL0[:len(VAL0)-6]+'.'+VAL0[-6:]
objectList[obIdx].getIpo().getCurve('LocX').addBezier((currentFrame, scale * float(VAL0)))
objectMotiondataMapping[obname, 'LocX'].append((currentFrame, scale * float( line[obChannel[0]] )))
if channelList[obIdx][1] != -1:
VAL1=lines[lineIdx][channelList[obIdx][1]]
if VAL1.find('.')==-1:
VAL1=VAL1[:len(VAL1)-6]+'.'+VAL1[-6:]
objectList[obIdx].getIpo().getCurve('LocY').addBezier((currentFrame, scale * float(VAL1)))
objectMotiondataMapping[obname, 'LocY'].append((currentFrame, scale * float( line[obChannel[1]] )))
if channelList[obIdx][2] != -1:
VAL2=lines[lineIdx][channelList[obIdx][2]]
if VAL2.find('.')==-1:
VAL2=VAL2[:len(VAL2)-6]+'.'+VAL2[-6:]
objectList[obIdx].getIpo().getCurve('LocZ').addBezier((currentFrame, scale * float(VAL2)))
objectMotiondataMapping[obname, 'LocZ'].append((currentFrame, scale * float( line[obChannel[2]] )))
if channelList[obIdx][3] != '-1' or channelList[obIdx][4] != '-1' or channelList[obIdx][5] != '-1':
VAL3=lines[lineIdx][channelList[obIdx][3]]
if VAL3.find('.')==-1:
VAL3=VAL3[:len(VAL3)-6]+'.'+VAL3[-6:]
if obChannel[3] != -1 or obChannel[4] != -1 or obChannel[5] != -1:
x, y, z = eulerRotate(float( line[obChannel[3]] ), float( line[obChannel[4]] ), float( line[obChannel[5]] ))
x,y,z = x/10.0, y/10.0, z/10.0 # For IPO's 36 is 360d
motionMappingRotX = objectMotiondataMapping[obname, 'RotX']
motionMappingRotY = objectMotiondataMapping[obname, 'RotY']
motionMappingRotZ = objectMotiondataMapping[obname, 'RotZ']
VAL4=lines[lineIdx][channelList[obIdx][4]]
if VAL4.find('.')==-1:
VAL4=VAL4[:len(VAL4)-6]+'.'+VAL4[-6:]
# Make interpolation not cross between 180d, thjis fixes sub frame interpolation and time scaling.
# Will go from (355d to 365d) rather then to (355d to 5d) - inbetween these 2 there will now be a correct interpolation.
if len(motionMappingRotX) > 1:
while (motionMappingRotX[-1][1] - x) > 18: x+=36
while (motionMappingRotX[-1][1] - x) < -18: x-=36
VAL5=lines[lineIdx][channelList[obIdx][5]]
if VAL5.find('.')==-1:
VAL5=VAL5[:len(VAL5)-6]+'.'+VAL5[-6:]
while (motionMappingRotY[-1][1] - y) > 18: y+=36
while (motionMappingRotY[-1][1] - y) < -18: y-=36
x, y, z = eulerRotate(float(VAL3), float(VAL4), float(VAL5))
while (motionMappingRotZ[-1][1] - z) > 18: z+=36
while (motionMappingRotZ[-1][1] - z) < -18: z-=36
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
motionMappingRotX.append((currentFrame, x))
motionMappingRotY.append((currentFrame, y))
motionMappingRotZ.append((currentFrame, z))
# Done importing motion data #
# lines[lineIdx] = None # Scrap old motion data, save some memory?
lineIdx += 1
# We have finished now
print currentFrame, 'done.'
#=======================================#
# Now Write the motion to the IPO's #
#=======================================#
for key, motion_data in objectMotiondataMapping.iteritems():
# Strip the motion data where all the points have the same falue.
i = len(motion_data) -2
while i > 0 and len(motion_data) > 2:
if motion_data[i][1] == motion_data[i-1][1] == motion_data[i+1][1]:
motion_data.pop(i)
i-=1
# Done stripping.
obname, tx_type = key
curve = objectCurveMapping[obname, tx_type]
for point_data in motion_data:
curve.addBezier( point_data )
# Imported motion to an IPO
# 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
print "bvh import time: ", Blender.sys.time() - time1
Blender.Window.FileSelector(loadBVH, "Import BVH")
print 'bvh import time for %i frames: %.6f' % (currentFrame, Blender.sys.time() - time1)
Window.RedrawAll()
Window.WaitCursor(0)
Blender.Window.FileSelector(loadBVH, "Import BVH")
#=============#
# TESTING #
#=============#
'''
#loadBVH('/metavr/mocap/bvh/boxer.bvh')
#loadBVH('/metavr/mocap/bvh/dg-306-g.bvh') # Incompleate EOF
#loadBVH('/metavr/mocap/bvh/wa8lk.bvh') # duplicate joint names, \r line endings.
#loadBVH('/metavr/mocap/bvh/walk4.bvh') # 0 channels
scale = 0.01
import os
DIR = '/metavr/mocap/bvh/'
for f in os.listdir(DIR):
if f.endswith('.bvh'):
s = Scene.New(f)
s.makeCurrent()
loadBVH(DIR + f)
'''
if __name__ == '__main__':
main()