diff options
author | Thomas Larsson <thomas_larsson_01@hotmail.com> | 2011-07-04 21:22:49 +0400 |
---|---|---|
committer | Thomas Larsson <thomas_larsson_01@hotmail.com> | 2011-07-04 21:22:49 +0400 |
commit | a6f0452eb818c5d8604f6cac5c9226c5d4400a59 (patch) | |
tree | a10ccc83dfc5ca2e686b9850a01a73d973e269a9 /io_import_scene_mhx.py | |
parent | 54f552eec3d7712bc932249c5aa0cd79c2772615 (diff) |
Mhx importer v 1.5.0: can now use Rigify.
Diffstat (limited to 'io_import_scene_mhx.py')
-rw-r--r-- | io_import_scene_mhx.py | 415 |
1 files changed, 328 insertions, 87 deletions
diff --git a/io_import_scene_mhx.py b/io_import_scene_mhx.py index e861fcf8..201d2f94 100644 --- a/io_import_scene_mhx.py +++ b/io_import_scene_mhx.py @@ -26,7 +26,7 @@ """ Abstract MHX (MakeHuman eXchange format) importer for Blender 2.5x. -Version 1.4.0 +Version 1.5.0 This script should be distributed with Blender. If not, place it in the .blender/scripts/addons dir @@ -39,9 +39,9 @@ Alternatively, run the script in the script editor (Alt-P), and access from the bl_info = { 'name': 'Import: MakeHuman (.mhx)', 'author': 'Thomas Larsson', - 'version': (1, 4, 0), - "blender": (2, 5, 7), - "api": 35774, + 'version': (1, 5, 0), + "blender": (2, 5, 8), + "api": 37702, 'location': "File > Import > MakeHuman (.mhx)", 'description': 'Import files in the MakeHuman eXchange format (.mhx)', 'warning': '', @@ -51,9 +51,9 @@ bl_info = { 'category': 'Import-Export'} MAJOR_VERSION = 1 -MINOR_VERSION = 4 +MINOR_VERSION = 5 SUB_VERSION = 0 -BLENDER_VERSION = (2, 57, 0) +BLENDER_VERSION = (2, 58, 0) # # @@ -114,7 +114,8 @@ T_Rigify = 0x1000 T_Opcns = 0x2000 T_Symm = 0x4000 -toggle = T_EnforceVersion + T_Replace + T_Mesh + T_Armature + T_Face + T_Shape + T_Proxy + T_Clothes +toggle = (T_EnforceVersion + T_Replace + T_Mesh + T_Armature + + T_Face + T_Shape + T_Proxy + T_Clothes + T_Rigify) # # Blender versions @@ -481,6 +482,12 @@ def parse(tokens): hideLayers(val) elif key == "CorrectRig": correctRig(val) + elif key == "Rigify": + rig = loadedData['Object'][val[0]] + rig['MhxRigify'] = True + bpy.context.scene.objects.active = rig + if toggle & T_Rigify: + rigifyMhx(bpy.context, rig) elif key == 'AnimationData': try: ob = loadedData['Object'][val[0]] @@ -1532,11 +1539,6 @@ def parseArmature (args, tokens): obname = args[1] mode = args[2] - if mode == 'Rigify': - toggle |= T_Rigify - return parseRigify(amtname, obname, tokens) - - toggle &= ~T_Rigify amt = bpy.data.armatures.new(amtname) ob = createObject('ARMATURE', obname, amt, amtname) @@ -1574,52 +1576,6 @@ def parseArmature (args, tokens): defaultKey(key, val, sub, "amt", ['MetaRig'], globals(), locals()) bpy.ops.object.mode_set(mode='OBJECT') return amt - -# -# parseRigify(amtname, obname, tokens): -# - -def parseRigify(amtname, obname, tokens): - (key,val,sub) = tokens[0] - if key != 'MetaRig': - raise NameError("Expected MetaRig") - typ = val[0] - if typ == "human": - bpy.ops.object.armature_human_advanced_add() - else: - bpy.ops.pose.metarig_sample_add(type = typ) - ob = bpy.context.scene.objects.active - amt = ob.data - loadedData['Rigify'][obname] = ob - loadedData['Armature'][amtname] = amt - loadedData['Object'][obname] = ob - print("Rigify object", ob, amt) - - bpy.ops.object.mode_set(mode='OBJECT') - bpy.ops.object.mode_set(mode='EDIT') - - heads = {} - tails = {} - for (bname, bone) in amt.edit_bones.items(): - heads[bname] = 10*theScale*bone.head - tails[bname] = 10*theScale*bone.tail - - for (key, val, sub) in tokens: - if key == 'Bone': - bname = val[0] - print("Bone", bname) - try: - bone = amt.edit_bones[bname] - except: - print("Did not find bone %s" % bname) - bone = None - print(" -> ", bone) - if bone: - parseBone(bone, amt, sub, heads, tails) - else: - defaultKey(key, val, sub, "amt", ['MetaRig'], globals(), locals()) - bpy.ops.object.mode_set(mode='OBJECT') - return amt # # parseBone(bone, amt, tokens, heads, tails): @@ -1654,8 +1610,6 @@ def parseBone(bone, amt, tokens, heads, tails): def parsePose (args, tokens): global todo - if toggle & T_Rigify: - return name = args[0] ob = loadedData['Object'][name] bpy.context.scene.objects.active = ob @@ -2084,21 +2038,6 @@ def postProcess(args): ob = None if toggle & T_Diamond == 0 and ob: deleteDiamonds(ob) - if toggle & T_Rigify and False: - for rig in loadedData['Rigify'].values(): - bpy.context.scene.objects.active = rig - print("Rigify", rig) - bpy.ops.pose.metarig_generate() - print("Metarig generated") - #bpy.context.scene.objects.unlink(rig) - - rig = bpy.context.scene.objects.active - print("Rigged", rig, bpy.context.object) - ob = loadedData['Object'][human] - mod = ob.modifiers[0] - print(ob, mod, mod.object) - mod.object = rig - print("Rig changed", mod.object) return # @@ -2611,9 +2550,321 @@ def writeDefaults(): fp.close() return +################################################################################### +# +# Postprocessing of rigify rig +# +# rigifyMhx(context, mhx): +# +################################################################################### + +def rigifyMhx(context, mhx): + print("Modifying MHX rig to Rigify") + # Delete widgets + scn = context.scene + for ob in scn.objects: + if ob.type == 'MESH' and ob.name[0:3] == "WGT": + scn.objects.unlink(ob) + + # Save mhx bone locations + name = mhx.name + heads = {} + tails = {} + rolls = {} + parents = {} + extras = {} + bpy.ops.object.mode_set(mode='EDIT') + + newParents = { + 'head' : 'DEF-head', + 'ribs' : 'DEF-ribs', + 'upper_arm.L' : 'DEF-upper_arm.L.02', + 'thigh.L' : 'DEF-thigh.L.02', + 'upper_arm.R' : 'DEF-upper_arm.R.02', + 'thigh.R' : 'DEF-thigh.R.02', + } + + for eb in mhx.data.edit_bones: + heads[eb.name] = eb.head.copy() + tails[eb.name] = eb.tail.copy() + rolls[eb.name] = eb.roll + if eb.parent: + par = eb.parent.name + print(eb.name, par) + try: + parents[eb.name] = newParents[par] + except: + parents[eb.name] = par + else: + parents[eb.name] = None + extras[eb.name] = not eb.layers[16] + bpy.ops.object.mode_set(mode='OBJECT') + + # Find corresponding meshes. Can be several (clothes etc.) + meshes = [] + for ob in scn.objects: + for mod in ob.modifiers: + if (mod.type == 'ARMATURE' and mod.object == mhx): + meshes.append((ob, mod)) + if meshes == []: + raise NameError("Did not find matching mesh") + + # Rename Head vertex group + for (mesh, mod) in meshes: + try: + vg = mesh.vertex_groups['DfmHead'] + vg.name = 'DEF-head' + except: + pass + + # Change rigify bone locations + scn.objects.active = None + try: + bpy.ops.object.armature_human_advanced_add() + success = True + except: + success = False + if not success: + raise NameError("Unable to create advanced human. Make sure that the Rigify add-on is enabled. It is found under Rigging.") + return + + rigify = context.object + bpy.ops.object.mode_set(mode='EDIT') + for eb in rigify.data.edit_bones: + eb.head = heads[eb.name] + eb.tail = tails[eb.name] + eb.roll = rolls[eb.name] + extras[eb.name] = False + + fingerPlanes = [ + ('UP-thumb.L', 'thumb.01.L', 'thumb.03.L', ['thumb.02.L']), + ('UP-index.L', 'finger_index.01.L', 'finger_index.03.L', ['finger_index.02.L']), + ('UP-middle.L', 'finger_middle.01.L', 'finger_middle.03.L', ['finger_middle.02.L']), + ('UP-ring.L', 'finger_ring.01.L', 'finger_ring.03.L', ['finger_ring.02.L']), + ('UP-pinky.L', 'finger_pinky.01.L', 'finger_pinky.03.L', ['finger_pinky.02.L']), + ('UP-thumb.R', 'thumb.01.R', 'thumb.03.R', ['thumb.02.R']), + ('UP-index.R', 'finger_index.01.R', 'finger_index.03.R', ['finger_index.02.R']), + ('UP-middle.R', 'finger_middle.01.R', 'finger_middle.03.R', ['finger_middle.02.R']), + ('UP-ring.R', 'finger_ring.01.R', 'finger_ring.03.R', ['finger_ring.02.R']), + ('UP-pinky.R', 'finger_pinky.01.R', 'finger_pinky.03.R', ['finger_pinky.02.R']), + ] + + for (upbone, first, last, middles) in fingerPlanes: + extras[upbone] = False + #lineateChain(upbone, first, last, middles, 0.01, rigify, heads, tails) + + ikPlanes = [ + ('UP-leg.L', 'thigh.L', 'shin.L'), + ('UP-arm.L', 'upper_arm.L', 'forearm.L'), + ('UP-leg.R', 'thigh.R', 'shin.R'), + ('UP-arm.R', 'upper_arm.R', 'forearm.R'), + ] + + for (upbone, first, last) in ikPlanes: + extras[upbone] = False + lineateChain(upbone, first, last, [], 0.1, rigify, heads, tails) + + bpy.ops.object.mode_set(mode='OBJECT') + + # Generate meta rig + bpy.ops.pose.rigify_generate() + scn.objects.unlink(rigify) + meta = context.object + meta.name = name+"Meta" + meta.show_x_ray = True + for (mesh, mod) in meshes: + mod.object = meta + + # Parent widgets under empty + empty = bpy.data.objects.new("Widgets", None) + scn.objects.link(empty) + empty.layers = 20*[False] + empty.layers[19] = True + for ob in scn.objects: + if ob.type == 'MESH' and ob.name[0:4] == "WGT-" and not ob.parent: + ob.parent = empty + + # Copy extra bones to meta rig + bpy.ops.object.mode_set(mode='EDIT') + for name in heads.keys(): + if extras[name]: + eb = meta.data.edit_bones.new(name) + eb.head = heads[name] + eb.tail = tails[name] + eb.roll = rolls[name] + for name in heads.keys(): + if extras[name] and parents[name]: + eb = meta.data.edit_bones[name] + eb.parent = meta.data.edit_bones[parents[name]] + + # Copy constraints etc. + bpy.ops.object.mode_set(mode='POSE') + for name in heads.keys(): + if extras[name]: + pb1 = mhx.pose.bones[name] + pb2 = meta.pose.bones[name] + pb2.custom_shape = pb1.custom_shape + pb2.lock_location = pb1.lock_location + pb2.lock_rotation = pb1.lock_rotation + pb2.lock_scale = pb1.lock_scale + b1 = pb1.bone + b2 = pb2.bone + b2.use_deform = b1.use_deform + b2.hide_select = b1.hide_select + b2.show_wire = b1.show_wire + layers = 32*[False] + if b1.layers[8]: + layers[28] = True + else: + layers[29] = True + if b1.layers[10]: + layers[2] = True + b2.layers = layers + for cns1 in pb1.constraints: + cns2 = copyConstraint(cns1, pb1, pb2, mhx, meta) + if cns2.type == 'CHILD_OF': + meta.data.bones.active = pb2.bone + bpy.ops.constraint.childof_set_inverse(constraint=cns2.name, owner='BONE') + + # Create animation data + if mhx.animation_data: + for fcu in mhx.animation_data.drivers: + meta.animation_data.drivers.from_existing(src_driver=fcu) + + fixDrivers(meta.animation_data, mhx, meta) + for (mesh, mod) in meshes: + skeys = mesh.data.shape_keys + if skeys: + fixDrivers(skeys.animation_data, mhx, meta) + + scn.objects.unlink(mhx) + print("Rigify rig complete") + return + +# +# lineateChain(upbone, first, last, middles, minDist, rigify, heads, tails): +# lineate(pt, start, minDist, normal, offVector): +# + +def lineateChain(upbone, first, last, middles, minDist, rigify, heads, tails): + fb = rigify.data.edit_bones[first] + lb = rigify.data.edit_bones[last] + uhead = heads[upbone] + utail = tails[upbone] + tang = lb.tail - fb.head + tangent = tang/tang.length + up = (uhead+utail)/2 - fb.head + norm = up - tangent*tangent.dot(up) + normal = norm/norm.length + offVector = tangent.cross(normal) + vec = utail - uhead + fb.tail = lineate(fb.tail, fb.head, minDist, normal, offVector) + lb.head = lineate(lb.head, fb.head, minDist, normal, offVector) + for bone in middles: + mb = rigify.data.edit_bones[bone] + mb.head = lineate(mb.head, fb.head, minDist, normal, offVector) + mb.tail = lineate(mb.tail, fb.head, minDist, normal, offVector) + return + +def lineate(pt, start, minDist, normal, offVector): + diff = pt - start + diff = diff - offVector*offVector.dot(diff) + dist = diff.dot(normal) + if dist < minDist: + diff += (minDist - dist)*normal + return start + diff + +# +# fixDrivers(adata, mhx, meta): +# + +def fixDrivers(adata, mhx, meta): + if not adata: + return + for fcu in adata.drivers: + for var in fcu.driver.variables: + for targ in var.targets: + if targ.id == mhx: + targ.id = meta + return + +# +# copyConstraint(cns1, pb1, pb2, mhx, meta): +# + +def copyConstraint(cns1, pb1, pb2, mhx, meta): + substitute = { + 'Head' : 'DEF-head', + 'MasterFloor' : 'root', + 'upper_arm.L' : 'DEF-upper_arm.L.01', + 'upper_arm.R' : 'DEF-upper_arm.R.01', + 'thigh.L' : 'DEF-thigh.L.01', + 'thigh.R' : 'DEF-thigh.R.01', + 'shin.L' : 'DEF-shin.L.01', + 'shin.R' : 'DEF-shin.R.01' + } + + cns2 = pb2.constraints.new(cns1.type) + for prop in dir(cns1): + if prop == 'target': + if cns1.target == mhx: + cns2.target = meta + else: + cns2.target = cns1.target + elif prop == 'subtarget': + try: + cns2.subtarget = substitute[cns1.subtarget] + except: + cns2.subtarget = cns1.subtarget + elif prop[0] != '_': + try: + expr = "cns2.%s = cns1.%s" % (prop, prop) + #print(pb1.name, expr) + exec(expr) + except: + pass + return cns2 + +# +# class OBJECT_OT_RigifyMhxButton(bpy.types.Operator): +# + +class OBJECT_OT_RigifyMhxButton(bpy.types.Operator): + bl_idname = "mhxrig.rigify_mhx" + bl_label = "Rigify MHX rig" + + def execute(self, context): + rigifyMhx(context, context.object) + return{'FINISHED'} + +# +# class RigifyMhxPanel(bpy.types.Panel): +# + +class RigifyMhxPanel(bpy.types.Panel): + bl_label = "Rigify MHX" + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + + @classmethod + def poll(cls, context): + if context.object: + try: + return context.object['MhxRigify'] + except: + return False + return False + + def draw(self, context): + layout = self.layout + layout.operator("mhxrig.rigify_mhx") + return + +################################################################################### # # User interface # +################################################################################### DEBUG = False from bpy.props import StringProperty, FloatProperty, EnumProperty, BoolProperty @@ -2633,8 +2884,8 @@ MhxBoolProps = [ ("shape", "Body shapes", "Include body shapekeys", T_Shape), ("symm", "Symmetric shapes", "Keep shapekeys symmetric", T_Symm), ("diamond", "Diamonds", "Keep joint diamonds", T_Diamond), - ("bend", "Bend joints", "Bend joints for better IK", T_Bend), - #("opcns", "Operator constraints", "Only for Aligorith", T_Opcns), + ("rigify", "Rigify", "Create rigify control rig", T_Rigify), + #("bend", "Bend joints", "Bend joints for better IK", T_Bend), ] class ImportMhx(bpy.types.Operator, ImportHelper): @@ -2702,16 +2953,6 @@ if __name__ == "__main__": pass register() -# -# Testing -# -""" -#readMhxFile("C:/Documents and Settings/xxxxxxxxxxxxxxxxxxxx/Mina dokument/makehuman/exports/foo-25.mhx", 'Classic') -readMhxFile("/home/thomas/makehuman/exports/foo-25.mhx", 1.0) - -#toggle = T_Replace + T_Mesh + T_Armature + T_MHX -#readMhxFile("/home/thomas/myblends/test.mhx", 1.0) -""" |