BVH Export updated for 2.4x, also small updates in many areas.
This commit is contained in:
@@ -9,7 +9,7 @@ Tip: 'Export a (.bvh) motion capture file'
|
||||
|
||||
__author__ = "Campbell Barton"
|
||||
__url__ = ("blender", "elysiun")
|
||||
__version__ = "1.0 03/30/04"
|
||||
__version__ = "1.1 12/16/05"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script exports animation data to BVH motion capture file format.
|
||||
@@ -30,12 +30,11 @@ Notes:<br>
|
||||
# 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 #
|
||||
# #
|
||||
# email me cbarton@metavr.com #
|
||||
#===============================================#
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# BVH Export v0.9 by Campbell Barton (AKA Ideasman)
|
||||
# BVH Export v1.1 by Campbell Barton (AKA Ideasman)
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
@@ -46,12 +45,12 @@ Notes:<br>
|
||||
#
|
||||
# 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
|
||||
# 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.
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
# --------------------------------------------------------------------------
|
||||
@@ -59,348 +58,328 @@ Notes:<br>
|
||||
import Blender
|
||||
from Blender import Scene, Object
|
||||
import math
|
||||
time = Blender.sys.time
|
||||
from math import *
|
||||
|
||||
# Get the current scene.
|
||||
scn = Scene.GetCurrent()
|
||||
context = scn.getRenderingContext()
|
||||
|
||||
frameRate = 0.3333 # 0.04 = 25fps
|
||||
scale = 1
|
||||
frameRate = 1.0/context.framesPerSec() # 0.04 = 25fps
|
||||
scale = 1.0
|
||||
|
||||
indent = ' ' # 2 space indent per object
|
||||
indent = '\t' # 2 space indent per object
|
||||
prefixDelimiter = '_'
|
||||
|
||||
# Vars used in eular rotation funtcion
|
||||
RAD_TO_DEG = 180.0/3.14159265359
|
||||
|
||||
DEG_TO_RAD = math.pi/180.0
|
||||
|
||||
|
||||
#====================================================#
|
||||
# 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
|
||||
children = [] # We'll assume none.
|
||||
for child in Object.Get():
|
||||
if child.parent == parent:
|
||||
children.append( child )
|
||||
return children
|
||||
|
||||
#====================================================#
|
||||
# MESSY BUT WORKS: Make a string that shows the #
|
||||
# hierarchy as a list and then eval it #
|
||||
# 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
|
||||
hierarchy = '%s["%s",' % (hierarchy, root.name)
|
||||
for child in getChildren(root):
|
||||
hierarchy = getHierarchy(child, hierarchy)
|
||||
hierarchy = '%s],' % hierarchy
|
||||
return hierarchy
|
||||
|
||||
|
||||
#====================================================#
|
||||
# Strips the prefix off the name before writing #
|
||||
# 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) + ' '
|
||||
|
||||
|
||||
|
||||
# WARNING!!! Special case for a custom RIG for output
|
||||
# for MetaVR's HPX compatable RIG.
|
||||
# print 'stripname', name[0:10]
|
||||
if name.lower().startswith('transform('):
|
||||
name = name[10:].split(prefixDelimiter)[0]
|
||||
return name.split('_')[0]
|
||||
|
||||
|
||||
#====================================================#
|
||||
# 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
|
||||
def getNodeData(nodeOb):
|
||||
ob = nodeOb
|
||||
obipo = ob.getIpo()
|
||||
# Get real location
|
||||
offset = [o*scale for o in ob.getLocation()]
|
||||
|
||||
#=========================#
|
||||
# Test for X/Y/Z IPO's #
|
||||
#=========================#
|
||||
|
||||
# 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.
|
||||
|
||||
# DUMMY channels xloc, yloc, zloc, xrot, yrot, zrot
|
||||
# [<bool>, <bool>, <bool>, <bool>, <bool>, <bool>]
|
||||
channels = [0,0,0,0,0,0] # xloc,yloc,zloc,xrot,yrot,zrot
|
||||
if obipo != None: # Do have an IPO, checkout which curves are in use.
|
||||
# Assume the rot's/loc's dont exist until they proven they do.
|
||||
if obipo.getCurve('LocX') != None:
|
||||
channels[0] = 1
|
||||
if obipo.getCurve('LocY') != None:
|
||||
channels[1] = 1
|
||||
if obipo.getCurve('LocZ') != None:
|
||||
channels[2] = 1
|
||||
|
||||
# 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 or \
|
||||
obipo.getCurve('RotY') != None or \
|
||||
obipo.getCurve('RotZ') != None:
|
||||
channels[3] = channels[4] = channels[5] = 1
|
||||
#print ob, channels
|
||||
return offset, channels
|
||||
|
||||
|
||||
#====================================================#
|
||||
# Return the BVH hierarchy to a file from a list #
|
||||
# Writes the BVH hierarchy to a file #
|
||||
# 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 #
|
||||
# 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 #
|
||||
#================#
|
||||
def hierarchy2bvh(file, hierarchy, level, channelList, nodeObjectList):
|
||||
nodeName = hierarchy[0]
|
||||
ob = Object.Get(nodeName)
|
||||
'''
|
||||
obipo = ob.getIpo()
|
||||
if obipo != None:
|
||||
obcurves = obipo.getCurves()
|
||||
else:
|
||||
obcurves = None
|
||||
'''
|
||||
#============#
|
||||
# JOINT NAME #
|
||||
#============#
|
||||
file.write(level * indent)
|
||||
if level == 0:
|
||||
# Add object to nodeObjectList
|
||||
#nodeObjectList.append( (ob, obipo, obcurves) )
|
||||
nodeObjectList.append( ob )
|
||||
file.write( 'ROOT %s\n' % stripName(nodeName) )
|
||||
# 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:
|
||||
file.write( 'End Site\n' )
|
||||
# Ok This is a normal joint
|
||||
else:
|
||||
# Add object to nodeObjectList
|
||||
#nodeObjectList.append((ob, obipo, obcurves))
|
||||
nodeObjectList.append( ob )
|
||||
file.write( 'JOINT %s\n' % stripName(nodeName) )
|
||||
#================#
|
||||
# END JOINT NAME #
|
||||
#================#
|
||||
|
||||
# Indent again, this line is just for the brackets
|
||||
file.write( '%s{\n' % (level * indent) )
|
||||
|
||||
# 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(ob)
|
||||
|
||||
#============#
|
||||
# Offset #
|
||||
#============#
|
||||
file.write( '%sOFFSET %.6f %.6f %.6f\n' %\
|
||||
(level*indent, scale*offset[0], scale*offset[1], scale*offset[2]) )
|
||||
|
||||
#============#
|
||||
# Channels #
|
||||
#============#
|
||||
if len(hierarchy) != 1:
|
||||
# Channels, remember who is where so when we write motiondata
|
||||
file.write('%sCHANNELS %i ' % (level*indent, len([c for c in channels if c ==1]) ))
|
||||
if channels[0]:
|
||||
file.write('Xposition ')
|
||||
channelList.append([len(nodeObjectList)-1, 0])
|
||||
if channels[1]:
|
||||
file.write('Yposition ')
|
||||
channelList.append([len(nodeObjectList)-1, 1])
|
||||
if channels[2]:
|
||||
file.write('Zposition ')
|
||||
channelList.append([len(nodeObjectList)-1, 2])
|
||||
if channels[5]:
|
||||
file.write('Zrotation ')
|
||||
channelList.append([len(nodeObjectList)-1, 5])
|
||||
if channels[3]:
|
||||
file.write('Xrotation ')
|
||||
channelList.append([len(nodeObjectList)-1, 3])
|
||||
if channels[4]:
|
||||
file.write('Yrotation ')
|
||||
channelList.append([len(nodeObjectList)-1, 4])
|
||||
file.write('\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
|
||||
# Loop through children if any and run this function (recursively)
|
||||
for hierarchyIdx in range(len(hierarchy)-1):
|
||||
level = hierarchy2bvh(file, hierarchy[hierarchyIdx+1], level, channelList, nodeObjectList)
|
||||
# Unindent
|
||||
level -= 1
|
||||
file.write('%s}\n' % (level * indent))
|
||||
|
||||
return level
|
||||
|
||||
# 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)
|
||||
'''
|
||||
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)
|
||||
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
|
||||
# this seems to be necessary - not sure why (right/left-handed coordinates?)
|
||||
# x = -x # x is negative, see below.
|
||||
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
|
||||
|
||||
''' # UNUSED, JUST GET OBJECT LOC/ROT
|
||||
def getIpoLocation(object, obipo, curves, frame):
|
||||
x = y = z = rx = ry = rz =0
|
||||
if obipo:
|
||||
for i in range(obipo.getNcurves()):
|
||||
if curves[i].getName() =='LocX':
|
||||
x = obipo.EvaluateCurveOn(i,frame)
|
||||
elif curves[i].getName() =='LocY':
|
||||
y = obipo.EvaluateCurveOn(i,frame)
|
||||
elif curves[i].getName() =='LocZ':
|
||||
z = obipo.EvaluateCurveOn(i,frame)
|
||||
elif curves[i].getName() =='RotX':
|
||||
rx = obipo.EvaluateCurveOn(i,frame)
|
||||
elif curves[i].getName() =='RotY':
|
||||
ry = obipo.EvaluateCurveOn(i,frame)
|
||||
elif curves[i].getName() =='RotZ':
|
||||
rz = obipo.EvaluateCurveOn(i,frame)
|
||||
return x, y, z, rx*10*DEG_TO_RAD, ry*10*DEG_TO_RAD, rz*10*DEG_TO_RAD
|
||||
'''
|
||||
|
||||
#====================================================#
|
||||
# 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 motion2bvh(file, frame, chennelList, nodeObjectList):
|
||||
for chIdx in chennelList:
|
||||
#ob, obipo, obcurves = nodeObjectList[chIdx[0]]
|
||||
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)
|
||||
|
||||
# Location
|
||||
xloc, yloc, zloc = ob.matrixLocal[3][:3]
|
||||
|
||||
# Using regular Locations stuffs upIPO locations stuffs up
|
||||
# Get IPO locations instead
|
||||
#xloc, yloc, zloc, x, y, z = getIpoLocation(ob, obipo, obcurves, frame)
|
||||
# Convert the rotation from ZYX order to ZXY order
|
||||
#x, y, z = ZYXToZXY(x, y, z)
|
||||
|
||||
|
||||
# WARNING non standard Location
|
||||
# xloc, zloc, yloc = -xloc, yloc, zloc
|
||||
|
||||
if chType == 0:
|
||||
file.write('%.6f ' % (scale * xloc))
|
||||
if chType == 1:
|
||||
file.write('%.6f ' % (scale * yloc))
|
||||
if chType == 2:
|
||||
file.write('%.6f ' % (scale * zloc))
|
||||
if chType == 3:
|
||||
file.write('%.6f ' % x)
|
||||
if chType == 4:
|
||||
file.write('%.6f ' % y)
|
||||
if chType == 5:
|
||||
file.write('%.6f ' % z)
|
||||
file.write('\n')
|
||||
|
||||
|
||||
def saveBVH(filename):
|
||||
|
||||
if filename.find('.bvh', -4) <= 0: filename += '.bvh' # for safety
|
||||
|
||||
# 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'
|
||||
|
||||
t = time()
|
||||
if not filename.lower().endswith('.bvh'):
|
||||
filename += '.bvh' # for safety
|
||||
|
||||
# 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 '\nBVH 1.1 by Campbell Barton (Ideasman) - cbarton@metavr.com'
|
||||
|
||||
# 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(scn.getActiveObject(),''))[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
|
||||
level = 0 # Indenting level, start with no indent
|
||||
level = hierarchy2bvh(file, hierarchy, level, chennelList, nodeObjectList)
|
||||
|
||||
#====================================================#
|
||||
# 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: %i\n' % ( 1 + context.endFrame() - context.startFrame() ) )
|
||||
file.write( 'Frame Time: %.6f\n' % frameRate )
|
||||
|
||||
frames = range(context.startFrame()+1, context.endFrame()+1)
|
||||
print 'exporting %i of motion...' % len(frames)
|
||||
|
||||
for frame in frames:
|
||||
context.currentFrame(frame)
|
||||
scn.update(1) # Update locations so we can write the new locations. This is the SLOW part.
|
||||
# Blender.Window.RedrawAll() # Debugging.
|
||||
|
||||
motion2bvh(file, frame, chennelList, nodeObjectList) # Write the motion to a file.
|
||||
|
||||
file.write('\n') # newline
|
||||
file.close()
|
||||
print '...Done in %.4f seconds.' % (time()-t)
|
||||
|
||||
Blender.Window.FileSelector(saveBVH, 'Export BVH')
|
||||
|
||||
Reference in New Issue
Block a user