forked from bartvdbraak/blender
==bvh removal for cambo==
removing to fix some commit problems - cambo will add them back
This commit is contained in:
parent
f2cfb886d6
commit
5bd324140d
@ -1,385 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Motion Capture (.bvh)...'
|
||||
Blender: 232
|
||||
Group: 'Export'
|
||||
Tip: 'Export a (.bvh) motion capture file'
|
||||
"""
|
||||
|
||||
__author__ = "Campbell Barton"
|
||||
__url__ = ("blender", "elysiun")
|
||||
__version__ = "1.1 12/16/05"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script exports animation data to BVH motion capture file format.
|
||||
|
||||
Supported:<br>
|
||||
|
||||
Missing:<br>
|
||||
|
||||
Known issues:<br>
|
||||
|
||||
Notes:<br>
|
||||
|
||||
"""
|
||||
|
||||
# $Id$
|
||||
#
|
||||
#===============================================#
|
||||
# BVH Export script 1.0 by Campbell Barton #
|
||||
# Copyright MetaVR 30/03/2004, #
|
||||
# if you have any questions about this script #
|
||||
# email me cbarton@metavr.com #
|
||||
#===============================================#
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# BVH Export v1.1 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
|
||||
time = Blender.sys.time
|
||||
from math import *
|
||||
|
||||
# Get the current scene.
|
||||
scn = Scene.GetCurrent()
|
||||
context = scn.getRenderingContext()
|
||||
|
||||
frameRate = 1.0/context.framesPerSec() # 0.04 = 25fps
|
||||
scale = 1.0
|
||||
|
||||
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.parent == parent:
|
||||
children.append( child )
|
||||
return children
|
||||
|
||||
#====================================================#
|
||||
# MESSY BUT WORKS: Make a string that shows the #
|
||||
# hierarchy as a list and then eval it #
|
||||
#====================================================#
|
||||
def getHierarchy(root, 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 #
|
||||
#====================================================#
|
||||
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.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(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
|
||||
|
||||
|
||||
#====================================================#
|
||||
# Writes the BVH hierarchy to a file #
|
||||
# hierarchy: is a list of the empty hierarcht #
|
||||
# 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(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
|
||||
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')
|
||||
|
||||
# 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)
|
||||
|
||||
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 # x is negative, see below.
|
||||
return -x*RAD_TO_DEG, y*RAD_TO_DEG, z*RAD_TO_DEG
|
||||
|
||||
|
||||
''' # 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 #
|
||||
# level: how many levels we are down the tree, #
|
||||
# ...used for indenting #
|
||||
#====================================================#
|
||||
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):
|
||||
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')
|
@ -1,497 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Motion Capture (.bvh)...'
|
||||
Blender: 239
|
||||
Group: 'Import'
|
||||
Tip: 'Import a (.bvh) motion capture file'
|
||||
"""
|
||||
|
||||
__author__ = "Campbell Barton"
|
||||
__url__ = ("blender", "elysiun")
|
||||
__version__ = "1.0.4 05/12/04"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script imports BVH motion capture data to Blender.
|
||||
|
||||
Supported: Poser 3.01<br>
|
||||
|
||||
Missing:<br>
|
||||
|
||||
Known issues:<br>
|
||||
|
||||
Notes:<br>
|
||||
Jean-Michel Soler improved importer to support Poser 3.01 files;<br>
|
||||
Jean-Baptiste Perin wrote a script to create an armature out of the
|
||||
Empties created by this importer, it's in the Scripts window -> Scripts -> Animation menu.
|
||||
"""
|
||||
|
||||
# $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 #
|
||||
# 01/01/2005, #
|
||||
#===============================================#
|
||||
|
||||
#===============================================#
|
||||
# BVH Import script 1.02 patched by Jm Soler #
|
||||
# to the Poser 3.01 bvh file #
|
||||
# 28/12/2004, #
|
||||
#===============================================#
|
||||
|
||||
#===============================================#
|
||||
# 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 scrip. #
|
||||
# email me cbarton@metavr.com #
|
||||
#===============================================#
|
||||
|
||||
#===============================================#
|
||||
# TODO: #
|
||||
# * Create bones when importing #
|
||||
# * Make an IPO jitter removal script #
|
||||
# * Work out a better naming system #
|
||||
#===============================================#
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# BVH Import v1.05 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 Window, Object, Scene, Ipo, Draw
|
||||
from Blender.Scene import Render
|
||||
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
global scale
|
||||
scale = None
|
||||
|
||||
# Update as we load?
|
||||
debug = 0
|
||||
|
||||
def getScale():
|
||||
return Draw.PupFloatInput('BVH Scale: ', 0.01, 0.001, 10.0, 0.1, 3)
|
||||
|
||||
|
||||
#===============================================#
|
||||
# MAIN FUNCTION - All things are done from here #
|
||||
#===============================================#
|
||||
def loadBVH(filename):
|
||||
global scale
|
||||
print '\nBVH Importer 1.05 by Campbell Barton (Ideasman) - cbarton@metavr.com'
|
||||
|
||||
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 = 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', name)
|
||||
ob.setIpo(newIpo)
|
||||
obname = ob.name
|
||||
for channelType in channels:
|
||||
channelType = BVH2BLEND_TX_NAME[channelType]
|
||||
curve = newIpo.addCurve(channelType)
|
||||
curve.setInterpolation('Linear')
|
||||
objectCurveMapping[(obname, channelType)] = curve
|
||||
|
||||
# Add to object list
|
||||
objectList.append(ob)
|
||||
|
||||
# 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, 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 = 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 ====================================#
|
||||
|
||||
|
||||
|
||||
|
||||
time1 = Blender.sys.time()
|
||||
|
||||
# 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')
|
||||
|
||||
# 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')
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
|
||||
# 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, sync with objectList: [[channelType1, channelType2...], [channelType1, channelType2...)]
|
||||
channelList = []
|
||||
channelIndex = -1
|
||||
|
||||
lineIdx = 0 # An index for the file.
|
||||
while lineIdx < len(lines) -1:
|
||||
#...
|
||||
if lines[lineIdx][0] == 'ROOT' or lines[lineIdx][0] == 'JOINT':
|
||||
|
||||
# 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.??
|
||||
|
||||
# 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 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:]:
|
||||
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, 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 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, 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 len(lines[lineIdx]) == 1 and lines[lineIdx][0] == '}': # == ['}']
|
||||
parent.pop() # Remove the last item
|
||||
|
||||
#=============================================#
|
||||
# BVH Structure loaded, Now import motion #
|
||||
#=============================================#
|
||||
if len(lines[lineIdx]) == 1 and lines[lineIdx][0] == 'MOTION':
|
||||
print '\nImporting motion data'
|
||||
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 #
|
||||
#=============================================#
|
||||
|
||||
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(line) < len(objectList):
|
||||
print '...ending on unknown tags'
|
||||
break
|
||||
|
||||
|
||||
currentFrame += 1 # Incriment to next frame
|
||||
|
||||
#=============================================#
|
||||
# Import motion data and assign it to an IPO #
|
||||
#=============================================#
|
||||
line.append(0.0) # Use this as a dummy var for objects that dont have a loc/rotate channel.
|
||||
|
||||
if debug: Blender.Redraw()
|
||||
for obIdx, ob in enumerate(objectList):
|
||||
obname = ob.name
|
||||
obChannel = channelList[obIdx]
|
||||
if channelList[obIdx][0] != -1:
|
||||
objectMotiondataMapping[obname, 'LocX'].append((currentFrame, scale * float( line[obChannel[0]] )))
|
||||
|
||||
if channelList[obIdx][1] != -1:
|
||||
objectMotiondataMapping[obname, 'LocY'].append((currentFrame, scale * float( line[obChannel[1]] )))
|
||||
|
||||
if channelList[obIdx][2] != -1:
|
||||
objectMotiondataMapping[obname, 'LocZ'].append((currentFrame, scale * float( line[obChannel[2]] )))
|
||||
|
||||
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']
|
||||
|
||||
# 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
|
||||
|
||||
while (motionMappingRotY[-1][1] - y) > 18: y+=36
|
||||
while (motionMappingRotY[-1][1] - y) < -18: y-=36
|
||||
|
||||
while (motionMappingRotZ[-1][1] - z) > 18: z+=36
|
||||
while (motionMappingRotZ[-1][1] - z) < -18: z-=36
|
||||
|
||||
motionMappingRotX.append((currentFrame, x))
|
||||
motionMappingRotY.append((currentFrame, y))
|
||||
motionMappingRotZ.append((currentFrame, z))
|
||||
# Done importing motion data #
|
||||
|
||||
lineIdx += 1
|
||||
|
||||
#=======================================#
|
||||
# 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
|
||||
break
|
||||
|
||||
# Main file loop
|
||||
lineIdx += 1
|
||||
|
||||
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()
|
Loading…
Reference in New Issue
Block a user