Skip to content

Instantly share code, notes, and snippets.

@zeffii
Created November 16, 2015 19:46
Show Gist options
  • Save zeffii/a0d6087baec01fcfd615 to your computer and use it in GitHub Desktop.
Save zeffii/a0d6087baec01fcfd615 to your computer and use it in GitHub Desktop.
## modified to bypass restricted context code. untested.
# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# Project Name: MakeHuman
# Product Home Page: http://www.makehuman.org/
# Code Home Page: http://code.google.com/p/makehuman/
# Authors: Thomas Larsson
# Script copyright (C) MakeHuman Team 2001-2011
# Coding Standards: See http://sites.google.com/site/makehumandocs/developers-guide
"""
Abstract
Tool for loading bvh files onto the MHX rig in Blender 2.5x
Version 0.6
Place the script in the .blender/scripts/addons dir
Activate the script in the "Add-Ons" tab (user preferences).
Access from UI panel (N-key) when MHX rig is active.
Alternatively, run the script in the script editor (Alt-P), and access from UI panel.
"""
bl_info = {
"name": "MHX Mocap",
"author": "Thomas Larsson",
"version": "0.7",
"blender": (2, 5, 6),
"api": 35774,
"location": "View3D > Properties > MHX Mocap",
"description": "Mocap tool for MHX rig",
"warning": "",
'wiki_url': 'http://sites.google.com/site/makehumandocs/blender-export-and-mhx/mocap-tool',
"category": "3D View"}
"""
Properties:
Scale:
for BVH import. Choose scale so that the vertical distance between hands and feet
are the same for MHX and BVH rigs.
Good values are: CMU: 0.6, OSU: 0.1
Start frame:
for BVH import
Rot90:
for BVH import. Rotate armature 90 degrees, so Z points up.
Simplify FCurves:
Include FCurve simplifcation.
Max loc error:
Max error allowed for simplification of location FCurves
Max rot error:
Max error allowed for simplification of rotation FCurves
Buttons:
Load BVH file (.bvh):
Load bvh file with Z up
Silence constraints:
Turn off constraints that may conflict with mocap data.
Retarget selected to MHX:
Retarget actions of selected BVH rigs to the active MHX rig.
Simplify FCurves:
Simplifiy FCurves of active action, allowing max errors specified above.
Load, retarget, simplify:
Load bvh file, retarget the action to the active MHX rig, and simplify FCurves.
Batch run:
Load all bvh files in the given directory, whose name start with the
given prefix, and create actions (with simplified FCurves) for the active MHX rig.
"""
import bpy, os, mathutils, math, time
from math import sin, cos
from mathutils import *
from bpy.props import *
from bpy_extras.io_utils import ImportHelper
###################################################################################
# BVH importer.
# The importer that comes with Blender had memory leaks which led to instability.
# It also creates a weird skeleton from CMU data, with hands theat start at the wrist
# and ends at the elbow.
#
#
# class CNode:
#
class CNode:
def __init__(self, words, parent):
name = words[1]
for word in words[2:]:
name += ' '+word
self.name = name
self.parent = parent
self.children = []
self.head = Vector((0,0,0))
self.offset = Vector((0,0,0))
if parent:
parent.children.append(self)
self.channels = []
self.matrix = None
self.inverse = None
return
def __repr__(self):
return "CNode %s" % (self.name)
def display(self, pad):
vec = self.offset
if vec.length < Epsilon:
c = '*'
else:
c = ' '
print("%s%s%10s (%8.3f %8.3f %8.3f)" % (c, pad, self.name, vec[0], vec[1], vec[2]))
for child in self.children:
child.display(pad+" ")
return
def build(self, amt, orig, parent):
self.head = orig + self.offset
if not self.children:
return self.head
zero = (self.offset.length < Epsilon)
eb = amt.edit_bones.new(self.name)
if parent:
eb.parent = parent
eb.head = self.head
tails = Vector((0,0,0))
for child in self.children:
tails += child.build(amt, self.head, eb)
n = len(self.children)
eb.tail = tails/n
#self.matrix = eb.matrix.rotation_part()
(loc, rot, scale) = eb.matrix.decompose()
self.matrix = rot.to_matrix()
self.inverse = self.matrix.copy()
self.inverse.invert()
if zero:
return eb.tail
else:
return eb.head
#
# readBvhFile(context, filepath, scn, scan):
# Custom importer
#
Location = 1
Rotation = 2
Hierarchy = 1
Motion = 2
Frames = 3
Deg2Rad = math.pi/180
Epsilon = 1e-5
def readBvhFile(context, filepath, scn, scan):
global theTarget
ensureInited(context)
scale = scn['MhxBvhScale']
startFrame = scn['MhxStartFrame']
endFrame = scn['MhxEndFrame']
rot90 = scn['MhxRot90Anim']
subsample = scn['MhxSubsample']
defaultSS = scn['MhxDefaultSS']
print(filepath)
fileName = os.path.realpath(os.path.expanduser(filepath))
(shortName, ext) = os.path.splitext(fileName)
if ext.lower() != ".bvh":
raise NameError("Not a bvh file: " + fileName)
print( "Loading BVH file "+ fileName )
trgRig = context.object
bpy.ops.object.mode_set(mode='POSE')
trgPbones = trgRig.pose.bones
time1 = time.clock()
level = 0
nErrors = 0
scn = context.scene
fp = open(fileName, "rU")
print( "Reading skeleton" )
lineNo = 0
for line in fp:
words= line.split()
lineNo += 1
if len(words) == 0:
continue
key = words[0].upper()
if key == 'HIERARCHY':
status = Hierarchy
elif key == 'MOTION':
if level != 0:
raise NameError("Tokenizer out of kilter %d" % level)
if scan:
return root
guessTargetArmature(trgRig)
amt = bpy.data.armatures.new("BvhAmt")
rig = bpy.data.objects.new("BvhRig", amt)
scn.objects.link(rig)
scn.objects.active = rig
bpy.ops.object.mode_set(mode='EDIT')
root.build(amt, Vector((0,0,0)), None)
#root.display('')
bpy.ops.object.mode_set(mode='OBJECT')
status = Motion
print("Reading motion")
elif status == Hierarchy:
if key == 'ROOT':
node = CNode(words, None)
root = node
nodes = [root]
elif key == 'JOINT':
node = CNode(words, node)
nodes.append(node)
elif key == 'OFFSET':
(x,y,z) = (float(words[1]), float(words[2]), float(words[3]))
if rot90:
node.offset = scale*Vector((x,-z,y))
else:
node.offset = scale*Vector((x,y,z))
elif key == 'END':
node = CNode(words, node)
elif key == 'CHANNELS':
oldmode = None
for word in words[2:]:
if rot90:
(index, mode, sign) = channelZup(word)
else:
(index, mode, sign) = channelYup(word)
if mode != oldmode:
indices = []
node.channels.append((mode, indices))
oldmode = mode
indices.append((index, sign))
elif key == '{':
level += 1
elif key == '}':
level -= 1
node = node.parent
else:
raise NameError("Did not expect %s" % words[0])
elif status == Motion:
if key == 'FRAMES:':
nFrames = int(words[1])
elif key == 'FRAME' and words[1].upper() == 'TIME:':
frameTime = float(words[2])
frameFactor = int(1.0/(25*frameTime) + 0.49)
if defaultSS:
subsample = frameFactor
status = Frames
frame = 0
frameno = 1
findSrcArmature(context, rig)
bpy.ops.object.mode_set(mode='POSE')
pbones = rig.pose.bones
for pb in pbones:
#try:
# trgName = theArmature[pb.name.lower()]
# pb.rotation_mode = trgPbones[trgName].rotation_mode
#except:
pb.rotation_mode = 'QUATERNION'
elif status == Frames:
if (frame >= startFrame and
frame <= endFrame and
frame % subsample == 0):
addFrame(words, frameno, nodes, pbones, scale)
if frameno % 200 == 0:
print(frame)
frameno += 1
frame += 1
fp.close()
setInterpolation(rig)
time2 = time.clock()
print("Bvh file loaded in %.3f s" % (time2-time1))
return rig
#
# addFrame(words, frame, nodes, pbones, scale):
#
def addFrame(words, frame, nodes, pbones, scale):
m = 0
first = True
for node in nodes:
name = node.name
try:
pb = pbones[name]
except:
pb = None
if pb:
for (mode, indices) in node.channels:
if mode == Location:
vec = Vector((0,0,0))
for (index, sign) in indices:
vec[index] = sign*float(words[m])
m += 1
if first:
pb.location = (scale * vec - node.head) * node.inverse
for n in range(3):
pb.keyframe_insert('location', index=n, frame=frame, group=name)
first = False
elif mode == Rotation:
mats = []
for (axis, sign) in indices:
angle = sign*float(words[m])*Deg2Rad
mats.append(Matrix.Rotation(angle, 3, axis))
m += 1
mat = node.inverse * mats[0] * mats[1] * mats[2] * node.matrix
setRotation(pb, mat, frame, name)
return
#
# channelYup(word):
# channelZup(word):
#
def channelYup(word):
if word == 'Xrotation':
return ('X', Rotation, +1)
elif word == 'Yrotation':
return ('Y', Rotation, +1)
elif word == 'Zrotation':
return ('Z', Rotation, +1)
elif word == 'Xposition':
return (0, Location, +1)
elif word == 'Yposition':
return (1, Location, +1)
elif word == 'Zposition':
return (2, Location, +1)
def channelZup(word):
if word == 'Xrotation':
return ('X', Rotation, +1)
elif word == 'Yrotation':
return ('Z', Rotation, +1)
elif word == 'Zrotation':
return ('Y', Rotation, -1)
elif word == 'Xposition':
return (0, Location, +1)
elif word == 'Yposition':
return (2, Location, +1)
elif word == 'Zposition':
return (1, Location, -1)
#
# end Bvh importer
###################################################################################
###################################################################################
#
# Supported source armatures
#
# OsuArmature
# www.accad.osu.edu/research/mocap/mocap_data.htm
#
OsuArmature = {
'hips' : 'Root',
'tospine' : 'Spine1',
'spine' : 'Spine2',
'spine1' : 'Spine3',
'neck' : 'Neck',
'head' : 'Head',
'leftshoulder' : 'Shoulder_L',
'leftarm' : 'UpArm_L',
'leftforearm' : 'LoArm_L',
'lefthand' : 'Hand_L',
'rightshoulder' : 'Shoulder_R',
'rightarm' : 'UpArm_R',
'rightforearm' : 'LoArm_R',
'righthand' : 'Hand_R',
'leftupleg' : 'UpLeg_L',
'leftleg' : 'LoLeg_L',
'leftfoot' : 'Foot_L',
'lefttoebase' : 'Toe_L',
'rightupleg' : 'UpLeg_R',
'rightleg' : 'LoLeg_R',
'rightfoot' : 'Foot_R',
'righttoebase' : 'Toe_R',
}
#
# MBArmature
#
MBArmature = {
'hips' : 'Root',
'lowerback' : 'Spine1',
'spine' : 'Spine2',
'spine1' : 'Spine3',
'neck' : 'Neck',
'neck1' : 'Head',
'head' : None,
'leftshoulder' : 'Shoulder_L',
'leftarm' : 'UpArm_L',
'leftforearm' : 'LoArm_L',
'lefthand' : 'Hand_L',
'lefthandindex1' : None,
'leftfingerbase' : None,
'lfingers' : None,
'lthumb' : None,
'rightshoulder' : 'Shoulder_R',
'rightarm' : 'UpArm_R',
'rightforearm' : 'LoArm_R',
'righthand' : 'Hand_R',
'righthandindex1' : None,
'rightfingerbase' : None,
'rfingers' : None,
'rthumb' : None,
'lhipjoint' : 'Hip_L',
'leftupleg' : 'UpLeg_L',
'leftleg' : 'LoLeg_L',
'leftfoot' : 'Foot_L',
'lefttoebase' : 'Toe_L',
'rhipjoint' : 'Hip_R',
'rightupleg' : 'UpLeg_R',
'rightleg' : 'LoLeg_R',
'rightfoot' : 'Foot_R',
'righttoebase' : 'Toe_R',
}
#
# MegaArmature
#
MegaArmature = {
'hip' : 'Root',
'abdomen' : 'Spine1',
'chest' : 'Spine3',
'neck' : 'Neck',
'head' : 'Head',
'left eye' : None,
'right eye' : None,
'left collar' : 'Shoulder_L',
'left shoulder' : 'UpArm_L',
'left forearm' : 'LoArm_L',
'left hand' : 'Hand_L',
'left thumb 1' : None,
'left thumb 2' : None,
'left thumb 3' : None,
'left index 1' : None,
'left index 2' : None,
'left index 3' : None,
'left mid 1' : None,
'left mid 2' : None,
'left mid 3' : None,
'left ring 1' : None,
'left ring 2' : None,
'left ring 3' : None,
'left pinky 1' : None,
'left pinky 2' : None,
'left pinky 3' : None,
'right collar' : 'Shoulder_R',
'right shoulder' : 'UpArm_R',
'right forearm' : 'LoArm_R',
'right hand' : 'Hand_R',
'right thumb 1' : None,
'right thumb 2' : None,
'right thumb 3' : None,
'right index 1' : None,
'right index 2' : None,
'right index 3' : None,
'right mid 1' : None,
'right mid 2' : None,
'right mid 3' : None,
'right ring 1' : None,
'right ring 2' : None,
'right ring 3' : None,
'right pinky 1' : None,
'right pinky 2' : None,
'right pinky 3' : None,
'left thigh' : 'UpLeg_L',
'left shin' : 'LoLeg_L',
'left foot' : 'Foot_L',
'left toe' : 'Toe_L',
'right thigh' : 'UpLeg_R',
'right shin' : 'LoLeg_R',
'right foot' : 'Foot_R',
'right toe' : 'Toe_R',
}
HDMArmature = {
'hip' : 'Root',
'lhipjoint' : 'Hip_L',
'lfemur' : 'UpLeg_L',
'ltibia' : 'LoLeg_L',
'lfoot' : 'Foot_L',
'ltoes' : 'Toe_L',
'rhipjoint' : 'Hip_R',
'rfemur' : 'UpLeg_R',
'rtibia' : 'LoLeg_R',
'rfoot' : 'Foot_R',
'rtoes' : 'Toe_R',
'lowerback' : 'Spine1',
'upperback' : 'Spine2',
'thorax' : 'Spine3',
'lowerneck' : 'LowerNeck',
'upperneck' : 'Neck',
'head' : 'Head',
'lclavicle' : 'Shoulder_L',
'lhumerus' : 'UpArm_L',
'lradius' : 'LoArm_L',
'lwrist' : 'Hand0_L',
'lhand' : 'Hand_L',
'lfingers' : None,
'lthumb' : 'Finger1_L',
'rclavicle' : 'Shoulder_R',
'rhumerus' : 'UpArm_R',
'rradius' : 'LoArm_R',
'rwrist' : 'Hand0_R',
'rhand' : 'Hand_R',
'rfingers' : None,
'rthumb' : 'Finger1_R',
}
EyesArmature = {
'hips' : 'Root',
'lefthip' : 'UpLeg_L',
'leftknee' : 'LoLeg_L',
'leftankle' : 'Foot_L',
'righthip' : 'UpLeg_R',
'rightknee' : 'LoLeg_R',
'rightankle' : 'Foot_R',
'chest' : 'Spine1',
'chest2' : 'Spine2',
'cs_bvh' : 'Spine3',
'leftcollar' : 'Shoulder_L',
'leftshoulder' : 'UpArm_L',
'leftelbow' : 'LoArm_L',
'leftwrist' : 'Hand_L',
'rightcollar' : 'Shoulder_R',
'rightshoulder' : 'UpArm_R',
'rightelbow' : 'LoArm_R',
'rightwrist' : 'Hand_R',
'neck' : 'Neck',
'head' : 'Head',
}
MaxArmature = {
'hips' : 'Root',
'lhipjoint' : 'Hip_L',
'lefthip' : 'UpLeg_L',
'leftknee' : 'LoLeg_L',
'leftankle' : 'Foot_L',
'lefttoe' : 'Toe_L',
'rhipjoint' : 'Hip_R',
'righthip' : 'UpLeg_R',
'rightknee' : 'LoLeg_R',
'rightankle' : 'Foot_R',
'righttoe' : 'Toe_R',
'lowerback' : 'Spine1',
'chest' : 'Spine2',
'chest2' : 'Spine3',
'lowerneck' : 'LowerNeck',
'neck' : 'Neck',
'head' : 'Head',
'leftcollar' : 'Shoulder_L',
'leftshoulder' : 'UpArm_L',
'leftelbow' : 'LoArm_L',
'leftwrist' : 'Hand_L',
'lhand' : None,
'lfingers' : None,
'lthumb' : None,
'rightcollar' : 'Shoulder_R',
'rightshoulder' : 'UpArm_R',
'rightelbow' : 'LoArm_R',
'rightwrist' : 'Hand_R',
'rhand' : None,
'rfingers' : None,
'rthumb' : None,
}
DazArmature = {
'hip' : 'Root',
'abdomen' : 'Spine1',
'chest' : 'Spine3',
'neck' : 'Neck',
'head' : 'Head',
'lefteye' : None,
'righteye' : None,
'figurehair' : None,
'lcollar' : 'Shoulder_L',
'lshldr' : 'UpArm_L',
'lforearm' : 'LoArm_L',
'lhand' : 'Hand_L',
'lthumb1' : None,
'lthumb2' : None,
'lthumb3' : None,
'lindex1' : None,
'lindex2' : None,
'lindex3' : None,
'lmid1' : None,
'lmid2' : None,
'lmid3' : None,
'lring1' : None,
'lring2' : None,
'lring3' : None,
'lpinky1' : None,
'lpinky2' : None,
'lpinky3' : None,
'rcollar' : 'Shoulder_R',
'rshldr' : 'UpArm_R',
'rforearm' : 'LoArm_R',
'rhand' : 'Hand_R',
'rthumb1' : None,
'rthumb2' : None,
'rthumb3' : None,
'rindex1' : None,
'rindex2' : None,
'rindex3' : None,
'rmid1' : None,
'rmid2' : None,
'rmid3' : None,
'rring1' : None,
'rring2' : None,
'rring3' : None,
'rpinky1' : None,
'rpinky2' : None,
'rpinky3' : None,
'lbuttock' : 'Hip_L',
'lthigh' : 'UpLeg_L',
'lshin' : 'LoLeg_L',
'lfoot' : 'Foot_L',
'ltoe' : 'Toe_L',
'rbuttock' : 'Hip_R',
'rthigh' : 'UpLeg_R',
'rshin' : 'LoLeg_R',
'rfoot' : 'Foot_R',
'rtoe' : 'Toe_R',
}
theArmatures = {
'MB' : MBArmature,
'OSU' : OsuArmature,
'Mega' : MegaArmature,
'HDM' : HDMArmature,
'3dsMax' : MaxArmature,
'Eyes' : EyesArmature,
'Daz' : DazArmature,
}
theArmatureList = [ 'OSU', 'MB', 'Mega', 'HDM', 'Eyes', 'Daz', '3dsMax' ]
MBFixes = {
'UpLeg_L' : ( Matrix.Rotation(0.4, 3, 'Y') * Matrix.Rotation(-0.45, 3, 'Z'), 0),
'UpLeg_R' : ( Matrix.Rotation(-0.4, 3, 'Y') * Matrix.Rotation(0.45, 3, 'Z'), 0),
'LoLeg_L' : ( Matrix.Rotation(-0.2, 3, 'Y'), 0),
'LoLeg_R' : ( Matrix.Rotation(0.2, 3, 'Y'), 0),
'Foot_L' : ( Matrix.Rotation(-0.3, 3, 'Z'), 0),
'Foot_R' : ( Matrix.Rotation(0.3, 3, 'Z'), 0),
#'UpArm_L' : ( Matrix.Rotation(0.1, 3, 'X'), 0),
#'UpArm_R' : ( Matrix.Rotation(0.1, 3, 'X'), 0),
}
HDMFixes = {
'UpLeg_L' : ( Matrix.Rotation(0.4, 3, 'Y') * Matrix.Rotation(-0.45, 3, 'Z'), 0),
'UpLeg_R' : ( Matrix.Rotation(-0.4, 3, 'Y') * Matrix.Rotation(0.45, 3, 'Z'), 0),
'LoLeg_L' : ( Matrix.Rotation(-0.4, 3, 'Y'), 0),
'LoLeg_R' : ( Matrix.Rotation(0.4, 3, 'Y'), 0),
'UpArm_L' : ( Matrix.Rotation(0.1, 3, 'X'), 0),
'UpArm_R' : ( Matrix.Rotation(0.1, 3, 'X'), 0),
}
OsuFixes = {}
MegaFixes = {}
MaxFixes = {
'UpLeg_L' : ( Matrix.Rotation(0.4, 3, 'Y') * Matrix.Rotation(-0.45, 3, 'Z'), 0),
'UpLeg_R' : ( Matrix.Rotation(-0.4, 3, 'Y') * Matrix.Rotation(0.45, 3, 'Z'), 0),
'LoLeg_L' : ( Matrix.Rotation(-0.3, 3, 'Y'), 0),
'LoLeg_R' : ( Matrix.Rotation(0.3, 3, 'Y'), 0),
#'Foot_L' : ( Matrix.Rotation(-0.3, 3, 'Z'), 0),
#'Foot_R' : ( Matrix.Rotation(0.3, 3, 'Z'), 0),
'UpArm_L' : (Matrix.Rotation(1.57, 3, 'Z'), 1.57),
'LoArm_L' : (None, 1.57),
'Hand_L' : (None, 1.57),
'UpArm_R' : (Matrix.Rotation(-1.57, 3, 'Z'), -1.57),
'LoArm_R' : (None, -1.57),
'Hand_R' : (None, -1.57),
}
EyesFixes = {
'Head2' : (Matrix.Rotation(0.2, 3, 'X'), 0),
'Spine2' : (Matrix.Rotation(0.3, 3, 'X'), 0),
'UpArm_L' : (Matrix.Rotation(1.57, 3, 'Z')*Matrix.Rotation(-0.1, 3, 'X'), 1.57),
'LoArm_L' : (None, 1.57),
'Hand_L' : (None, 1.57),
'UpArm_R' : (Matrix.Rotation(-1.57, 3, 'Z')*Matrix.Rotation(-0.1, 3, 'X'), -1.57),
'LoArm_R' : (None, -1.57),
'Hand_R' : (None, -1.57),
}
DazFixes = {}
theFixesList = {
'MB' : MBFixes,
'OSU' : OsuFixes,
'Mega' : MegaFixes,
'HDM' : HDMFixes,
'3dsMax': MaxFixes,
'Eyes': EyesFixes,
'Daz' : DazFixes,
}
#
# end supported source armatures
###################################################################################
#
# Mhx rig
#
MhxFkBoneList = [
'Root', 'Hips', 'Spine1', 'Spine2', 'Spine3', 'Shoulders', 'LowerNeck', 'Neck', 'Head', 'Sternum',
'Shoulder_L', 'ShoulderEnd_L', 'ArmLoc_L', 'UpArm_L', 'LoArm_L', 'Hand0_L', 'Hand_L',
'Shoulder_R', 'ShoulderEnd_R', 'ArmLoc_R', 'UpArm_R', 'LoArm_R', 'Hand0_R', 'Hand_R',
'Hip_L', 'LegLoc_L', 'UpLeg_L', 'LoLeg_L', 'Foot_L', 'Toe_L', 'LegFK_L',
'Hip_R', 'LegLoc_R', 'UpLeg_R', 'LoLeg_R', 'Foot_R', 'Toe_R', 'LegFK_R',
]
F_Rev = 1
F_LR = 2
#
# theIkParent
# bone : (realParent, fakeParent, copyRot, reverse)
#
MhxIkParents = {
'Elbow_L' : (None, 'UpArm_L', None, False),
'ElbowPT_L' : ('Shoulder_L', 'UpArm_L', None, False),
'Wrist_L' : (None, 'LoArm_L', 'Hand_L', False),
'LegIK_L' : (None, 'Toe_L', 'LegFK_L', False),
'KneePT_L' : ('Hips', 'UpLeg_L', None, False),
'ToeRev_L' : ('LegIK_L', 'Foot_L', 'Toe_L', True),
'FootRev_L' : ('ToeRev_L', 'LoLeg_L', 'Foot_L', True),
'Ankle_L' : ('FootRev_L', 'LoLeg_L', None, False),
'Elbow_R' : (None, 'UpArm_R', None, False),
'ElbowPT_R' : ('Shoulder_R', 'UpArm_R', None, False),
'Wrist_R' : (None, 'LoArm_R', 'Hand_R', False),
'LegIK_R' : (None, 'Toe_R', 'LegFK_R', False),
'KneePT_R' : ('Hips', 'UpLeg_R', None, False),
'ToeRev_R' : ('LegIK_R', 'Foot_R', 'Toe_R', True),
'FootRev_R' : ('ToeRev_R', 'LoLeg_R', 'Foot_R', True),
'Ankle_R' : ('FootRev_R', 'LoLeg_R', None, False),
}
MhxIkBoneList = [
'Elbow_L', 'ElbowPT_L', 'Wrist_L',
'LegIK_L', 'KneePT_L', # 'ToeRev_L', 'FootRev_L', 'Ankle_L',
'Elbow_R', 'ElbowPT_R', 'Wrist_R',
'LegIK_R', 'KneePT_R', # 'ToeRev_R', 'FootRev_R', 'Ankle_R',
]
MhxGlobalBoneList = [
'Root',
]
###################################################################################
#
# Other supported target armatures
#
# If you want to use the mocap tool for your own armature, it should suffice to
# modify this section (down to getParentName()).
#
T_MHX = 1
T_Rorkimaru = 2
T_Game = 3
T_Custom = 4
theTarget = 0
theArmature = None
RorkimaruBones = [
('Root', 'Root'),
('Spine1', 'Spine1'),
('Spine2', 'Spine3'),
('Neck', 'Neck'),
('Head', 'Head'),
('Clavicle_L', 'Shoulder_L'),
('UpArm_L', 'UpArm_L'),
('LoArm_L', 'LoArm_L'),
('Hand_L', 'Hand_L'),
('Clavicle_R', 'Shoulder_R'),
('UpArm_R', 'UpArm_R'),
('LoArm_R', 'LoArm_R'),
('Hand_R', 'Hand_R'),
('UpLeg_L', 'UpLeg_L'),
('LoLeg_L', 'LoLeg_L'),
('Foot_L', 'Foot_L'),
('Toe_L', 'Toe_L'),
('UpLeg_R', 'UpLeg_R'),
('LoLeg_R', 'LoLeg_R'),
('Foot_R', 'Foot_R'),
('Toe_R', 'Toe_R'),
]
GameBones = [
('Root', 'Root'),
('Spine1', 'Spine1'),
('Spine2', 'Spine2'),
('Spine3', 'Spine3'),
('Neck', 'Neck'),
('Head', 'Head'),
('Clavicle_L', 'Shoulder_L'),
('UpArm_L', 'UpArm_L'),
('LoArm_L', 'LoArm_L'),
('Hand_L', 'Hand_L'),
('Clavicle_R', 'Shoulder_R'),
('UpArm_R', 'UpArm_R'),
('LoArm_R', 'LoArm_R'),
('Hand_R', 'Hand_R'),
('UpLeg_L', 'UpLeg_L'),
('LoLeg_L', 'LoLeg_L'),
('Foot_L', 'Foot_L'),
('Toe_L', 'Toe_L'),
('UpLeg_R', 'UpLeg_R'),
('LoLeg_R', 'LoLeg_R'),
('Foot_R', 'Foot_R'),
('Toe_R', 'Toe_R'),
]
GameIkParents = {
'Wrist_L' : (None, 'LoArm_L', 'Hand_L', False),
'Ankle_L' : (None, 'LoLeg_L', None, False),
'Wrist_R' : (None, 'LoArm_R', 'Hand_R', False),
'Ankle_R' : (None, 'LoLeg_R', None, False),
}
GameIkBoneList = [ 'Wrist_L', 'Wrist_R', 'Ankle_L', 'Ankle_R' ]
# bone : (realParent, fakeParent, copyRot, reverse)
#
#
#
GameNames = {
'MasterFloor' : None,
'MasterFloorInv' : None,
'RootInv' : 'Root',
'HipsInv' : 'Root',
'Hips' : 'Root',
'Spine3Inv' : 'Spine3',
}
RorkimaruNames = {
'MasterFloor' : None,
'MasterFloorInv' : None,
'RootInv' : 'Root',
'HipsInv' : 'Root',
'Hips' : 'Root',
'Spine2Inv' : 'Spine2',
'Spine3' : 'Spine2',
}
#
# getTrgBone(b):
# getSrcBone(b):
# getParentName(b):
#
def getTrgBone(b):
if theTarget == T_MHX:
return b
else:
try:
return theTrgBone[b]
except:
return None
def getSrcBone(b):
if theTarget == T_MHX:
return b
else:
try:
return theSrcBone[b]
except:
return None
def getParentName(b):
if b == None:
return None
elif theTarget == T_MHX:
if b == 'MasterFloor':
return None
else:
return b
elif theTarget == T_Rorkimaru:
try:
return RorkimaruNames[b]
except:
return b
elif theTarget == T_Game:
try:
return GameNames[b]
except:
return b
else:
return b
#
# guessTargetArmature(trgRig):
# setupTargetArmature():
# testTargetRig(bones, rigBones):
#
def guessTargetArmature(trgRig):
global theTarget, theFkBoneList, theIkBoneList, theGlobalBoneList, theIkParents
global theSrcBone, theTrgBone, theParents, theTargetRolls, theTargetMats
bones = trgRig.data.bones.keys()
try:
custom = trgRig['MhxTargetRig']
except:
custom = False
if custom:
theTarget = T_Custom
name = "Custom %s" % trgRig.name
elif 'KneePT_L' in bones:
theTarget = T_MHX
name = "MHX"
elif testTargetRig(bones, GameBones):
theTarget = T_Game
name = "Game"
elif testTargetRig(bones, RorkimaruBones):
theTarget = T_Rorkimaru
name = "Rorkimaru"
else:
print("Bones", bones)
raise NameError("Did not recognize target armature")
print("Target armature %s" % name)
theParents = {}
theTargetRolls = {}
theTargetMats = {}
if theTarget == T_MHX:
theFkBoneList = MhxFkBoneList
theIkBoneList = MhxIkBoneList
theGlobalBoneList = MhxGlobalBoneList
theIkParents = MhxIkParents
for bone in trgRig.data.bones:
try:
roll = bone['Roll']
except:
roll = 0
if abs(roll) > 0.1:
theTargetRolls[bone.name] = roll
else:
theFkBoneList = []
theGlobalBoneList = []
theTrgBone = {}
theSrcBone = {}
if theTarget == T_Custom:
(bones, theParents, theTargetRolls, theTargetMats, theIkBoneList, theIkParents) = makeTargetAssoc(trgRig)
elif theTarget == T_Rorkimaru:
bones = RorkimaruBones
theIkBoneList = GameIkBoneList
theIkParents = GameIkParents
elif theTarget == T_Game:
bones = GameBones
theIkBoneList = GameIkBoneList
theIkParents = GameIkParents
else:
raise NameError("Unknown target %s" % theTarget)
for (trg,src) in bones:
theFkBoneList.append(trg)
theSrcBone[trg] = src
theTrgBone[src] = trg
if src in MhxGlobalBoneList:
theGlobalBoneList.append(trg)
return
def testTargetRig(bones, rigBones):
for (b, mb) in rigBones:
if b not in bones:
print("Fail", b, mb)
return False
return True
# end supported target armatures
###################################################################################
#
# class CEditBone():
#
class CEditBone():
def __init__(self, bone):
self.name = bone.name
self.head = bone.head.copy()
self.tail = bone.tail.copy()
self.roll = bone.roll
if bone.parent:
self.parent = getParentName(bone.parent.name)
else:
self.parent = None
if self.parent:
self.use_connect = bone.use_connect
else:
self.use_connect = False
#self.matrix = bone.matrix.copy().rotation_part()
(loc, rot, scale) = bone.matrix.decompose()
self.matrix = rot.to_matrix()
self.inverse = self.matrix.copy()
self.inverse.invert()
def __repr__(self):
return ("%s p %s\n h %s\n t %s\n" % (self.name, self.parent, self.head, self.tail))
#
# renameBones(bones00, rig00, action):
#
def renameBones(bones00, rig00, action):
bones90 = {}
bpy.ops.object.mode_set(mode='EDIT')
ebones = rig00.data.edit_bones
setbones = []
for bone00 in bones00:
name00 = bone00.name
lname = name00.lower()
try:
name90 = theArmature[lname]
except:
name90 = theArmature[lname.replace(' ','_')]
eb = ebones[name00]
if name90:
eb.name = name90
bones90[name90] = CEditBone(eb)
grp = action.groups[name00]
grp.name = name90
setbones.append((eb, name90))
else:
eb.name = '_' + name00
for (eb, name) in setbones:
eb.name = name
#createExtraBones(ebones, bones90)
bpy.ops.object.mode_set(mode='POSE')
return
#
# createExtraBones(ebones, bones90):
#
def createExtraBones(ebones, bones90):
for suffix in ['_L', '_R']:
try:
foot = ebones['Foot'+suffix]
except:
foot = None
try:
toe = ebones['Toe'+suffix]
except:
toe = None
if not toe:
nameSrc = 'Toe'+suffix
toe = ebones.new(name=nameSrc)
toe.head = foot.tail
toe.tail = toe.head - Vector((0, 0.5*foot.length, 0))
toe.parent = foot
bones90[nameSrc] = CEditBone(toe)
nameSrc = 'Leg'+suffix
eb = ebones.new(name=nameSrc)
eb.head = 2*toe.head - toe.tail
eb.tail = 4*toe.head - 3*toe.tail
eb.parent = toe
bones90[nameSrc] = CEditBone(eb)
nameSrc = 'Ankle'+suffix
eb = ebones.new(name=nameSrc)
eb.head = foot.head
eb.tail = 2*foot.head - foot.tail
eb.parent = ebones['LoLeg'+suffix]
bones90[nameSrc] = CEditBone(eb)
return
#
# makeVectorDict(ob, channels):
#
def makeVectorDict(ob, channels):
fcuDict = {}
for fcu in ob.animation_data.action.fcurves:
words = fcu.data_path.split('"')
if words[2] in channels:
name = words[1]
try:
x = fcuDict[name]
except:
fcuDict[name] = []
fcuDict[name].append((fcu.array_index, fcu))
vecDict = {}
for name in fcuDict.keys():
fcuDict[name].sort()
(index, fcu) = fcuDict[name][0]
m = len(fcu.keyframe_points)
for (index, fcu) in fcuDict[name]:
if len(fcu.keyframe_points) != m:
raise NameError("Not all F-Curves for %s have the same length" % name)
vectors = []
for kp in range(m):
vectors.append([])
for (index, fcu) in fcuDict[name]:
n = 0
for kp in fcu.keyframe_points:
vectors[n].append(kp.co[1])
n += 1
vecDict[name] = vectors
return vecDict
#
# renameBvhRig(rig00, filepath):
#
def renameBvhRig(rig00, filepath):
base = os.path.basename(filepath)
(filename, ext) = os.path.splitext(base)
print("File", filename, len(filename))
if len(filename) > 12:
words = filename.split('_')
if len(words) == 1:
words = filename.split('-')
name = 'Y_'
if len(words) > 1:
words = words[1:]
for word in words:
name += word
else:
name = 'Y_' + filename
print("Name", name)
rig00.name = name
action = rig00.animation_data.action
action.name = name
bones00 = []
bpy.ops.object.mode_set(mode='EDIT')
for bone in rig00.data.edit_bones:
bones00.append( CEditBone(bone) )
bpy.ops.object.mode_set(mode='POSE')
return (rig00, bones00, action)
#
# copyAnglesIK():
#
def copyAnglesIK(context):
trgRig = context.object
guessTargetArmature(trgRig)
trgAnimations = createTargetAnimation(context, trgRig)
insertAnimation(context, trgRig, trgAnimations, theFkBoneList)
onoff = toggleLimitConstraints(trgRig)
setLimitConstraints(trgRig, 0.0)
poseTrgIkBones(context, trgRig, trgAnimations)
setInterpolation(trgRig)
if onoff == 'OFF':
setLimitConstraints(trgRig, 1.0)
else:
setLimitConstraints(trgRig, 0.0)
return
#
# guessSrcArmature(rig):
# setArmature(rig)
#
def guessSrcArmature(rig):
global theArmatures
bestMisses = 1000
misses = {}
bones = rig.data.bones
for name in theArmatureList:
amt = theArmatures[name]
nMisses = 0
for bone in bones:
try:
amt[bone.name.lower()]
except:
nMisses += 1
misses[name] = nMisses
if nMisses < bestMisses:
best = amt
bestName = name
bestMisses = nMisses
if bestMisses > 0:
for bone in bones:
print("'%s'" % bone.name)
for (name, n) in misses.items():
print(name, n)
raise NameError('Did not find matching armature. nMisses = %d' % bestMisses)
return (best, bestName)
def findSrcArmature(context, rig):
global theArmature, theArmatures
if useCustomSrcRig(context):
(theArmature, name, fixes) = buildSrcArmature(context, rig)
theArmatures[name] = theArmature
theFixesList[name] = fixes
else:
(theArmature, name) = guessSrcArmature(rig)
rig['MhxArmature'] = name
print("Using matching armature %s." % name)
return
def setArmature(rig):
global theArmature, theArmatures
try:
name = rig['MhxArmature']
except:
raise NameError("No armature set")
theArmature = theArmatures[name]
print("Set armature %s" % name)
return
#
# importAndRename(context, filepath):
#
def importAndRename(context, filepath):
trgRig = context.object
rig = readBvhFile(context, filepath, context.scene, False)
(rig00, bones00, action) = renameBvhRig(rig, filepath)
findSrcArmature(context, rig00)
renameBones(bones00, rig00, action)
setInterpolation(rig00)
rescaleRig(context.scene, trgRig, rig00, action)
return (rig00, action)
#
# rescaleRig(scn, trgRig, srcRig, action):
#
def rescaleRig(scn, trgRig, srcRig, action):
if not scn['MhxAutoScale']:
return
upleg = getTrgBone('UpLeg_L')
trgScale = trgRig.data.bones[upleg].length
srcScale = srcRig.data.bones['UpLeg_L'].length
scale = trgScale/srcScale
print("Rescale %s with factor %f" % (scn.objects.active, scale))
scn['MhxBvhScale'] = scale
bpy.ops.object.mode_set(mode='EDIT')
ebones = srcRig.data.edit_bones
for eb in ebones:
oldlen = eb.length
eb.head *= scale
eb.tail *= scale
bpy.ops.object.mode_set(mode='POSE')
for fcu in action.fcurves:
words = fcu.data_path.split('.')
if words[-1] == 'location':
for kp in fcu.keyframe_points:
kp.co[1] *= scale
return
#
# class CAnimData():
#
class CAnimData():
def __init__(self, name):
self.nFrames = 0
self.parent = None
self.headRest = None
self.vecRest = None
self.tailRest = None
self.roll = 0
self.offsetRest = None
self.matrixRest = None
self.inverseRest = None
self.heads = {}
self.quats = {}
self.matrices = {}
self.name = name
def __repr__(self):
return "<CAnimData n %s p %s f %d>" % (self.name, self.parent, self.nFrames)
#
# createSourceAnimation(context, rig):
# createTargetAnimation(context, rig):
# createAnimData(name, animations, ebones, isTarget):
#
def createSourceAnimation(context, rig):
context.scene.objects.active = rig
animations = {}
for name in MhxFkBoneList:
createAnimData(name, animations, rig.data.bones, False)
return animations
def createTargetAnimation(context, rig):
context.scene.objects.active = rig
animations = {}
for name in theFkBoneList+theIkBoneList:
createAnimData(name, animations, rig.data.bones, True)
return animations
def createAnimData(name, animations, bones, isTarget):
try:
b = bones[name]
except:
return
anim = CAnimData(name)
animations[name] = anim
anim.headRest = b.head_local.copy()
anim.tailRest = b.tail_local.copy()
anim.vecRest = anim.tailRest - anim.headRest
try:
anim.roll = b['Roll']
except:
anim.roll = 0
if isTarget and theTarget == T_Custom:
anim.parent = theParents[name]
elif b.parent:
if isTarget:
anim.parent = getParentName(b.parent.name)
else:
anim.parent = b.parent.name
else:
anim.parent = None
if anim.parent:
try:
animPar = animations[anim.parent]
except:
animPar = None
else:
animPar = None
#print("AD", isTarget, anim.name, anim.parent, animPar)
if animPar:
anim.offsetRest = anim.headRest - animPar.headRest
else:
anim.offsetRest = Vector((0,0,0))
(loc, rot, scale) = b.matrix_local.decompose()
anim.matrixRest = rot.to_matrix()
anim.inverseRest = anim.matrixRest.copy()
anim.inverseRest.invert()
return
#
# insertAnimation(context, rig, animations, boneList):
# insertAnimRoot(root, animations, nFrames, locs, rots):
# insertAnimChild(name, animations, nFrames, rots):
#
def insertAnimation(context, rig, animations, boneList):
context.scene.objects.active = rig
bpy.ops.object.mode_set(mode='POSE')
locs = makeVectorDict(rig, ['].location'])
rots = makeVectorDict(rig, ['].rotation_quaternion', '].rotation_euler'])
try:
root = 'Root'
nFrames = len(locs[root])
except:
root = getTrgBone('Root')
nFrames = len(locs[root])
insertAnimRoot(root, animations, nFrames, locs[root], rots[root])
bones = rig.data.bones
for nameSrc in boneList:
try:
bones[nameSrc]
success = (nameSrc != root)
except:
success = False
if success:
try:
rot = rots[nameSrc]
except:
rot = None
insertAnimChild(nameSrc, animations, nFrames, rot)
def insertAnimRoot(root, animations, nFrames, locs, rots):
anim = animations[root]
if nFrames < 0:
nFrames = len(locs)
anim.nFrames = nFrames
for frame in range(anim.nFrames):
quat = Quaternion(rots[frame])
anim.quats[frame] = quat
matrix = anim.matrixRest * quat.to_matrix() * anim.inverseRest
anim.matrices[frame] = matrix
anim.heads[frame] = Vector(locs[frame]) * anim.matrixRest + anim.headRest
return
def insertAnimChildLoc(nameIK, name, animations, locs):
animIK = animations[nameIK]
anim = animations[name]
animPar = animations[anim.parent]
animIK.nFrames = anim.nFrames
for frame in range(anim.nFrames):
parmat = animPar.matrices[frame]
animIK.heads[frame] = animPar.heads[frame] + anim.offsetRest * parmat
return
def insertAnimChild(name, animations, nFrames, rots):
try:
anim = animations[name]
except:
return None
if nFrames < 0:
nFrames = len(rots)
par = anim.parent
#print("iAC", name, par)
animPar = animations[par]
anim.nFrames = nFrames
quat = Quaternion()
quat.identity()
for frame in range(anim.nFrames):
parmat = animPar.matrices[frame]
if rots:
try:
quat = Quaternion(rots[frame])
except:
quat = Euler(rots[frame]).to_quaternion()
anim.quats[frame] = quat
locmat = anim.matrixRest * quat.to_matrix() * anim.inverseRest
matrix = parmat * locmat
anim.matrices[frame] = matrix
anim.heads[frame] = animPar.heads[frame] + anim.offsetRest*parmat
return anim
#
# poseTrgFkBones(context, trgRig, srcAnimations, trgAnimations, srcFixes)
#
def poseTrgFkBones(context, trgRig, srcAnimations, trgAnimations, srcFixes):
context.scene.objects.active = trgRig
bpy.ops.object.mode_set(mode='POSE')
pbones = trgRig.pose.bones
nameSrc = 'Root'
nameTrg = getTrgBone(nameSrc)
insertLocationKeyFrames(nameTrg, pbones[nameTrg], srcAnimations[nameSrc], trgAnimations[nameTrg])
for nameTrg in theFkBoneList:
nameSrc = getSrcBone(nameTrg)
trgRoll = safeGet(nameTrg, theTargetRolls)
trgFix = safeGet(nameTrg, theTargetMats)
try:
pb = pbones[nameTrg]
animSrc = srcAnimations[nameSrc]
animTrg = trgAnimations[nameTrg]
success = True
except:
success = False
if not success:
pass
elif (nameTrg in theGlobalBoneList) or (not pb.bone.use_inherit_rotation):
print("global", pb)
insertGlobalRotationKeyFrames(nameTrg, pb, animSrc, animTrg, trgRoll, trgFix)
else:
try:
srcFix = srcFixes[nameSrc]
except:
srcFix = None
if srcFix or trgFix:
fixAndInsertLocalRotationKeyFrames(nameTrg, pb, animSrc, animTrg, srcFix, trgRoll, trgFix)
else:
insertLocalRotationKeyFrames(nameTrg, pb, animSrc, animTrg, trgRoll)
insertAnimation(context, trgRig, trgAnimations, theFkBoneList)
setInterpolation(trgRig)
return
#
# safeGet(name, struct):
#
def safeGet(name, struct):
try:
return struct[name]
except:
return None
#
# setRotation(pb, mat, frame, group):
#
def setRotation(pb, rot, frame, group):
if pb.rotation_mode == 'QUATERNION':
try:
quat = rot.to_quaternion()
except:
quat = rot
pb.rotation_quaternion = quat
for n in range(4):
pb.keyframe_insert('rotation_quaternion', index=n, frame=frame, group=group)
else:
try:
euler = rot.to_euler(pb.rotation_mode)
except:
euler = rot
pb.rotation_euler = euler
for n in range(3):
pb.keyframe_insert('rotation_euler', index=n, frame=frame, group=group)
#
# insertLocationKeyFrames(name, pb, animSrc, animTrg):
# insertGlobalRotationKeyFrames(name, pb, animSrc, animTrg, trgRoll, trgFix):
#
def insertLocationKeyFrames(name, pb, animSrc, animTrg):
locs = []
for frame in range(animSrc.nFrames):
loc0 = animSrc.heads[frame] - animTrg.headRest
loc = loc0 * animTrg.inverseRest
locs.append(loc)
pb.location = loc
for n in range(3):
pb.keyframe_insert('location', index=n, frame=frame, group=name)
return locs
def insertIKLocationKeyFrames(nameIK, name, pb, animations):
pb.bone.select = True
animIK = animations[nameIK]
anim = animations[name]
if animIK.parent:
animPar = animations[animIK.parent]
else:
animPar = None
locs = []
for frame in range(anim.nFrames):
if animPar:
loc0 = animPar.heads[frame] + animIK.offsetRest*animPar.matrices[frame]
offset = anim.heads[frame] - loc0
mat = animPar.matrices[frame] * animIK.matrixRest
loc = offset*mat.invert()
else:
offset = anim.heads[frame] - animIK.headRest
loc = offset * animIK.inverseRest
pb.location = loc
for n in range(3):
pb.keyframe_insert('location', index=n, frame=frame, group=nameIK)
return
def insertGlobalRotationKeyFrames(name, pb, animSrc, animTrg, trgRoll, trgFix):
rots = []
animTrg.nFrames = animSrc.nFrames
for frame in range(animSrc.nFrames):
mat90 = animSrc.matrices[frame]
animTrg.matrices[frame] = mat90
matMhx = animTrg.inverseRest * mat90 * animTrg.matrixRest
rot = matMhx.to_quaternion()
rots.append(rot)
setRotation(pb, rot, frame, name)
return rots
def insertLocalRotationKeyFrames(name, pb, animSrc, animTrg, trgRoll):
animTrg.nFrames = animSrc.nFrames
for frame in range(animSrc.nFrames):
rot = animSrc.quats[frame]
rollRot(rot, trgRoll)
animTrg.quats[frame] = rot
setRotation(pb, rot, frame, name)
return
def fixAndInsertLocalRotationKeyFrames(name, pb, animSrc, animTrg, srcFix, trgRoll, trgFix):
(fixMat, srcRoll) = srcFix
animTrg.nFrames = animSrc.nFrames
for frame in range(animSrc.nFrames):
matSrc = animSrc.quats[frame].to_matrix()
if fixMat:
matMhx = fixMat * matSrc
else:
matMhx = matSrc
if trgFix:
matTrg = trgFix * matMhx
else:
matTrg = matMhx
rot = matMhx.to_quaternion()
rollRot(rot, srcRoll)
rollRot(rot, trgRoll)
animTrg.quats[frame] = rot
setRotation(pb, rot, frame, name)
return
#
# rollRot(rot, roll):
#
def rollRot(rot, roll):
if not roll:
return
x = rot.x
z = rot.z
rot.x = x*cos(roll) - z*sin(roll)
rot.z = x*sin(roll) + z*cos(roll)
return
#
# poseTrgIkBones(context, trgRig, trgAnimations)
#
def poseTrgIkBones(context, trgRig, trgAnimations):
bpy.ops.object.mode_set(mode='POSE')
pbones = trgRig.pose.bones
for name in theIkBoneList:
(realPar, fakePar, copyRot, reverse) = theIkParents[name]
pb = pbones[name]
pb.bone.select = True
if copyRot:
animCopy = trgAnimations[copyRot]
else:
animCopy = None
if reverse:
insertReverseIkKeyFrames(name, pb, trgAnimations[name], trgAnimations[realPar], animCopy)
elif realPar:
insertParentedIkKeyFrames(name, pb, trgAnimations[name], trgAnimations[realPar], trgAnimations[fakePar], animCopy)
else:
insertRootIkKeyFrames(name, pb, trgAnimations[name], trgAnimations[fakePar], animCopy)
return
#
# insertParentedIkKeyFrames(name, pb, anim, animReal, animFake, animCopy):
#
def insertParentedIkKeyFrames(name, pb, anim, animReal, animFake, animCopy):
offsetFake = anim.headRest - animFake.headRest
offsetReal = anim.headRest - animReal.headRest
if animCopy:
roll = anim.roll - animCopy.roll
else:
roll = 0
for frame in range(animFake.nFrames):
locAbs = animFake.heads[frame] + offsetFake*animFake.matrices[frame]
headAbs = animReal.heads[frame] + offsetReal*animReal.matrices[frame]
#debugPrintVecVec(locAbs, headAbs)
offset = locAbs - headAbs
mat = animReal.matrices[frame] * anim.matrixRest
if pb.bone.use_local_location:
inv = mat.copy()
inv.invert()
loc = offset*inv
pb.location = loc
else:
pb.location = offset
anim.heads[frame] = locAbs
for n in range(3):
pb.keyframe_insert('location', index=n, frame=frame, group=name)
if animCopy:
mat = mat * animCopy.inverseRest * animCopy.matrices[frame]
anim.matrices[frame] = mat
matMhx = anim.inverseRest * mat * anim.matrixRest
rot = matMhx.to_quaternion()
#rollRot(rot, roll)
setRotation(pb, rot, frame, name)
return
#
# insertReverseIkKeyFrames(name, pb, anim, animReal, animCopy):
#
def vecString(vec):
return "%.3f %.3f %.3f" % (vec[0], vec[1], vec[2])
def insertReverseIkKeyFrames(name, pb, anim, animReal, animCopy):
offsetCopy = anim.headRest - animCopy.headRest
offsetReal = anim.headRest - animReal.headRest
rotX = Matrix.Rotation(math.pi, 3, 'X')
#print("*** %s %s %s" % (name, vecString(animCopy.headRest), vecString(offsetCopy)))
for frame in range(animCopy.nFrames):
locAbs = animCopy.heads[frame] + offsetCopy*animCopy.matrices[frame]
headAbs = animReal.heads[frame] + offsetReal*animReal.matrices[frame]
offset = locAbs - headAbs
mat = animReal.matrices[frame] * anim.matrixRest
if pb.bone.use_local_location:
inv = mat.copy()
inv.invert()
loc = offset*inv
pb.location = loc
else:
pb.location = offset
anim.heads[frame] = locAbs
for n in range(3):
pb.keyframe_insert('location', index=n, frame=frame, group=name)
mat = mat * animCopy.inverseRest * animCopy.matrices[frame]
anim.matrices[frame] = mat
matMhx = rotX * anim.inverseRest * mat * anim.matrixRest * rotX
rot = matMhx.to_quaternion()
setRotation(pb, rot, frame, name)
return
#
# insertRootIkKeyFrames(name, pb, anim, animFake, animCopy):
#
def insertRootIkKeyFrames(name, pb, anim, animFake, animCopy):
locs = []
offsetFake = anim.headRest - animFake.headRest
if animCopy:
roll = anim.roll - animCopy.roll
else:
roll = 0
for frame in range(animFake.nFrames):
locAbs = animFake.heads[frame] + offsetFake*animFake.matrices[frame]
offset = locAbs - anim.headRest
if pb.bone.use_local_location:
loc = offset * anim.inverseRest
pb.location = loc
else:
pb.location = offset
anim.heads[frame] = locAbs
for n in range(3):
pb.keyframe_insert('location', index=n, frame=frame, group=name)
mat = anim.matrixRest
if animCopy:
mat = mat * animCopy.inverseRest * animCopy.matrices[frame]
anim.matrices[frame] = mat
matMhx = anim.inverseRest * mat * anim.matrixRest
rot = matMhx.to_quaternion()
#rollRot(rot, roll)
setRotation(pb, rot, frame, name)
return
#
# retargetMhxRig(context, srcRig, trgRig):
#
def retargetMhxRig(context, srcRig, trgRig):
scn = context.scene
setArmature(srcRig)
print("Retarget %s --> %s" % (srcRig, trgRig))
if trgRig.animation_data:
trgRig.animation_data.action = None
trgAnimations = createTargetAnimation(context, trgRig)
srcAnimations = createSourceAnimation(context, srcRig)
insertAnimation(context, srcRig, srcAnimations, MhxFkBoneList)
onoff = toggleLimitConstraints(trgRig)
setLimitConstraints(trgRig, 0.0)
if scn['MhxApplyFixes']:
srcFixes = theFixesList[srcRig['MhxArmature']]
else:
srcFixes = None
#debugOpen()
poseTrgFkBones(context, trgRig, srcAnimations, trgAnimations, srcFixes)
poseTrgIkBones(context, trgRig, trgAnimations)
#debugClose()
setInterpolation(trgRig)
if onoff == 'OFF':
setLimitConstraints(trgRig, 1.0)
else:
setLimitConstraints(trgRig, 0.0)
trgRig.animation_data.action.name = trgRig.name[:4] + srcRig.name[2:]
print("Retargeted %s --> %s" % (srcRig, trgRig))
return
#
# deleteRig(context, rig00, action, prefix):
#
def deleteRig(context, rig00, action, prefix):
context.scene.objects.unlink(rig00)
if rig00.users == 0:
bpy.data.objects.remove(rig00)
#del rig00
if bpy.data.actions:
for act in bpy.data.actions:
if act.name[0:2] == prefix:
act.use_fake_user = False
if act.users == 0:
bpy.data.actions.remove(act)
del act
return
#
# simplifyFCurves(context, rig, useVisible, useMarkers):
#
def simplifyFCurves(context, rig, useVisible, useMarkers):
scn = context.scene
if not scn.MhxDoSimplify:
return
try:
act = rig.animation_data.action
except:
act = None
if not act:
print("No action to simplify")
return
if useVisible:
fcurves = []
for fcu in act.fcurves:
if not fcu.hide:
fcurves.append(fcu)
#print(fcu.data_path, fcu.array_index)
else:
fcurves = act.fcurves
if useMarkers:
(minTime, maxTime) = getMarkedTime(scn)
if minTime == None:
print("Need two selected markers")
return
else:
(minTime, maxTime) = ('All', 0)
for fcu in fcurves:
simplifyFCurve(fcu, act, scn.MhxErrorLoc, scn.MhxErrorRot, minTime, maxTime)
setInterpolation(rig)
print("Curves simplified")
return
#
# simplifyFCurve(fcu, act, maxErrLoc, maxErrRot, minTime, maxTime):
#
def simplifyFCurve(fcu, act, maxErrLoc, maxErrRot, minTime, maxTime):
#print("WARNING: F-curve simplification turned off")
#return
words = fcu.data_path.split('.')
if words[-1] == 'location':
maxErr = maxErrLoc
elif words[-1] == 'rotation_quaternion':
maxErr = maxErrRot * math.pi/180
elif words[-1] == 'rotation_euler':
maxErr = maxErrRot * math.pi/180
else:
raise NameError("Unknown FCurve type %s" % words[-1])
if minTime == 'All':
points = fcu.keyframe_points
before = []
after = []
else:
points = []
before = []
after = []
for pt in fcu.keyframe_points:
t = pt.co[0]
if t < minTime:
before.append(pt.co)
elif t > maxTime:
after.append(pt.co)
else:
points.append(pt)
nPoints = len(points)
if nPoints <= 2:
return
keeps = []
new = [0, nPoints-1]
while new:
keeps += new
keeps.sort()
new = iterateFCurves(points, keeps, maxErr)
newVerts = before
for n in keeps:
newVerts.append(points[n].co)
newVerts += after
path = fcu.data_path
index = fcu.array_index
grp = fcu.group.name
act.fcurves.remove(fcu)
nfcu = act.fcurves.new(path, index, grp)
for co in newVerts:
t = co[0]
try:
dt = t - int(t)
except:
dt = 0.5
if abs(dt) > 1e-5:
pass
# print(path, co, dt)
else:
nfcu.keyframe_points.insert(frame=co[0], value=co[1])
return
#
# getMarkedTime(scn):
#
def getMarkedTime(scn):
markers = []
for mrk in scn.timeline_markers:
if mrk.select:
markers.append(mrk.frame)
markers.sort()
if len(markers) >= 2:
return (markers[0], markers[-1])
else:
return (None, None)
#
# setInterpolation(rig):
#
def setInterpolation(rig):
if not rig.animation_data:
return
act = rig.animation_data.action
if not act:
return
for fcu in act.fcurves:
for pt in fcu.keyframe_points:
pt.interpolation = 'LINEAR'
fcu.extrapolation = 'CONSTANT'
return
#
# plantKeys(context)
# plantFCurves(fcurves, first, last):
#
def plantKeys(context):
rig = context.object
scn = context.scene
if not rig.animation_data:
print("Cannot plant: no animation data")
return
act = rig.animation_data.action
if not act:
print("Cannot plant: no action")
return
bone = rig.data.bones.active
if not bone:
print("Cannot plant: no active bone")
return
(first, last) = getMarkedTime(scn)
if first == None:
print("Cannot plant: need two selected time markers")
return
pb = rig.pose.bones[bone.name]
locPath = 'pose.bones["%s"].location' % bone.name
if pb.rotation_mode == 'QUATERNION':
rotPath = 'pose.bones["%s"].rotation_quaternion' % bone.name
pbRot = pb.rotation_quaternion
else:
rotPath = 'pose.bones["%s"].rotation_euler' % bone.name
pbRot = pb.rotation_euler
rots = []
locs = []
for fcu in act.fcurves:
if fcu.data_path == locPath:
locs.append(fcu)
if fcu.data_path == rotPath:
rots.append(fcu)
useCrnt = scn['MhxPlantCurrent']
if scn['MhxPlantLoc']:
plantFCurves(locs, first, last, useCrnt, pb.location)
if scn['MhxPlantRot']:
plantFCurves(rots, first, last, useCrnt, pbRot)
return
def plantFCurves(fcurves, first, last, useCrnt, values):
for fcu in fcurves:
print("Plant", fcu.data_path, fcu.array_index)
kpts = fcu.keyframe_points
sum = 0.0
dellist = []
firstx = first - 1e-4
lastx = last + 1e-4
print("Btw", firstx, lastx)
for kp in kpts:
(x,y) = kp.co
if x > firstx and x < lastx:
dellist.append(kp)
sum += y
nterms = len(dellist)
if nterms == 0:
return
if useCrnt:
ave = values[fcu.array_index]
print("Current", ave)
else:
ave = sum/nterms
for kp in dellist:
kp.co[1] = ave
kpts.insert(first, ave, options='FAST')
kpts.insert(last, ave)
return
#
# iterateFCurves(points, keeps, maxErr):
#
def iterateFCurves(points, keeps, maxErr):
new = []
for edge in range(len(keeps)-1):
n0 = keeps[edge]
n1 = keeps[edge+1]
(x0, y0) = points[n0].co
(x1, y1) = points[n1].co
if x1 > x0:
dxdn = (x1-x0)/(n1-n0)
dydx = (y1-y0)/(x1-x0)
err = 0
for n in range(n0+1, n1):
(x, y) = points[n].co
xn = n0 + dxdn*(n-n0)
yn = y0 + dydx*(xn-x0)
if abs(y-yn) > err:
err = abs(y-yn)
worst = n
if err > maxErr:
new.append(worst)
return new
#
# togglePoleTargets(trgRig):
# toggleIKLimits(trgRig):
# toggleLimitConstraints(trgRig):
# setLimitConstraints(trgRig, inf):
#
def togglePoleTargets(trgRig):
bones = trgRig.data.bones
pbones = trgRig.pose.bones
if bones['ElbowPT_L'].hide:
hide = False
poletar = trgRig
res = 'ON'
trgRig.MhxTogglePoleTargets = True
else:
hide = True
poletar = None
res = 'OFF'
trgRig.MhxTogglePoleTargets = False
for suffix in ['_L', '_R']:
for name in ['ElbowPT', 'ElbowLinkPT', 'Elbow', 'KneePT', 'KneeLinkPT', 'Knee']:
try:
bones[name+suffix].hide = hide
except:
pass
cns = pbones['LoArm'+suffix].constraints['ArmIK']
cns = pbones['LoLeg'+suffix].constraints['LegIK']
cns.pole_target = poletar
return res
def toggleIKLimits(trgRig):
pbones = trgRig.pose.bones
if pbones['UpLeg_L'].use_ik_limit_x:
use = False
res = 'OFF'
trgRig.MhxToggleIkLimits = False
else:
use = True
res = 'ON'
trgRig.MhxToggleIkLimits = True
for suffix in ['_L', '_R']:
for name in ['UpArm', 'LoArm', 'UpLeg', 'LoLeg']:
pb = pbones[name+suffix]
pb.use_ik_limit_x = use
pb.use_ik_limit_y = use
pb.use_ik_limit_z = use
return res
def toggleLimitConstraints(trgRig):
pbones = trgRig.pose.bones
first = True
trgRig.MhxToggleLimitConstraints = False
for pb in pbones:
if onUserLayer(pb.bone.layers):
for cns in pb.constraints:
if (cns.type == 'LIMIT_LOCATION' or
cns.type == 'LIMIT_ROTATION' or
cns.type == 'LIMIT_DISTANCE' or
cns.type == 'LIMIT_SCALE'):
if first:
first = False
if cns.influence > 0.5:
inf = 0.0
res = 'OFF'
else:
inf = 1.0
res = 'ON'
trgRig.MhxToggleLimitConstraints = True
cns.influence = inf
if first:
return 'NOT FOUND'
return res
def onUserLayer(layers):
for n in [0,1,2,3,4,5,6,7, 9,10,11,12,13]:
if layers[n]:
return True
return False
def setLimitConstraints(trgRig, inf):
pbones = trgRig.pose.bones
for pb in pbones:
if onUserLayer(pb.bone.layers):
for cns in pb.constraints:
if (cns.type == 'LIMIT_LOCATION' or
cns.type == 'LIMIT_ROTATION' or
cns.type == 'LIMIT_DISTANCE' or
cns.type == 'LIMIT_SCALE'):
cns.influence = inf
return
#
# silenceConstraints(rig):
#
def silenceConstraints(rig):
for pb in rig.pose.bones:
pb.lock_location = (False, False, False)
pb.lock_rotation = (False, False, False)
pb.lock_scale = (False, False, False)
for cns in pb.constraints:
if cns.type == 'CHILD_OF':
cns.influence = 0.0
elif False and (cns.type == 'LIMIT_LOCATION' or
cns.type == 'LIMIT_ROTATION' or
cns.type == 'LIMIT_DISTANCE' or
cns.type == 'LIMIT_SCALE'):
cns.influence = 0.0
return
###################################################################################
# User interface
#
# getBvh(mhx)
# initInterface(context)
#
def getBvh(mhx):
for (bvh, mhx1) in theArmature.items():
if mhx == mhx1:
return bvh
return None
def initInterface(context):
bpy.types.Scene.MhxBvhScale = FloatProperty(
name="Scale",
description="Scale the BVH by this value",
min=0.0001, max=1000000.0,
soft_min=0.001, soft_max=100.0,
default=0.65)
bpy.types.Scene.MhxAutoScale = BoolProperty(
name="Auto scale",
description="Rescale skeleton to match target",
default=True)
bpy.types.Scene.MhxStartFrame = IntProperty(
name="Start Frame",
description="Starting frame for the animation",
default=1)
bpy.types.Scene.MhxEndFrame = IntProperty(
name="Last Frame",
description="Last frame for the animation",
default=32000)
bpy.types.Scene.MhxSubsample = IntProperty(
name="Subsample",
description="Sample only every n:th frame",
default=1)
bpy.types.Scene.MhxDefaultSS = BoolProperty(
name="Use default subsample",
default=True)
bpy.types.Scene.MhxRot90Anim = BoolProperty(
name="Rotate 90 deg",
description="Rotate 90 degress so Z points up",
default=True)
bpy.types.Scene.MhxDoSimplify = BoolProperty(
name="Simplify FCurves",
description="Simplify FCurves",
default=True)
bpy.types.Scene.MhxSimplifyVisible = BoolProperty(
name="Only visible",
description="Simplify only visible F-curves",
default=False)
bpy.types.Scene.MhxSimplifyMarkers = BoolProperty(
name="Only between markers",
description="Simplify only between markers",
default=False)
bpy.types.Scene.MhxApplyFixes = BoolProperty(
name="Apply found fixes",
description="Apply found fixes",
default=True)
bpy.types.Scene.MhxPlantCurrent = BoolProperty(
name="Use current",
description="Plant at current",
default=True)
bpy.types.Scene.MhxPlantLoc = BoolProperty(
name="Loc",
description="Plant location keys",
default=True)
bpy.types.Scene.MhxPlantRot = BoolProperty(
name="Rot",
description="Plant rotation keys",
default=False)
bpy.types.Scene.MhxErrorLoc = FloatProperty(
name="Max loc error",
description="Max error for location FCurves when doing simplification",
min=0.001,
default=0.01)
bpy.types.Scene.MhxErrorRot = FloatProperty(
name="Max rot error",
description="Max error for rotation (degrees) FCurves when doing simplification",
min=0.001,
default=0.1)
bpy.types.Scene.MhxDirectory = StringProperty(
name="Directory",
description="Directory",
maxlen=1024,
default='')
bpy.types.Scene.MhxReallyDelete = BoolProperty(
name="Really delete action",
description="Delete button deletes action permanently",
default=False)
bpy.types.Scene.MhxPrefix = StringProperty(
name="Prefix",
description="Prefix",
maxlen=1024,
default='')
bpy.types.Object.MhxArmature = StringProperty()
bpy.types.Object.MhxTogglePoleTargets = BoolProperty(default=True)
bpy.types.Object.MhxToggleIkLimits = BoolProperty(default=False)
bpy.types.Object.MhxToggleLimitConstraints = BoolProperty(default=True)
'''
for mhx in theFkBoneList:
bpy.types.Scene.StringProperty(
attr=mhx,
name=mhx,
description="Bvh bone corresponding to %s" % mhx,
default = ''
)
bvh = getBvh(mhx)
if bvh:
scn[mhx] = bvh
'''
# loadDefaults(context)
return
def postload_registration(context):
scn = context.scene
if scn:
scn['MhxPlantCurrent'] = True
scn['MhxPlantLoc'] = True
scn['MhxBvhScale'] = 0.65
scn['MhxAutoScale'] = True
scn['MhxStartFrame'] = 1
scn['MhxEndFrame'] = 32000
scn['MhxSubsample'] = 1
scn['MhxDefaultSS'] = True
scn['MhxRot90Anim'] = True
scn['MhxDoSimplify'] = True
scn['MhxSimplifyVisible'] = False
scn['MhxSimplifyMarkers'] = False
scn['MhxApplyFixes'] = True
scn['MhxPlantLoc'] = True
scn['MhxPlantRot'] = False
scn['MhxErrorLoc'] = 0.01
scn['MhxErrorRot'] = 0.1
scn['MhxPrefix'] = "Female1_A"
scn['MhxDirectory'] = "~/makehuman/bvh/Female1_bvh"
scn['MhxReallyDelete'] = False
listAllActions(context)
else:
print("Warning - no scene - scene properties not set")
loadDefaults(context)
#
# ensureInited(context):
#
def ensureInited(context):
try:
context.scene['MhxBvhScale']
inited = True
except:
inited = False
if not inited:
initInterface(context)
#
# saveDefaults(context):
# loadDefaults(context):
#
def saveDefaults(context):
if not context.scene:
return
filename = os.path.realpath(os.path.expanduser("~/makehuman/mhx_defaults.txt"))
try:
fp = open(filename, "w")
except:
print("Unable to open %s for writing" % filename)
return
for (key,value) in context.scene.items():
if key[:3] == 'Mhx':
fp.write("%s %s\n" % (key, value))
fp.close()
return
def loadDefaults(context):
if not context.scene:
return
filename = os.path.realpath(os.path.expanduser("~/makehuman/mhx_defaults.txt"))
try:
fp = open(filename, "r")
except:
print("Unable to open %s for reading" % filename)
return
for line in fp:
words = line.split()
try:
val = eval(words[1])
except:
val = words[1]
context.scene[words[0]] = val
fp.close()
return
#
# makeMhxRig(ob)
#
def makeMhxRig(ob):
try:
test = ob['MhxRig']
except:
test = False
if not test:
return
#
# class Bvh2MhxPanel(bpy.types.Panel):
#
class Bvh2MhxPanel(bpy.types.Panel):
bl_label = "Bvh to Mhx"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
@classmethod
def poll(cls, context):
if context.object and context.object.type == 'ARMATURE':
return True
def draw(self, context):
layout = self.layout
scn = context.scene
ob = context.object
layout.operator("mhx.mocap_init_interface")
layout.operator("mhx.mocap_save_defaults")
layout.operator("mhx.mocap_copy_angles_fk_ik")
layout.separator()
layout.label('Load')
layout.prop(scn, "MhxBvhScale")
layout.prop(scn, "MhxAutoScale")
layout.prop(scn, "MhxStartFrame")
layout.prop(scn, "MhxEndFrame")
layout.prop(scn, "MhxSubsample")
layout.prop(scn, "MhxDefaultSS")
layout.prop(scn, "MhxRot90Anim")
layout.prop(scn, "MhxDoSimplify")
layout.prop(scn, "MhxApplyFixes")
layout.operator("mhx.mocap_load_bvh")
layout.operator("mhx.mocap_retarget_mhx")
layout.separator()
layout.operator("mhx.mocap_load_retarget_simplify")
layout.separator()
layout.label('Toggle')
row = layout.row()
row.operator("mhx.mocap_toggle_pole_targets")
row.prop(ob, "MhxTogglePoleTargets")
row = layout.row()
row.operator("mhx.mocap_toggle_ik_limits")
row.prop(ob, "MhxToggleIkLimits")
row = layout.row()
row.operator("mhx.mocap_toggle_limit_constraints")
row.prop(ob, "MhxToggleLimitConstraints")
layout.separator()
layout.label('Plant')
row = layout.row()
row.prop(scn, "MhxPlantLoc")
row.prop(scn, "MhxPlantRot")
layout.prop(scn, "MhxPlantCurrent")
layout.operator("mhx.mocap_plant")
layout.separator()
layout.label('Simplify')
layout.prop(scn, "MhxErrorLoc")
layout.prop(scn, "MhxErrorRot")
layout.prop(scn, "MhxSimplifyVisible")
layout.prop(scn, "MhxSimplifyMarkers")
layout.operator("mhx.mocap_simplify_fcurves")
layout.separator()
layout.label('Batch conversion')
layout.prop(scn, "MhxDirectory")
layout.prop(scn, "MhxPrefix")
layout.operator("mhx.mocap_batch")
layout.separator()
layout.label('Manage actions')
layout.prop_menu_enum(scn, "MhxActions")
layout.operator("mhx.mocap_update_action_list")
layout.prop(scn, "MhxReallyDelete")
layout.operator("mhx.mocap_delete")
return
#
# class VIEW3D_OT_MhxLoadBvhButton(bpy.types.Operator, ImportHelper):
#
class VIEW3D_OT_MhxLoadBvhButton(bpy.types.Operator, ImportHelper):
bl_idname = "mhx.mocap_load_bvh"
bl_label = "Load BVH file (.bvh)"
filename_ext = ".bvh"
filter_glob = StringProperty(default="*.bvh", options={'HIDDEN'})
filepath = StringProperty(name="File Path", description="Filepath used for importing the BVH file", maxlen=1024, default="")
def execute(self, context):
import bpy, os
importAndRename(context, self.properties.filepath)
print("%s imported" % self.properties.filepath)
return{'FINISHED'}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
#
# class VIEW3D_OT_MhxRetargetMhxButton(bpy.types.Operator):
#
class VIEW3D_OT_MhxRetargetMhxButton(bpy.types.Operator):
bl_idname = "mhx.mocap_retarget_mhx"
bl_label = "Retarget selected to MHX"
def execute(self, context):
trgRig = context.object
guessTargetArmature(trgRig)
for srcRig in context.selected_objects:
if srcRig != trgRig:
retargetMhxRig(context, srcRig, trgRig)
return{'FINISHED'}
#
# class VIEW3D_OT_MhxSimplifyFCurvesButton(bpy.types.Operator):
#
class VIEW3D_OT_MhxSimplifyFCurvesButton(bpy.types.Operator):
bl_idname = "mhx.mocap_simplify_fcurves"
bl_label = "Simplify FCurves"
def execute(self, context):
scn = context.scene
simplifyFCurves(context, context.object, scn.MhxSimplifyVisible, scn.MhxSimplifyMarkers)
return{'FINISHED'}
#
# class VIEW3D_OT_MhxSilenceConstraintsButton(bpy.types.Operator):
#
class VIEW3D_OT_MhxSilenceConstraintsButton(bpy.types.Operator):
bl_idname = "mhx.mocap_silence_constraints"
bl_label = "Silence constraints"
def execute(self, context):
silenceConstraints(context.object)
print("Constraints silenced")
return{'FINISHED'}
#
# class VIEW3D_OT_MhxTogglePoleTargetsButton(bpy.types.Operator):
#
class VIEW3D_OT_MhxTogglePoleTargetsButton(bpy.types.Operator):
bl_idname = "mhx.mocap_toggle_pole_targets"
bl_label = "Toggle pole targets"
def execute(self, context):
import bpy
res = togglePoleTargets(context.object)
print("Pole targets toggled", res)
return{'FINISHED'}
#
# class VIEW3D_OT_MhxToggleIKLimitsButton(bpy.types.Operator):
#
class VIEW3D_OT_MhxToggleIKLimitsButton(bpy.types.Operator):
bl_idname = "mhx.mocap_toggle_ik_limits"
bl_label = "Toggle IK limits"
def execute(self, context):
import bpy
res = toggleIKLimits(context.object)
print("IK limits toggled", res)
return{'FINISHED'}
#
# class VIEW3D_OT_MhxToggleLimitConstraintsButton(bpy.types.Operator):
#
class VIEW3D_OT_MhxToggleLimitConstraintsButton(bpy.types.Operator):
bl_idname = "mhx.mocap_toggle_limit_constraints"
bl_label = "Toggle Limit constraints"
def execute(self, context):
import bpy
res = toggleLimitConstraints(context.object)
print("Limit constraints toggled", res)
return{'FINISHED'}
#
# class VIEW3D_OT_MhxInitInterfaceButton(bpy.types.Operator):
#
class VIEW3D_OT_MhxInitInterfaceButton(bpy.types.Operator):
bl_idname = "mhx.mocap_init_interface"
bl_label = "Initialize"
def execute(self, context):
import bpy
initInterface(context)
postload_registration(context)
print("Interface initialized")
return{'FINISHED'}
#
# class VIEW3D_OT_MhxSaveDefaultsButton(bpy.types.Operator):
#
class VIEW3D_OT_MhxSaveDefaultsButton(bpy.types.Operator):
bl_idname = "mhx.mocap_save_defaults"
bl_label = "Save defaults"
def execute(self, context):
saveDefaults(context)
return{'FINISHED'}
#
# class VIEW3D_OT_MhxPlantButton(bpy.types.Operator):
#
class VIEW3D_OT_MhxPlantButton(bpy.types.Operator):
bl_idname = "mhx.mocap_plant"
bl_label = "Plant"
def execute(self, context):
import bpy
plantKeys(context)
print("Keys planted")
return{'FINISHED'}
#
# class VIEW3D_OT_MhxCopyAnglesIKButton(bpy.types.Operator):
#
class VIEW3D_OT_MhxCopyAnglesIKButton(bpy.types.Operator):
bl_idname = "mhx.mocap_copy_angles_fk_ik"
bl_label = "Angles --> IK"
def execute(self, context):
import bpy
copyAnglesIK(context)
print("Angles copied")
return{'FINISHED'}
#
# loadRetargetSimplify(context, filepath):
# class VIEW3D_OT_MhxLoadRetargetSimplify(bpy.types.Operator):
#
def loadRetargetSimplify(context, filepath):
print("Load and retarget %s" % filepath)
time1 = time.clock()
trgRig = context.object
(srcRig, action) = importAndRename(context, filepath)
retargetMhxRig(context, srcRig, trgRig)
if context.scene['MhxDoSimplify']:
simplifyFCurves(context, trgRig, False, False)
deleteRig(context, srcRig, action, 'Y_')
time2 = time.clock()
print("%s finished in %.3f s" % (filepath, time2-time1))
return
class VIEW3D_OT_MhxLoadRetargetSimplifyButton(bpy.types.Operator, ImportHelper):
bl_idname = "mhx.mocap_load_retarget_simplify"
bl_label = "Load, retarget, simplify"
filename_ext = ".bvh"
filter_glob = StringProperty(default="*.bvh", options={'HIDDEN'})
filepath = StringProperty(name="File Path", description="Filepath used for importing the BVH file", maxlen=1024, default="")
def execute(self, context):
import bpy, os, mathutils
loadRetargetSimplify(context, self.properties.filepath)
return{'FINISHED'}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
#
# readDirectory(directory, prefix):
# class VIEW3D_OT_MhxBatchButton(bpy.types.Operator):
#
def readDirectory(directory, prefix):
realdir = os.path.realpath(os.path.expanduser(directory))
files = os.listdir(realdir)
n = len(prefix)
paths = []
for fileName in files:
(name, ext) = os.path.splitext(fileName)
if name[:n] == prefix and ext == '.bvh':
paths.append("%s/%s" % (realdir, fileName))
return paths
class VIEW3D_OT_MhxBatchButton(bpy.types.Operator):
bl_idname = "mhx.mocap_batch"
bl_label = "Batch run"
def execute(self, context):
import bpy, os, mathutils
paths = readDirectory(context.scene['MhxDirectory'], context.scene['MhxPrefix'])
trgRig = context.object
for filepath in paths:
context.scene.objects.active = trgRig
loadRetargetSimplify(context, filepath)
return{'FINISHED'}
#
# Select or delete action
# Delete button really deletes action. Handle with care.
#
# listAllActions(context):
# findAction(name):
# class VIEW3D_OT_MhxSelectButton(bpy.types.Operator):
# class VIEW3D_OT_MhxDeleteButton(bpy.types.Operator):
#
def listAllActions(context):
global theActions
theActions = []
for act in bpy.data.actions:
name = act.name
theActions.append((name, name, name))
bpy.types.Scene.MhxActions = EnumProperty(
items = theActions,
name = "Actions")
return
def findAction(name):
global theActions
for n,action in enumerate(theActions):
(name1, name2, name3) = action
if name == name1:
return n
raise NameError("Unrecognized action %s" % name)
class VIEW3D_OT_MhxUpdateActionListButton(bpy.types.Operator):
bl_idname = "mhx.mocap_update_action_list"
bl_label = "Update action list"
@classmethod
def poll(cls, context):
return context.object
def execute(self, context):
listAllActions(context)
return{'FINISHED'}
class VIEW3D_OT_MhxDeleteButton(bpy.types.Operator):
bl_idname = "mhx.mocap_delete"
bl_label = "Delete action"
@classmethod
def poll(cls, context):
return context.scene.MhxReallyDelete
def execute(self, context):
global theActions
listAllActions(context)
scn = context.scene
name = scn.MhxActions
print('Delete action', name)
try:
act = bpy.data.actions[name]
except:
act = None
if act:
act.use_fake_user = False
if act.users == 0:
print("Deleting", act)
n = findAction(name)
theActions.pop(n)
bpy.data.actions.remove(act)
print('Action', act, 'deleted')
listAllActions(context)
#del act
else:
print("Cannot delete. %s has %d users." % (act, act.users))
return{'FINISHED'}
###############################################################################
#
# Source armatures
#
###############################################################################
theSourceProps = []
#
# defaultEnums():
# setSourceProp(scn, prop, mhx, enums):
# makeSourceBoneList(scn, root):
#
def defaultEnums():
global TargetBoneNames
enums = [('None','None','None')]
for bn in TargetBoneNames:
if not bn:
continue
(mhx, text) = bn
enum = (mhx, text, mhx)
enums.append(enum)
return enums
def setSourceProp(scn, prop, mhx, enums):
scn[prop] = 0
n = 0
for (mhx1, text1, mhx2) in enums:
if mhx == mhx1:
scn[prop] = n
return
n += 1
return
def makeSourceBoneList(scn, root):
enums = defaultEnums()
props = []
makeSourceNodes(scn, root, enums, props)
for prop in props:
name = prop[2:].lower()
mhx = guessSourceBone(name)
setSourceProp(scn, prop, mhx, enums)
return (props, enums)
#
# makeSourceNodes(scn, node, enums, props):
# defineSourceProp(name, enums):
#
def makeSourceNodes(scn, node, enums, props):
if not node.children:
return
prop = defineSourceProp(node.name, enums)
props.append(prop)
for child in node.children:
makeSourceNodes(scn, child, enums, props)
return
def defineSourceProp(name, enums):
qname = name.replace(' ','_')
expr = 'bpy.types.Scene.S_%s = EnumProperty(items = enums, name = "%s")' % (qname, name)
exec(expr)
return 'S_'+qname
#
# guessSourceBone(name):
#
def guessSourceBone(name):
for amtname in theArmatureList:
amt = theArmatures[amtname]
try:
mhx = amt[name]
return mhx
except:
pass
return ''
#
# useCustomSrcRig(context):
#
def useCustomSrcRig(context):
if theSourceProps:
try:
guess = context.scene.MhxGuessSrcRig
except:
guess = True
return not guess
return False
#
# buildSrcArmature(context, rig):
#
def buildSrcArmature(context, rig):
amt = {}
used = {}
scn = context.scene
for prop in theSourceProps:
name = prop[2:].lower()
(mhx1, text, mhx2) = theSourceEnums[scn[prop]]
if mhx1 == 'None':
amt[name] = None
continue
amt[name] = mhx1
try:
user = used[mhx1]
except:
user = None
if user:
raise NameError("Source bones %s and %s both assigned to %s" % (user, name, mhx1))
used[mhx1] = name
fixes = createCustomFixes(scn['MhxSrcLegBentOut'], scn['MhxSrcLegRoll'], scn['MhxSrcArmBentDown'], scn['MhxSrcArmRoll'])
return (amt, "MySource", fixes)
#
# createCustomFixes(bendLeg, rollLeg, bendArm, rollArm):
#
def createCustomFixes(bendLeg, rollLeg, bendArm, rollArm):
fixMats = {}
eps = 4
if abs(bendLeg) > eps or abs(rollLeg) > eps:
bendLeg *= Deg2Rad
fixMats['UpLeg_L'] = (Matrix.Rotation(-bendLeg, 3, 'Z'), rollLeg*Deg2Rad)
fixMats['UpLeg_R'] = (Matrix.Rotation(bendLeg, 3, 'Z'), -rollLeg*Deg2Rad)
if abs(rollLeg) > eps:
rollLeg *= Deg2Rad
fixMats['LoLeg_L'] = (None, rollLeg)
fixMats['LoLeg_R'] = (None, -rollLeg)
if abs(bendArm) > eps or abs(rollArm) > eps:
bendArm *= Deg2Rad
fixMats['UpArm_L'] = (Matrix.Rotation(bendArm, 3, 'Z'), rollArm*Deg2Rad)
fixMats['UpArm_R'] = (Matrix.Rotation(-bendArm, 3, 'Z'), -rollArm*Deg2Rad)
if abs(rollArm) > eps:
rollArm *= Deg2Rad
fixMats['LoArm_L'] = (None, rollArm)
fixMats['Hand_L'] = (None, rollArm)
fixMats['LoArm_R'] = (None, -rollArm)
fixMats['Hand_R'] = (None, -rollArm)
return fixMats
#
# ensureSourceInited(context):
#
def ensureSourceInited(context):
scn = context.scene
try:
scn.MhxGuessSrcRig
return
except:
pass
expr = 'bpy.types.Scene.MhxGuessSrcRig = BoolProperty(name = "Guess source rig")'
exec(expr)
scn.MhxGuessSrcRig = False
return
#
# class VIEW3D_OT_MhxScanBvhButton(bpy.types.Operator):
#
class VIEW3D_OT_MhxScanBvhButton(bpy.types.Operator):
bl_idname = "mhx.mocap_scan_bvh"
bl_label = "Scan bvh file"
bl_options = {'REGISTER'}
filename_ext = ".bvh"
filter_glob = StringProperty(default="*.bvh", options={'HIDDEN'})
filepath = StringProperty(name="File Path", maxlen=1024, default="")
def execute(self, context):
global theSourceProps, theSourceEnums
scn = context.scene
root = readBvhFile(context, self.filepath, scn, True)
(theSourceProps, theSourceEnums) = makeSourceBoneList(scn, root)
scn['MhxSrcArmBentDown'] = 0.0
scn['MhxSrcArmRoll'] = 0.0
scn['MhxSrcLegBentOut'] = 0.0
scn['MhxSrcLegRoll'] = 0.0
ensureSourceInited(context)
return{'FINISHED'}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
#
# saveSourceBones(context, path):
# loadSourceBones(context, path):
# class VIEW3D_OT_MhxLoadSaveSourceBonesButton(bpy.types.Operator, ImportHelper):
#
def saveSourceBones(context, path):
global theSourceProps, theSourceEnums
scn = context.scene
fp = open(path, "w")
fp.write("Settings\n")
for prop in ['MhxSrcArmBentDown','MhxSrcArmRoll','MhxSrcLegBentOut','MhxSrcLegRoll']:
fp.write("%s %s\n" % (prop, scn[prop]))
fp.write("Bones\n")
for prop in theSourceProps:
(mhx1, text, mhx2) = theSourceEnums[scn[prop]]
fp.write("%s %s\n" % (prop, mhx1))
fp.close()
return
def loadSourceBones(context, path):
global theSourceProps, theSourceEnums
scn = context.scene
theSourceEnums = defaultEnums()
theSourceProps = []
fp = open(path, "rU")
status = 0
for line in fp:
words = line.split()
if len(words) == 1:
status = words[0]
elif status == 'Settings':
prop = words[0]
value = float(words[1])
scn[prop] = value
elif status == 'Bones':
prop = words[0]
theSourceProps.append(prop)
mhx = words[1]
setSourceProp(scn, prop, mhx, theSourceEnums)
print(prop, scn[prop], mhx)
fp.close()
for prop in theSourceProps:
defineSourceProp(prop[2:], theSourceEnums)
return
class VIEW3D_OT_MhxLoadSaveSourceBonesButton(bpy.types.Operator, ImportHelper):
bl_idname = "mhx.mocap_load_save_source_bones"
bl_label = "Load/save source bones"
loadSave = bpy.props.StringProperty()
filename_ext = ".txt"
#filter_glob = StringProperty(default="*.txt", options={'HIDDEN'})
filepath = StringProperty(name="File Path", maxlen=1024, default="")
def execute(self, context):
ensureSourceInited(context)
if self.loadSave == 'save':
saveSourceBones(context, self.properties.filepath)
else:
loadSourceBones(context, self.properties.filepath)
return{'FINISHED'}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
#
# class MhxSourceBonesPanel(bpy.types.Panel):
#
class MhxSourceBonesPanel(bpy.types.Panel):
bl_label = "Source armature"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
@classmethod
def poll(cls, context):
return (context.object and context.object.type == 'ARMATURE')
def draw(self, context):
global theSourceProps
layout = self.layout
scn = context.scene
rig = context.object
if theSourceProps:
layout.operator("mhx.mocap_scan_bvh", text="Rescan bvh file")
else:
layout.operator("mhx.mocap_scan_bvh", text="Scan bvh file")
layout.operator("mhx.mocap_load_save_source_bones", text='Load source bones').loadSave = 'load'
layout.operator("mhx.mocap_load_save_source_bones", text='Save source bones').loadSave = 'save'
if not theSourceProps:
return
layout.separator()
layout.prop(scn, 'MhxGuessSrcRig')
layout.label("Arms")
row = layout.row()
row.prop(scn, '["MhxSrcArmBentDown"]', text='Down')
row.prop(scn, '["MhxSrcArmRoll"]', text='Roll')
layout.label("Legs")
row = layout.row()
row.prop(scn, '["MhxSrcLegBentOut"]', text='Out')
row.prop(scn, '["MhxSrcLegRoll"]', text='Roll')
for prop in theSourceProps:
layout.prop_menu_enum(scn, prop)
###############################################################################
#
# Target armatures
#
###############################################################################
# (mhx bone, text)
TargetBoneNames = [
('Root', 'Root bone'),
('Spine1', 'Lower spine'),
('Spine2', 'Middle spine'),
('Spine3', 'Upper spine'),
('Neck', 'Neck'),
('Head', 'Head'),
None,
('Shoulder_L', 'L shoulder'),
('UpArm_L', 'L upper arm'),
('LoArm_L', 'L forearm'),
('Hand_L', 'L hand'),
None,
('Shoulder_R', 'R shoulder'),
('UpArm_R', 'R upper arm'),
('LoArm_R', 'R forearm'),
('Hand_R', 'R hand'),
None,
('Hips', 'Hips'),
None,
('Hip_L', 'L hip'),
('UpLeg_L', 'L thigh'),
('LoLeg_L', 'L shin'),
('Foot_L', 'L foot'),
('Toe_L', 'L toes'),
None,
('Hip_R', 'R hip'),
('UpLeg_R', 'R thigh'),
('LoLeg_R', 'R shin'),
('Foot_R', 'R foot'),
('Toe_R', 'R toes'),
]
# (mhx bone, text, fakeparent, copyRot)
TargetIkBoneNames = [
('Wrist_L', 'L wrist', 'LoArm_L', 'Hand_L'),
('ElbowPT_L', 'L elbow', 'UpArm_L', None),
('Ankle_L', 'L ankle', 'LoLeg_L', 'Foot_L'),
('KneePT_L', 'L knee', 'UpLeg_L', None),
('Wrist_R', 'R wrist', 'LoArm_R', 'Hand_R'),
('ElbowPT_R', 'R elbow', 'UpArm_R', None),
('Ankle_R', 'R ankle', 'LoLeg_R', 'Foot_R'),
('KneePT_R', 'R knee', 'UpLeg_R', None),
]
#
# initTargetCharacter(rig):
# class VIEW3D_OT_MhxInitTargetCharacterButton(bpy.types.Operator):
# class VIEW3D_OT_MhxUnInitTargetCharacterButton(bpy.types.Operator):
#
def initTargetCharacter(rig):
for bn in TargetBoneNames+TargetIkBoneNames:
if not bn:
continue
try:
(mhx, text) = bn
except:
(mhx, text, fakepar, copyrot) = bn
rig[mhx] = mhx
rig['MhxTargetRig'] = True
rig['MhxArmBentDown'] = 0.0
rig['MhxLegBentOut'] = 0.0
return
class VIEW3D_OT_MhxInitTargetCharacterButton(bpy.types.Operator):
bl_idname = "mhx.mocap_init_target_character"
bl_label = "Initialize target character"
bl_options = {'REGISTER'}
def execute(self, context):
initTargetCharacter(context.object)
print("Target character initialized")
return{'FINISHED'}
class VIEW3D_OT_MhxUnInitTargetCharacterButton(bpy.types.Operator):
bl_idname = "mhx.mocap_uninit_target_character"
bl_label = "Uninitialize"
bl_options = {'REGISTER'}
def execute(self, context):
context.object['MhxTargetRig'] = False
print("Target character uninitialized")
return{'FINISHED'}
#
# assocTargetBones(rig, names, xtraAssoc):
#
def assocTargetBones(rig, names, xtraAssoc):
boneAssoc = []
for bn in names:
if not bn:
continue
try:
(mhx, text) = bn
except:
(mhx, text, fakePar, copyRot) = bn
bone = rig[mhx]
if bone != '':
try:
rig.data.bones[bone]
exists = True
except:
exists = False
if exists:
boneAssoc.append((bone, mhx))
else:
raise NameError("Bone %s does not exist in armature %s" % (bone, rig.name))
parAssoc = {}
assoc = boneAssoc+xtraAssoc
for (bname, mhx) in boneAssoc:
bone = rig.data.bones[bname]
(par, stop) = realBone(bone.parent, rig, 0, assoc)
while not stop:
(par, stop) = realBone(par.parent, rig, 0, assoc)
if par:
parAssoc[bname] = par.name
else:
parAssoc[bname] = None
rolls = {}
try:
bpy.ops.object.mode_set(mode='EDIT')
(bname, mhx) = boneAssoc[0]
rig.data.edit_bones[bname]
edit = True
except:
edit = False
if edit:
for (bname, mhx) in boneAssoc:
eb = rig.data.edit_bones[bname]
rolls[bname] = eb.roll
bpy.ops.object.mode_set(mode='POSE')
for (bname, mhx) in boneAssoc:
bone = rig.data.bones[bname]
bone['Roll'] = rolls[bname]
else:
for (bname, mhx) in boneAssoc:
bone = rig.data.bones[bname]
try:
rolls[bname] = bone['Roll']
except:
raise NameError("Associations must be made in rig source file")
pb = rig.pose.bones[rig['Root']]
pb.lock_location = (False,False,False)
return (boneAssoc, parAssoc, rolls)
#
# findFakeParent(mhx, boneAssoc):
#
def findFakeParent(mhx, boneAssoc):
for (mhx1, text, fakeMhx, copyMhx) in TargetIkBoneNames:
if mhx == mhx1:
fakePar = assocKey(fakeMhx, boneAssoc)
copyRot = assocKey(copyMhx, boneAssoc)
return (fakePar, copyRot)
raise NameError("Did not find fake parent %s" % mhx)
#
# makeTargetAssoc(rig):
#
def makeTargetAssoc(rig):
(boneAssoc, parAssoc, rolls) = assocTargetBones(rig, TargetBoneNames, [])
(ikBoneAssoc, ikParAssoc, ikRolls) = assocTargetBones(rig, TargetIkBoneNames, boneAssoc)
ikBones = []
ikParents = {}
for (bone, mhx) in ikBoneAssoc:
ikBones.append(bone)
(fakePar, copyRot) = findFakeParent(mhx, boneAssoc)
# bone : (realParent, fakeParent, copyRot, reverse)
par = ikParAssoc[bone]
ikParents[bone] = (par, fakePar, copyRot, False)
parAssoc[bone] = par
fixMats = createCustomFixes(rig['MhxLegBentOut'], 0, rig['MhxArmBentDown'], 0)
print("Associations:")
print(" Bone : Mhx bone Parent Roll")
for (bname, mhx) in boneAssoc:
roll = rolls[bname]
print(" %14s : %14s %14s %5d" % (bname, mhx, parAssoc[bname], roll/Deg2Rad))
print("IK bones:")
print(" Bone : Mhx bone Real parent Fake parent Copy rot")
for (bname, mhx) in ikBoneAssoc:
(par, fakePar, copyRot, reverse) = ikParents[bname]
print(" %14s : %14s %14s %14s %14s" % (bname, mhx, par, fakePar, copyRot))
return (boneAssoc, parAssoc, rolls, fixMats, ikBones, ikParents)
#
# assocValue(name, assoc):
# assocKey(name, assoc):
#
def assocValue(name, assoc):
for (key, value) in assoc:
if key == name:
return value
return None
def assocKey(name, assoc):
for (key, value) in assoc:
if value == name:
return key
return None
#
# realBone(bone, rig, n, assoc):
#
def realBone(bone, rig, n, assoc):
if not bone:
return (None, True)
if assocValue(bone.name, assoc):
return (bone, True)
if n > 5:
print("Real bone overflow:", bone)
return (bone, True)
pb = rig.pose.bones[bone.name]
for cns in pb.constraints:
if (((cns.type == 'COPY_ROTATION' and cns.use_x and cns.use_z) or
(cns.type == 'COPY_TRANSFORMS')) and
(cns.influence > 0.6) and
(cns.target == rig)):
rb = rig.data.bones[cns.subtarget]
return realBone(rb, rig, n+1, assoc)
return (bone, False)
class VIEW3D_OT_MhxMakeTargetAssocButton(bpy.types.Operator):
bl_idname = "mhx.mocap_make_assoc"
bl_label = "Make target associations"
bl_options = {'REGISTER'}
def execute(self, context):
makeTargetAssoc(context.object)
print("Associations made")
return{'FINISHED'}
#
#
#
def unrollAll(context):
bpy.ops.object.mode_set(mode='EDIT')
ebones = context.object.data.edit_bones
for eb in ebones:
eb.roll = 0
bpy.ops.object.mode_set(mode='POSE')
return
class VIEW3D_OT_MhxUnrollAllButton(bpy.types.Operator):
bl_idname = "mhx.mocap_unroll_all"
bl_label = "Unroll all"
bl_options = {'REGISTER'}
def execute(self, context):
unrollAll(context)
print("Associations made")
return{'FINISHED'}
#
# saveTargetBones(context, path):
# loadTargetBones(context, path):
# class VIEW3D_OT_MhxLoadSaveTargetBonesButton(bpy.types.Operator, ImportHelper):
#
def saveTargetBones(context, path):
rig = context.object
fp = open(path, "w")
for bn in TargetBoneNames+TargetIkBoneNames:
if not bn:
continue
try:
(mhx, text) = bn
except:
(mhx, text, fakepar, copyrot) = bn
bone = rig[mhx]
if bone == '':
fp.write("%s %s\n" % (mhx, '-'))
else:
fp.write("%s %s\n" % (mhx, bone))
fp.close()
return
def loadTargetBones(context, path):
rig = context.object
fp = open(path, "rU")
for line in fp:
words = line.split()
try:
mhx = words[0]
bone = words[1]
except:
mhx = None
if mhx:
if bone == '-':
bone = ''
rig[mhx] = bone
fp.close()
return
class VIEW3D_OT_MhxLoadSaveTargetBonesButton(bpy.types.Operator, ImportHelper):
bl_idname = "mhx.mocap_load_save_target_bones"
bl_label = "Load/save target bones"
loadSave = bpy.props.StringProperty()
filename_ext = ".txt"
#filter_glob = StringProperty(default="*.txt", options={'HIDDEN'})
filepath = StringProperty(name="File Path", maxlen=1024, default="")
def execute(self, context):
if self.loadSave == 'save':
saveTargetBones(context, self.properties.filepath)
else:
loadTargetBones(context, self.properties.filepath)
return{'FINISHED'}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
#
# class MhxTargetBonesPanel(bpy.types.Panel):
#
class MhxTargetBonesPanel(bpy.types.Panel):
bl_label = "Target armature"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
@classmethod
def poll(cls, context):
return (context.object and context.object.type == 'ARMATURE')
def draw(self, context):
layout = self.layout
rig = context.object
try:
inited = rig['MhxTargetRig']
except:
inited = False
if not inited:
layout.operator("mhx.mocap_init_target_character", text='Initialize target character')
return
layout.operator("mhx.mocap_init_target_character", text='Reinitialize target character')
layout.operator("mhx.mocap_uninit_target_character")
layout.operator("mhx.mocap_load_save_target_bones", text='Load target bones').loadSave = 'load'
layout.operator("mhx.mocap_load_save_target_bones", text='Save target bones').loadSave = 'save'
layout.operator("mhx.mocap_make_assoc")
layout.operator("mhx.mocap_unroll_all")
#layout.prop(rig, '["MhxArmBentDown"]', text='Arm bent down')
#layout.prop(rig, '["MhxLegBentOut"]', text='Leg bent out')
layout.label("FK bones")
for bn in TargetBoneNames:
if bn:
(mhx, text) = bn
layout.prop(rig, '["%s"]' % mhx, text=text)
else:
layout.separator()
layout.label("IK bones")
for (mhx, text, fakePar, copyRot) in TargetIkBoneNames:
layout.prop(rig, '["%s"]' % mhx, text=text)
return
#
# Debugging
#
"""
def debugOpen():
global theDbgFp
theDbgFp = open("/home/thomas/myblends/debug.txt", "w")
def debugClose():
global theDbgFp
theDbgFp.close()
def debugPrint(string):
global theDbgFp
theDbgFp.write("%s\n" % string)
def debugPrintVec(vec):
global theDbgFp
theDbgFp.write("(%.3f %.3f %.3f)\n" % (vec[0], vec[1], vec[2]))
def debugPrintVecVec(vec1, vec2):
global theDbgFp
theDbgFp.write("(%.3f %.3f %.3f) (%.3f %.3f %.3f)\n" %
(vec1[0], vec1[1], vec1[2], vec2[0], vec2[1], vec2[2]))
"""
#
# init and register
#
def register():
initInterface(bpy.context)
bpy.utils.register_module(__name__)
pass
def unregister():
bpy.utils.unregister_module(__name__)
pass
if __name__ == "__main__":
register()
#readBvhFile(context, filepath, scale, startFrame, rot90, 1)
#readBvhFile(bpy.context, '/home/thomas/makehuman/bvh/Male1_bvh/Male1_A5_PickUpBox.bvh', 1.0, 1, False)
#readBvhFile(bpy.context, '/home/thomas/makehuman/bvh/cmu/10/10_03.bvh', 1.0, 1, False)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment