blender/release/scripts/bpymodules/BPyArmature.py
Campbell Barton d2fb4afb7c BPyArmature - has a function that gets final pose locations/rotations. the data it returns can be swaped with IPO curve/locations, so exporters can use this to export bones with IK's/constraints.
export_cal3d.py - option to export with baked animation from posebones, added popup UI with some options, fixed object scaling, get the meshes armature if its not selected.
2007-04-25 05:13:03 +00:00

138 lines
4.6 KiB
Python

# 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
import Blender
import bpy
def getBakedPoseData(ob_arm, start_frame, end_frame):
'''
If you are currently getting IPO's this function can be used to
return a list of frame aligned bone dictionary's
The data in these can be swaped in for the IPO loc and quat
If you want to bake an action, this is not as hard and the ipo hack can be removed.
'''
# --------------------------------- Dummy Action! Only for this functon
backup_action = ob_arm.action
backup_frame = Blender.Get('curframe')
DUMMY_ACTION_NAME = '~DONT_USE~'
# Get the dummy action if it has no users
try:
new_action = bpy.data.actions[DUMMY_ACTION_NAME]
if new_action.users:
new_action = None
except:
new_action = None
if not new_action:
new_action = bpy.data.actions.new(DUMMY_ACTION_NAME)
new_action.fakeUser = False
# ---------------------------------- Done
Matrix = Blender.Mathutils.Matrix
Quaternion = Blender.Mathutils.Quaternion
Vector = Blender.Mathutils.Vector
POSE_XFORM= [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT]
# Each dict a frame
bake_data = [{} for i in xrange(1+end_frame-start_frame)]
pose= ob_arm.getPose()
armature_data= ob_arm.getData();
pose_bones= pose.bones
# --------------------------------- Build a list of arma data for reuse
armature_bone_data = []
bones_index = {}
for bone_name, rest_bone in armature_data.bones.items():
pose_bone = pose_bones[bone_name]
rest_matrix = rest_bone.matrix['ARMATURESPACE']
rest_matrix_inv = rest_matrix.copy().invert()
armature_bone_data.append( [len(bones_index), -1, bone_name, rest_bone, rest_matrix, rest_matrix_inv, pose_bone, None ])
bones_index[bone_name] = len(bones_index)
# Set the parent ID's
for bone_name, pose_bone in pose_bones.items():
parent = pose_bone.parent
if parent:
bone_index= bones_index[bone_name]
parent_index= bones_index[parent.name]
armature_bone_data[ bone_index ][1]= parent_index
# ---------------------------------- Done
# --------------------------------- Main loop to collect IPO data
frame_index = 0
for current_frame in xrange(start_frame, end_frame+1):
ob_arm.action = backup_action
#pose.update() # not needed
Blender.Set('curframe', current_frame)
#Blender.Window.RedrawAll()
#frame_data = bake_data[frame_index]
ob_arm.action = new_action
###for i,pose_bone in enumerate(pose_bones):
for index, parent_index, bone_name, rest_bone, rest_matrix, rest_matrix_inv, pose_bone, ipo in armature_bone_data:
matrix= pose_bone.poseMatrix
parent_bone= rest_bone.parent
if parent_index != -1:
parent_pose_matrix = armature_bone_data[parent_index][6].poseMatrix
parent_bone_matrix_inv = armature_bone_data[parent_index][5]
matrix= matrix * parent_pose_matrix.copy().invert()
rest_matrix= rest_matrix * parent_bone_matrix_inv
matrix=matrix * rest_matrix.copy().invert()
pose_bone.quat= matrix.toQuat()
pose_bone.loc= matrix.translationPart()
pose_bone.insertKey(ob_arm, 1, POSE_XFORM) # always frame 1
# THIS IS A BAD HACK! IT SUCKS BIGTIME BUT THE RESULT ARE NICE
# - use a temp action and bake into that, always at the same frame
# so as not to make big IPO's, then collect the result from the IPOs
# Now get the data from the IPOs
if not ipo: ipo = armature_bone_data[index][7] = new_action.getChannelIpo(bone_name)
loc = Vector()
quat = Quaternion()
for curve in ipo:
val = curve.evaluate(1)
curve_name= curve.name
if curve_name == 'LocX': loc[0] = val
elif curve_name == 'LocY': loc[1] = val
elif curve_name == 'LocZ': loc[2] = val
elif curve_name == 'QuatW': quat[3] = val
elif curve_name == 'QuatX': quat[0] = val
elif curve_name == 'QuatY': quat[1] = val
elif curve_name == 'QuatZ': quat[2] = val
bake_data[frame_index][bone_name] = loc, quat
frame_index+=1
ob_arm.action = backup_action
Blender.Set('curframe', backup_frame)
return bake_data