[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [24308] trunk/blender/release/scripts/io/ import_bvh.py: bvh import from 2.4x (unchanged)
Campbell Barton
ideasman42 at gmail.com
Wed Nov 4 15:31:15 CET 2009
Revision: 24308
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=24308
Author: campbellbarton
Date: 2009-11-04 15:31:14 +0100 (Wed, 04 Nov 2009)
Log Message:
-----------
bvh import from 2.4x (unchanged)
Added Paths:
-----------
trunk/blender/release/scripts/io/import_bvh.py
Copied: trunk/blender/release/scripts/io/import_bvh.py (from rev 24307, branches/blender2.4/release/scripts/bvh_import.py)
===================================================================
--- trunk/blender/release/scripts/io/import_bvh.py (rev 0)
+++ trunk/blender/release/scripts/io/import_bvh.py 2009-11-04 14:31:14 UTC (rev 24308)
@@ -0,0 +1,757 @@
+#!BPY
+
+"""
+Name: 'Motion Capture (.bvh)...'
+Blender: 242
+Group: 'Import'
+Tip: 'Import a (.bvh) motion capture file'
+"""
+
+__author__ = "Campbell Barton"
+__url__ = ("blender.org", "blenderartists.org")
+__version__ = "1.90 06/08/01"
+
+__bpydoc__ = """\
+This script imports BVH motion capture data to Blender.
+as empties or armatures.
+"""
+
+# --------------------------------------------------------------------------
+# BVH Import v2.0 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
+import bpy
+import BPyMessages
+Vector= Blender.Mathutils.Vector
+Euler= Blender.Mathutils.Euler
+Matrix= Blender.Mathutils.Matrix
+RotationMatrix = Blender.Mathutils.RotationMatrix
+TranslationMatrix= Blender.Mathutils.TranslationMatrix
+
+DEG2RAD = 0.017453292519943295
+
+class bvh_node_class(object):
+ __slots__=(\
+ 'name',# bvh joint name
+ 'parent',# bvh_node_class type or None for no parent
+ 'children',# a list of children of this type.
+ 'rest_head_world',# worldspace rest location for the head of this node
+ 'rest_head_local',# localspace rest location for the head of this node
+ 'rest_tail_world',# # worldspace rest location for the tail of this node
+ 'rest_tail_local',# # worldspace rest location for the tail of this node
+ 'channels',# list of 6 ints, -1 for an unused channel, otherwise an index for the BVH motion data lines, lock triple then rot triple
+ 'rot_order',# a triple of indicies as to the order rotation is applied. [0,1,2] is x/y/z - [None, None, None] if no rotation.
+ 'anim_data',# a list one tuple's one for each frame. (locx, locy, locz, rotx, roty, rotz)
+ 'has_loc',# Conveinience function, bool, same as (channels[0]!=-1 or channels[1]!=-1 channels[2]!=-1)
+ 'has_rot',# Conveinience function, bool, same as (channels[3]!=-1 or channels[4]!=-1 channels[5]!=-1)
+ 'temp')# use this for whatever you want
+
+ def __init__(self, name, rest_head_world, rest_head_local, parent, channels, rot_order):
+ self.name= name
+ self.rest_head_world= rest_head_world
+ self.rest_head_local= rest_head_local
+ self.rest_tail_world= None
+ self.rest_tail_local= None
+ self.parent= parent
+ self.channels= channels
+ self.rot_order= rot_order
+
+ # convenience functions
+ self.has_loc= channels[0] != -1 or channels[1] != -1 or channels[2] != -1
+ self.has_rot= channels[3] != -1 or channels[4] != -1 or channels[5] != -1
+
+
+ self.children= []
+
+ # list of 6 length tuples: (lx,ly,lz, rx,ry,rz)
+ # even if the channels arnt used they will just be zero
+ #
+ self.anim_data= [(0,0,0,0,0,0)]
+
+
+ def __repr__(self):
+ return 'BVH name:"%s", rest_loc:(%.3f,%.3f,%.3f), rest_tail:(%.3f,%.3f,%.3f)' %\
+ (self.name,\
+ self.rest_head_world.x, self.rest_head_world.y, self.rest_head_world.z,\
+ self.rest_head_world.x, self.rest_head_world.y, self.rest_head_world.z)
+
+
+
+# Change the order rotation is applied.
+MATRIX_IDENTITY_3x3 = Matrix([1,0,0],[0,1,0],[0,0,1])
+MATRIX_IDENTITY_4x4 = Matrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1])
+
+def eulerRotate(x,y,z, rot_order):
+ # Clamp all values between 0 and 360, values outside this raise an error.
+ mats=[RotationMatrix(x%360,3,'x'), RotationMatrix(y%360,3,'y'), RotationMatrix(z%360,3,'z')]
+ # print rot_order
+ # Standard BVH multiplication order, apply the rotation in the order Z,X,Y
+ return (mats[rot_order[2]]*(mats[rot_order[1]]* (mats[rot_order[0]]* MATRIX_IDENTITY_3x3))).toEuler()
+
+def read_bvh(file_path, GLOBAL_SCALE=1.0):
+ # File loading stuff
+ # Open the file for importing
+ file = open(file_path, 'rU')
+
+ # Seperate into a list of lists, each line a list of words.
+ file_lines = file.readlines()
+ # Non standard carrage returns?
+ if len(file_lines) == 1:
+ file_lines = file_lines[0].split('\r')
+
+ # Split by whitespace.
+ file_lines =[ll for ll in [ l.split() for l in file_lines] if ll]
+
+
+ # Create Hirachy as empties
+
+ if file_lines[0][0].lower() == 'hierarchy':
+ #print 'Importing the BVH Hierarchy for:', file_path
+ pass
+ else:
+ raise 'ERROR: This is not a BVH file'
+
+ bvh_nodes= {None:None}
+ bvh_nodes_serial = [None]
+
+ channelIndex = -1
+
+
+ lineIdx = 0 # An index for the file.
+ while lineIdx < len(file_lines) -1:
+ #...
+ if file_lines[lineIdx][0].lower() == 'root' or file_lines[lineIdx][0].lower() == 'joint':
+
+ # Join spaces into 1 word with underscores joining it.
+ if len(file_lines[lineIdx]) > 2:
+ file_lines[lineIdx][1] = '_'.join(file_lines[lineIdx][1:])
+ file_lines[lineIdx] = file_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 = file_lines[lineIdx][1]
+
+ #print '%snode: %s, parent: %s' % (len(bvh_nodes_serial) * ' ', name, bvh_nodes_serial[-1])
+
+ lineIdx += 2 # Incriment to the next line (Offset)
+ rest_head_local = Vector( GLOBAL_SCALE*float(file_lines[lineIdx][1]), GLOBAL_SCALE*float(file_lines[lineIdx][2]), GLOBAL_SCALE*float(file_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.
+ my_channel = [-1, -1, -1, -1, -1, -1]
+ my_rot_order= [None, None, None]
+ rot_count= 0
+ for channel in file_lines[lineIdx][2:]:
+ channel= channel.lower()
+ channelIndex += 1 # So the index points to the right channel
+ if channel == 'xposition': my_channel[0] = channelIndex
+ elif channel == 'yposition': my_channel[1] = channelIndex
+ elif channel == 'zposition': my_channel[2] = channelIndex
+
+ elif channel == 'xrotation':
+ my_channel[3] = channelIndex
+ my_rot_order[rot_count]= 0
+ rot_count+=1
+ elif channel == 'yrotation':
+ my_channel[4] = channelIndex
+ my_rot_order[rot_count]= 1
+ rot_count+=1
+ elif channel == 'zrotation':
+ my_channel[5] = channelIndex
+ my_rot_order[rot_count]= 2
+ rot_count+=1
+
+ channels = file_lines[lineIdx][2:]
+
+ my_parent= bvh_nodes_serial[-1] # account for none
+
+
+ # Apply the parents offset accumletivly
+ if my_parent==None:
+ rest_head_world= Vector(rest_head_local)
+ else:
+ rest_head_world= my_parent.rest_head_world + rest_head_local
+
+ bvh_node= bvh_nodes[name]= bvh_node_class(name, rest_head_world, rest_head_local, my_parent, my_channel, my_rot_order)
+
+ # If we have another child then we can call ourselves a parent, else
+ bvh_nodes_serial.append(bvh_node)
+
+ # Account for an end node
+ if file_lines[lineIdx][0].lower() == 'end' and file_lines[lineIdx][1].lower() == 'site': # There is somtimes a name after 'End Site' but we will ignore it.
+ lineIdx += 2 # Incriment to the next line (Offset)
+ rest_tail = Vector( GLOBAL_SCALE*float(file_lines[lineIdx][1]), GLOBAL_SCALE*float(file_lines[lineIdx][2]), GLOBAL_SCALE*float(file_lines[lineIdx][3]) )
+
+ bvh_nodes_serial[-1].rest_tail_world= bvh_nodes_serial[-1].rest_head_world + rest_tail
+ bvh_nodes_serial[-1].rest_tail_local= rest_tail
+
+
+ # Just so we can remove the Parents in a uniform way- End end never has kids
+ # so this is a placeholder
+ bvh_nodes_serial.append(None)
+
+ if len(file_lines[lineIdx]) == 1 and file_lines[lineIdx][0] == '}': # == ['}']
+ bvh_nodes_serial.pop() # Remove the last item
+
+ if len(file_lines[lineIdx]) == 1 and file_lines[lineIdx][0].lower() == 'motion':
+ #print '\nImporting motion data'
+ lineIdx += 3 # Set the cursor to the first frame
+ break
+
+ lineIdx += 1
+
+
+ # Remove the None value used for easy parent reference
+ del bvh_nodes[None]
+ # Dont use anymore
+ del bvh_nodes_serial
+
+ bvh_nodes_list= bvh_nodes.values()
+
+ while lineIdx < len(file_lines):
+ line= file_lines[lineIdx]
+ for bvh_node in bvh_nodes_list:
+ #for bvh_node in bvh_nodes_serial:
+ lx= ly= lz= rx= ry= rz= 0.0
+ channels= bvh_node.channels
+ anim_data= bvh_node.anim_data
+ if channels[0] != -1:
+ lx= GLOBAL_SCALE * float( line[channels[0]] )
+
+ if channels[1] != -1:
+ ly= GLOBAL_SCALE * float( line[channels[1]] )
+
+ if channels[2] != -1:
+ lz= GLOBAL_SCALE * float( line[channels[2]] )
+
+ if channels[3] != -1 or channels[4] != -1 or channels[5] != -1:
+ rx, ry, rz = eulerRotate(float( line[channels[3]] ), float( line[channels[4]] ), float( line[channels[5]] ), bvh_node.rot_order)
+ #x,y,z = x/10.0, y/10.0, z/10.0 # For IPO's 36 is 360d
+
+ # 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.
+
+ while anim_data[-1][3] - rx > 180: rx+=360
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list