diff options
author | Campbell Barton <ideasman42@gmail.com> | 2009-11-04 17:31:14 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2009-11-04 17:31:14 +0300 |
commit | 37fde5b33520b1a7fd27560785ba196022564d31 (patch) | |
tree | 144a84b21a29c671cd931896d4d5bd87b95d07d3 /release | |
parent | 8436608513ad14607bb523d3d6ed070c7e6bfe7b (diff) |
bvh import from 2.4x (unchanged)
Diffstat (limited to 'release')
-rw-r--r-- | release/scripts/io/import_bvh.py | 757 |
1 files changed, 757 insertions, 0 deletions
diff --git a/release/scripts/io/import_bvh.py b/release/scripts/io/import_bvh.py new file mode 100644 index 00000000000..4134503c511 --- /dev/null +++ b/release/scripts/io/import_bvh.py @@ -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 + while anim_data[-1][3] - rx < -180: rx-=360 + + while anim_data[-1][4] - ry > 180: ry+=360 + while anim_data[-1][4] - ry < -180: ry-=360 + + while anim_data[-1][5] - rz > 180: rz+=360 + while anim_data[-1][5] - rz < -180: rz-=360 + + # Done importing motion data # + anim_data.append( (lx, ly, lz, rx, ry, rz) ) + lineIdx += 1 + + # Assign children + for bvh_node in bvh_nodes.itervalues(): + bvh_node_parent= bvh_node.parent + if bvh_node_parent: + bvh_node_parent.children.append(bvh_node) + + # Now set the tip of each bvh_node + for bvh_node in bvh_nodes.itervalues(): + + if not bvh_node.rest_tail_world: + if len(bvh_node.children)==0: + # could just fail here, but rare BVH files have childless nodes + bvh_node.rest_tail_world = Vector(bvh_node.rest_head_world) + bvh_node.rest_tail_local = Vector(bvh_node.rest_head_local) + elif len(bvh_node.children)==1: + bvh_node.rest_tail_world= Vector(bvh_node.children[0].rest_head_world) + bvh_node.rest_tail_local= Vector(bvh_node.children[0].rest_head_local) + else: + # allow this, see above + #if not bvh_node.children: + # raise 'error, bvh node has no end and no children. bad file' + + # Removed temp for now + rest_tail_world= Vector(0,0,0) + rest_tail_local= Vector(0,0,0) + for bvh_node_child in bvh_node.children: + rest_tail_world += bvh_node_child.rest_head_world + rest_tail_local += bvh_node_child.rest_head_local + + bvh_node.rest_tail_world= rest_tail_world * (1.0/len(bvh_node.children)) + bvh_node.rest_tail_local= rest_tail_local * (1.0/len(bvh_node.children)) + + # Make sure tail isnt the same location as the head. + if (bvh_node.rest_tail_local-bvh_node.rest_head_local).length <= 0.001*GLOBAL_SCALE: + + bvh_node.rest_tail_local.y= bvh_node.rest_tail_local.y + GLOBAL_SCALE/10 + bvh_node.rest_tail_world.y= bvh_node.rest_tail_world.y + GLOBAL_SCALE/10 + + + + return bvh_nodes + + + +def bvh_node_dict2objects(bvh_nodes, IMPORT_START_FRAME= 1, IMPORT_LOOP= False): + + if IMPORT_START_FRAME<1: + IMPORT_START_FRAME= 1 + + scn= bpy.data.scenes.active + scn.objects.selected = [] + + objects= [] + + def add_ob(name): + ob = scn.objects.new('Empty') + objects.append(ob) + return ob + + # Add objects + for name, bvh_node in bvh_nodes.iteritems(): + bvh_node.temp= add_ob(name) + + # Parent the objects + for bvh_node in bvh_nodes.itervalues(): + bvh_node.temp.makeParent([ bvh_node_child.temp for bvh_node_child in bvh_node.children ], 1, 0) # ojbs, noninverse, 1 = not fast. + + # Offset + for bvh_node in bvh_nodes.itervalues(): + # Make relative to parents offset + bvh_node.temp.loc= bvh_node.rest_head_local + + # Add tail objects + for name, bvh_node in bvh_nodes.iteritems(): + if not bvh_node.children: + ob_end= add_ob(name + '_end') + bvh_node.temp.makeParent([ob_end], 1, 0) # ojbs, noninverse, 1 = not fast. + ob_end.loc= bvh_node.rest_tail_local + + + # Animate the data, the last used bvh_node will do since they all have the same number of frames + for current_frame in xrange(len(bvh_node.anim_data)): + Blender.Set('curframe', current_frame+IMPORT_START_FRAME) + + for bvh_node in bvh_nodes.itervalues(): + lx,ly,lz,rx,ry,rz= bvh_node.anim_data[current_frame] + + rest_head_local= bvh_node.rest_head_local + bvh_node.temp.loc= rest_head_local.x+lx, rest_head_local.y+ly, rest_head_local.z+lz + + bvh_node.temp.rot= rx*DEG2RAD,ry*DEG2RAD,rz*DEG2RAD + + bvh_node.temp.insertIpoKey(Blender.Object.IpoKeyTypes.LOCROT) + + scn.update(1) + return objects + + + +def bvh_node_dict2armature(bvh_nodes, IMPORT_START_FRAME= 1, IMPORT_LOOP= False): + + if IMPORT_START_FRAME<1: + IMPORT_START_FRAME= 1 + + + # Add the new armature, + scn = bpy.data.scenes.active + scn.objects.selected = [] + + arm_data= bpy.data.armatures.new() + arm_ob = scn.objects.new(arm_data) + scn.objects.context = [arm_ob] + scn.objects.active = arm_ob + + # Put us into editmode + arm_data.makeEditable() + + # Get the average bone length for zero length bones, we may not use this. + average_bone_length= 0.0 + nonzero_count= 0 + for bvh_node in bvh_nodes.itervalues(): + l= (bvh_node.rest_head_local-bvh_node.rest_tail_local).length + if l: + average_bone_length+= l + nonzero_count+=1 + + # Very rare cases all bones couldbe zero length??? + if not average_bone_length: + average_bone_length = 0.1 + else: + # Normal operation + average_bone_length = average_bone_length/nonzero_count + + + + ZERO_AREA_BONES= [] + for name, bvh_node in bvh_nodes.iteritems(): + # New editbone + bone= bvh_node.temp= Blender.Armature.Editbone() + + bone.name= name + arm_data.bones[name]= bone + + bone.head= bvh_node.rest_head_world + bone.tail= bvh_node.rest_tail_world + + # ZERO AREA BONES. + if (bone.head-bone.tail).length < 0.001: + if bvh_node.parent: + ofs= bvh_node.parent.rest_head_local- bvh_node.parent.rest_tail_local + if ofs.length: # is our parent zero length also?? unlikely + bone.tail= bone.tail+ofs + else: + bone.tail.y= bone.tail.y+average_bone_length + else: + bone.tail.y= bone.tail.y+average_bone_length + + ZERO_AREA_BONES.append(bone.name) + + + for bvh_node in bvh_nodes.itervalues(): + if bvh_node.parent: + # bvh_node.temp is the Editbone + + # Set the bone parent + bvh_node.temp.parent= bvh_node.parent.temp + + # Set the connection state + if not bvh_node.has_loc and\ + bvh_node.parent and\ + bvh_node.parent.temp.name not in ZERO_AREA_BONES and\ + bvh_node.parent.rest_tail_local == bvh_node.rest_head_local: + bvh_node.temp.options= [Blender.Armature.CONNECTED] + + # Replace the editbone with the editbone name, + # to avoid memory errors accessing the editbone outside editmode + for bvh_node in bvh_nodes.itervalues(): + bvh_node.temp= bvh_node.temp.name + + arm_data.update() + + # Now Apply the animation to the armature + + # Get armature animation data + pose= arm_ob.getPose() + pose_bones= pose.bones + + action = Blender.Armature.NLA.NewAction("Action") + action.setActive(arm_ob) + #xformConstants= [ Blender.Object.Pose.LOC, Blender.Object.Pose.ROT ] + + # Replace the bvh_node.temp (currently an editbone) + # With a tuple (pose_bone, armature_bone, bone_rest_matrix, bone_rest_matrix_inv) + for bvh_node in bvh_nodes.itervalues(): + bone_name= bvh_node.temp # may not be the same name as the bvh_node, could have been shortened. + pose_bone= pose_bones[bone_name] + rest_bone= arm_data.bones[bone_name] + bone_rest_matrix = rest_bone.matrix['ARMATURESPACE'].rotationPart() + + bone_rest_matrix_inv= Matrix(bone_rest_matrix) + bone_rest_matrix_inv.invert() + + bone_rest_matrix_inv.resize4x4() + bone_rest_matrix.resize4x4() + bvh_node.temp= (pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv) + + + # Make a dict for fast access without rebuilding a list all the time. + xformConstants_dict={ + (True,True): [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT],\ + (False,True): [Blender.Object.Pose.ROT],\ + (True,False): [Blender.Object.Pose.LOC],\ + (False,False): [],\ + } + + + # KEYFRAME METHOD, SLOW, USE IPOS DIRECT + + # Animate the data, the last used bvh_node will do since they all have the same number of frames + for current_frame in xrange(len(bvh_node.anim_data)-1): # skip the first frame (rest frame) + # print current_frame + + #if current_frame==40: # debugging + # break + + # Dont neet to set the current frame + for bvh_node in bvh_nodes.itervalues(): + pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp + lx,ly,lz,rx,ry,rz= bvh_node.anim_data[current_frame+1] + + if bvh_node.has_rot: + # Set the rotation, not so simple + bone_rotation_matrix= Euler(rx,ry,rz).toMatrix() + bone_rotation_matrix.resize4x4() + pose_bone.quat= (bone_rest_matrix * bone_rotation_matrix * bone_rest_matrix_inv).toQuat() + + if bvh_node.has_loc: + # Set the Location, simple too + pose_bone.loc= (\ + TranslationMatrix(Vector(lx, ly, lz) - bvh_node.rest_head_local ) *\ + bone_rest_matrix_inv).translationPart() # WHY * 10? - just how pose works + + # Get the transform + xformConstants= xformConstants_dict[bvh_node.has_loc, bvh_node.has_rot] + + + if xformConstants: + # Insert the keyframe from the loc/quat + pose_bone.insertKey(arm_ob, current_frame+IMPORT_START_FRAME, xformConstants, True ) + + # First time, set the IPO's to linear + if current_frame==0: + for ipo in action.getAllChannelIpos().itervalues(): + if ipo: + for cur in ipo: + cur.interpolation = Blender.IpoCurve.InterpTypes.LINEAR + if IMPORT_LOOP: + cur.extend = Blender.IpoCurve.ExtendTypes.CYCLIC + + + + + # END KEYFRAME METHOD + + + """ + # IPO KEYFRAME SETTING + # Add in the IPOs by adding keyframes, AFAIK theres no way to add IPOs to an action so I do this :/ + for bvh_node in bvh_nodes.itervalues(): + pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp + + # Get the transform + xformConstants= xformConstants_dict[bvh_node.has_loc, bvh_node.has_rot] + if xformConstants: + pose_bone.loc[:]= 0,0,0 + pose_bone.quat[:]= 0,0,1,0 + # Insert the keyframe from the loc/quat + pose_bone.insertKey(arm_ob, IMPORT_START_FRAME, xformConstants) + + + action_ipos= action.getAllChannelIpos() + + + for bvh_node in bvh_nodes.itervalues(): + has_loc= bvh_node.has_loc + has_rot= bvh_node.has_rot + + if not has_rot and not has_loc: + # No animation data + continue + + ipo= action_ipos[bvh_node.temp[0].name] # posebones name as key + + if has_loc: + curve_xloc= ipo[Blender.Ipo.PO_LOCX] + curve_yloc= ipo[Blender.Ipo.PO_LOCY] + curve_zloc= ipo[Blender.Ipo.PO_LOCZ] + + curve_xloc.interpolation= \ + curve_yloc.interpolation= \ + curve_zloc.interpolation= \ + Blender.IpoCurve.InterpTypes.LINEAR + + + if has_rot: + curve_wquat= ipo[Blender.Ipo.PO_QUATW] + curve_xquat= ipo[Blender.Ipo.PO_QUATX] + curve_yquat= ipo[Blender.Ipo.PO_QUATY] + curve_zquat= ipo[Blender.Ipo.PO_QUATZ] + + curve_wquat.interpolation= \ + curve_xquat.interpolation= \ + curve_yquat.interpolation= \ + curve_zquat.interpolation= \ + Blender.IpoCurve.InterpTypes.LINEAR + + # Get the bone + pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp + + + def pose_rot(anim_data): + bone_rotation_matrix= Euler(anim_data[3], anim_data[4], anim_data[5]).toMatrix() + bone_rotation_matrix.resize4x4() + return tuple((bone_rest_matrix * bone_rotation_matrix * bone_rest_matrix_inv).toQuat()) # qw,qx,qy,qz + + def pose_loc(anim_data): + return tuple((TranslationMatrix(Vector(anim_data[0], anim_data[1], anim_data[2])) * bone_rest_matrix_inv).translationPart()) + + + last_frame= len(bvh_node.anim_data)+IMPORT_START_FRAME-1 + + if has_loc: + pose_locations= [pose_loc(anim_key) for anim_key in bvh_node.anim_data] + + # Add the start at the end, we know the start is just 0,0,0 anyway + curve_xloc.append((last_frame, pose_locations[-1][0])) + curve_yloc.append((last_frame, pose_locations[-1][1])) + curve_zloc.append((last_frame, pose_locations[-1][2])) + + if len(pose_locations) > 1: + ox,oy,oz= pose_locations[0] + x,y,z= pose_locations[1] + + for i in xrange(1, len(pose_locations)-1): # from second frame to second last frame + + nx,ny,nz= pose_locations[i+1] + xset= yset= zset= True # we set all these by default + if abs((ox+nx)/2 - x) < 0.00001: xset= False + if abs((oy+ny)/2 - y) < 0.00001: yset= False + if abs((oz+nz)/2 - z) < 0.00001: zset= False + + if xset: curve_xloc.append((i+IMPORT_START_FRAME, x)) + if yset: curve_yloc.append((i+IMPORT_START_FRAME, y)) + if zset: curve_zloc.append((i+IMPORT_START_FRAME, z)) + + # Set the old and use the new + ox,oy,oz= x,y,z + x,y,z= nx,ny,nz + + + if has_rot: + pose_rotations= [pose_rot(anim_key) for anim_key in bvh_node.anim_data] + + # Add the start at the end, we know the start is just 0,0,0 anyway + curve_wquat.append((last_frame, pose_rotations[-1][0])) + curve_xquat.append((last_frame, pose_rotations[-1][1])) + curve_yquat.append((last_frame, pose_rotations[-1][2])) + curve_zquat.append((last_frame, pose_rotations[-1][3])) + + + if len(pose_rotations) > 1: + ow,ox,oy,oz= pose_rotations[0] + w,x,y,z= pose_rotations[1] + + for i in xrange(1, len(pose_rotations)-1): # from second frame to second last frame + + nw, nx,ny,nz= pose_rotations[i+1] + wset= xset= yset= zset= True # we set all these by default + if abs((ow+nw)/2 - w) < 0.00001: wset= False + if abs((ox+nx)/2 - x) < 0.00001: xset= False + if abs((oy+ny)/2 - y) < 0.00001: yset= False + if abs((oz+nz)/2 - z) < 0.00001: zset= False + + if wset: curve_wquat.append((i+IMPORT_START_FRAME, w)) + if xset: curve_xquat.append((i+IMPORT_START_FRAME, x)) + if yset: curve_yquat.append((i+IMPORT_START_FRAME, y)) + if zset: curve_zquat.append((i+IMPORT_START_FRAME, z)) + + # Set the old and use the new + ow,ox,oy,oz= w,x,y,z + w,x,y,z= nw,nx,ny,nz + + # IPO KEYFRAME SETTING + """ + pose.update() + return arm_ob + + +#=============# +# TESTING # +#=============# + +#('/metavr/mocap/bvh/boxer.bvh') +#('/d/staggered_walk.bvh') +#('/metavr/mocap/bvh/dg-306-g.bvh') # Incompleate EOF +#('/metavr/mocap/bvh/wa8lk.bvh') # duplicate joint names, \r line endings. +#('/metavr/mocap/bvh/walk4.bvh') # 0 channels + +''' +import os +DIR = '/metavr/mocap/bvh/' +for f in ('/d/staggered_walk.bvh',): + #for f in os.listdir(DIR)[5:6]: + #for f in os.listdir(DIR): + if f.endswith('.bvh'): + s = Blender.Scene.New(f) + s.makeCurrent() + #file= DIR + f + file= f + print f + bvh_nodes= read_bvh(file, 1.0) + bvh_node_dict2armature(bvh_nodes, 1) +''' + +def load_bvh_ui(file, PREF_UI= True): + + if BPyMessages.Error_NoFile(file): + return + + Draw= Blender.Draw + + IMPORT_SCALE = Draw.Create(0.1) + IMPORT_START_FRAME = Draw.Create(1) + IMPORT_AS_ARMATURE = Draw.Create(1) + IMPORT_AS_EMPTIES = Draw.Create(0) + IMPORT_LOOP = Draw.Create(0) + + # Get USER Options + if PREF_UI: + pup_block = [\ + ('As Armature', IMPORT_AS_ARMATURE, 'Imports the BVH as an armature'),\ + ('As Empties', IMPORT_AS_EMPTIES, 'Imports the BVH as empties'),\ + ('Scale: ', IMPORT_SCALE, 0.001, 100.0, 'Scale the BVH, Use 0.01 when 1.0 is 1 metre'),\ + ('Start Frame: ', IMPORT_START_FRAME, 1, 30000, 'Frame to start BVH motion'),\ + ('Loop Animation', IMPORT_LOOP, 'Enable cyclic IPOs'),\ + ] + + if not Draw.PupBlock('BVH Import...', pup_block): + return + + print 'Attempting import BVH', file + + IMPORT_SCALE = IMPORT_SCALE.val + IMPORT_START_FRAME = IMPORT_START_FRAME.val + IMPORT_AS_ARMATURE = IMPORT_AS_ARMATURE.val + IMPORT_AS_EMPTIES = IMPORT_AS_EMPTIES.val + IMPORT_LOOP = IMPORT_LOOP.val + + if not IMPORT_AS_ARMATURE and not IMPORT_AS_EMPTIES: + Blender.Draw.PupMenu('No import option selected') + return + Blender.Window.WaitCursor(1) + # Get the BVH data and act on it. + t1= Blender.sys.time() + print '\tparsing bvh...', + bvh_nodes= read_bvh(file, IMPORT_SCALE) + print '%.4f' % (Blender.sys.time()-t1) + t1= Blender.sys.time() + print '\timporting to blender...', + if IMPORT_AS_ARMATURE: bvh_node_dict2armature(bvh_nodes, IMPORT_START_FRAME, IMPORT_LOOP) + if IMPORT_AS_EMPTIES: bvh_node_dict2objects(bvh_nodes, IMPORT_START_FRAME, IMPORT_LOOP) + + print 'Done in %.4f\n' % (Blender.sys.time()-t1) + Blender.Window.WaitCursor(0) + +def main(): + Blender.Window.FileSelector(load_bvh_ui, 'Import BVH', '*.bvh') + +if __name__ == '__main__': + #def foo(): + main() + ''' + scn = bpy.data.scenes.active + for ob in list(scn.objects): + if ob.name!='arm__': + scn.objects.unlink(ob) + load_bvh_ui('/test.bvh', False) + '''
\ No newline at end of file |