[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