Skip to content

Commit

Permalink
0.6: Added Armature Repose Button
Browse files Browse the repository at this point in the history
- Updated Armature
- Myriad of other features I have forgotten about
  • Loading branch information
Menithal committed Mar 15, 2018
1 parent 30e160b commit 3ffef5f
Show file tree
Hide file tree
Showing 6 changed files with 626 additions and 81 deletions.
2 changes: 1 addition & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
bl_info = {
"name": "HiFi Blender Add-on",
"author": "Matti 'Menithal' Lahtinen",
"version": (0,4,4),
"version": (0,6,0),
"blender": (2,7,7),
"location": "File > Import-Export, Materials, Armature",
"description": "Blender tools to allow for easier Content creation for High Fidelity",
Expand Down
61 changes: 43 additions & 18 deletions debug_armature_extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,43 +36,69 @@ def vec4_to_list(v):
def vec_to_list(v):
return [v.x,v.y,v.z]

def build_armature(bone, tree):
def build_armature(bone, bones, tree):

print(bone.name)
rotation = matrix4_to_dict(bone.matrix)

print(rotation)
head = vec_to_list(bone.head)
tail = vec_to_list(bone.tail)
regular_bone = bones[bone.name]
current_tree = {
"name": bone.name,
"rotation": rotation,
"head": head,
"tail": tail,
"matrix": bone.matrix,
"matrix_local": regular_bone.matrix_local,
"head": bone.head,
"tail": bone.tail,
"connect": bone.use_connect,
"children": []
}

for child in bone.children:
build_armature(child, current_tree["children"])
build_armature(child, bones, current_tree["children"])

tree.append(current_tree)
return tree


def build_world_rotations(bone, world_matrix, list):

parent_rotation = world_matrix.to_quaternion()

matrix = bone.matrix

current_rotation = matrix.to_quaternion()
current_node = {
"name": bone.name,
"rotation": parent_rotation * current_rotation,
"local": bone.matrix_local.to_quaternion()
}

list.append(current_node)

for child in bone.children:
build_world_rotations(child, world_matrix, list)

return list

armature = bpy.context.object.data

print("|||||||||||||||||||||||||||")
print("---------------------------")
print("---------POSE DATA---------")
print("---------------------------")
print("---------------------------")
print("|||||||||||||||||||||||||||")

armature = bpy.context.object

world_matrix = armature.matrix_world


if bpy.context.active_object:
bpy.ops.object.mode_set(mode = 'EDIT')

print(armature.edit_bones[0].name)
if len(armature.edit_bones) > 0:
test = build_armature( armature.edit_bones[0], [])
print(test)
print(armature.data.edit_bones[0].name)
if len(armature.data.edit_bones) > 0:
edit_armature = build_armature( armature.data.edit_bones[0], armature.data.bones, [])
print("structure =", edit_armature)

print("#-----------------------------")




bpy.ops.object.mode_set(mode = 'OBJECT')
Expand All @@ -85,4 +111,3 @@ def build_armature(bone, tree):

# print(bone.name, rotation, head, tail)


412 changes: 392 additions & 20 deletions hifi_armature_data.py

Large diffs are not rendered by default.

141 changes: 141 additions & 0 deletions hifi_armature_repose.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@

import bpy
from mathutils import Quaternion, Matrix, Vector, Euler

from math import pi
from .hifi_armature_data import structure as base_armature


def fix_armature(obj):

bpy.ops.object.mode_set(mode = 'OBJECT')
bpy.ops.object.select_all(action='DESELECT')

obj.select = True
bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)
obj.scale = Vector((100, 100, 100))

print("Set Angle -90")
str_angle = -90 * pi/180
obj.rotation_euler = Euler((str_angle, 0, 0), 'XYZ')

bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)

obj.scale = Vector((0.01, 0.01, 0.01))
obj.rotation_euler = Euler((-str_angle, 0, 0), 'XYZ')

bpy.ops.object.select_all(action='DESELECT')


def navigate_armature(data, current_rest_node, world_matrix, parent, parent_node):

name = current_rest_node["name"]
bone = data.get(name)

if(bone):
print(name)
bone.rotation_mode = "QUATERNION"

destination_matrix = current_rest_node["matrix_local"].copy()
inv_destination_matrix = destination_matrix.inverted()

matrix = bone.matrix

if parent:
parent_matrix = parent.matrix.copy()
parent_inverted = parent_matrix.inverted()
parent_destination = parent_node["matrix_local"].copy()
else:
parent_matrix = Matrix()
parent_inverted = Matrix()
parent_destination = Matrix()

smat = inv_destination_matrix * (parent_destination * ( parent_inverted * matrix))

bone.rotation_quaternion = smat.to_quaternion().inverted()

for child in current_rest_node["children"]:

navigate_armature(data, child, world_matrix, bone, current_rest_node)

else:
bone = parent

for child in current_rest_node["children"]:
navigate_armature(data, child, world_matrix, bone, parent_node)


def retarget_armature(options):

obj = bpy.context.object
if obj.type == "ARMATURE":
print("Got Armature")
bpy.ops.object.mode_set(mode='POSE')
bpy.ops.pose.select_all(action='SELECT')

bpy.ops.pose.transforms_clear()
bpy.ops.pose.select_all(action='DESELECT')
print("---")
world_matrix = obj.matrix_world
bones = obj.pose.bones
for bone in base_armature:
navigate_armature(bones, bone, world_matrix, None, None)
print("Iterating Bones")

bpy.ops.object.mode_set(mode='OBJECT')

if options['apply']:

print("Now Fix Armature for all")
bpy.context.scene.objects.active = obj
print(bpy.context.active_object.name)

bpy.ops.object.mode_set(mode='POSE')
bpy.ops.pose.armature_apply()
bpy.ops.object.mode_set(mode='OBJECT')
fix_armature(obj)

for child in obj.children:
armature = None

for modifier in child.modifiers:
if modifier.type == "ARMATURE" and modifier.object == obj:
name = modifier.name
## COPY OTHER SETTINGs
print("Apply", name, " to ", child.name)

bpy.context.scene.objects.active = child
armature = modifier
bpy.ops.object.modifier_apply(apply_as='DATA', modifier=modifier.name)
break

# If Overriden Armature is found, then override
if armature:
print("Creating new modifier", name, "_fix for ", child.name)
new_modifier = child.modifiers.new(name + "_fix", "ARMATURE")
new_modifier.object = obj

print("Rescale", child.name, child.dimensions, child.scale)
bpy.context.scene.objects.active = child
### TODO> Something is wrong here. its not scaling the parent correctly
# Then the scale correction assume current is correct
child.select = True
print('Active is', bpy.context.active_object.name, bpy.context.selected_objects)
state = bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)
print(state)
print("Now", child.name, child.dimensions, child.scale, bpy.context.selected_objects)
child.scale = Vector((100, 100, 100))

# Now Rescale to the correct one.
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)

print(bpy.context.active_object.name)
print("Added size", child.name, child.dimensions, child.scale)
child.scale = Vector((0.01, 0.01, 0.01))
child.select = False
print("Down Scaled to Normal", child.name, child.dimensions, child.scale)




#retarget_armature({'apply': True})
69 changes: 39 additions & 30 deletions hifi_armature_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
import bpy
import sys
from .hifi_armature_data import structure as base_armature
from .hifi_armature_repose import retarget_armature, fix_armature
from mathutils import Quaternion, Vector, Euler, Matrix
from math import pi

if "bpy" in locals():
import importlib
if "hifi_armature" in locals():
importlib.reload(hifi_armature)
if "hifi_armature_repose" in locals():
importlib.reload(hifi_armature_repose)

def list_tuple(l):
if len(l) == 4:
Expand Down Expand Up @@ -56,16 +56,19 @@ def build_armature_structure(data, current_node, parent):

current_bone.parent = parent

current_bone.head = list_vector(current_node["head"])
current_bone.tail = list_vector(current_node["tail"])
mat = list_matrix(current_node['rotation'])
current_bone.head = current_node["head"]
current_bone.tail = current_node["tail"]
mat = current_node['matrix']
current_bone.matrix = mat

if current_node["connect"]:
current_bone.use_connect = True

for child in current_node["children"]:
build_armature_structure(data, child, current_bone)

return current_bone


def build_skeleton():
current_view = bpy.context.area.type
Expand All @@ -85,7 +88,6 @@ def build_skeleton():
if bpy.context.active_object:
bpy.ops.object.mode_set(mode = 'OBJECT')

print ("Adding Armature" )
bpy.ops.object.add(type="ARMATURE", enter_editmode=True)

current_armature = bpy.context.active_object
Expand All @@ -95,21 +97,8 @@ def build_skeleton():
for root_bone in base_armature:
build_armature_structure(current_armature.data, root_bone, None)

#bpy.ops.object.mode_set(mode = 'OBJECT')


bpy.ops.object.mode_set(mode = 'OBJECT')

obj = bpy.context.active_object

obj.scale = Vector((100, 100, 100))
str_angle = -90 * pi/180
obj.rotation_euler = Euler((str_angle, 0, 0), 'XYZ')

bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)
bpy.context.active_object.scale = Vector((0.01, 0.01, 0.01))
obj.rotation_euler = Euler((-str_angle, 0, 0), 'XYZ')

fix_armature(bpy.context.active_object)

except Exception as detail:
print('Error', detail)

Expand All @@ -133,13 +122,13 @@ def poll(self, context):
def draw(self, context):
layout = self.layout
layout.operator(HifiArmatureCreateOperator.bl_idname)
layout.operator(HifiArmatureRetargetPoseOperator.bl_idname)
return None



class HifiArmatureCreateOperator(bpy.types.Operator):
bl_idname = "armature_toolset_create_base_rig.hifi"
bl_label = "Create High Fidelity Armature"
bl_label = "Add HiFi Armature"

bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
Expand All @@ -149,24 +138,44 @@ def execute(self, context):
build_skeleton()
return {'FINISHED'}

def draw(self, context):
layout = self.layout

class HifiArmatureRetargetPoseOperator(bpy.types.Operator):
bl_idname = "armature_toolset_retarget.hifi"
bl_label = "Retarget Avatar Pose / Fix Avatar"

bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
bl_category = "High Fidelity"

def execute(self, context):
retarget_armature({'apply': True})
return {'FINISHED'}




classes = [
HifiArmaturePanel,
HifiArmatureCreateOperator
HifiArmatureCreateOperator,
HifiArmatureRetargetPoseOperator
]

def armature_create_menu_func(self,context):
self.layout.operator(HifiArmatureCreateOperator.bl_idname,
text="Add HiFi Armature",
icon="ARMATURE_DATA")


def armature_ui_register():
for cls in classes:
bpy.utils.register_class(cls)

bpy.types.INFO_MT_armature_add.append(armature_create_menu_func)

def armature_ui_unregister():
def armature_ui_unregister():
for cls in classes:
bpy.utils.unregister_class(cls)

bpy.types.INFO_MT_armature_add.remove(armature_create_menu_func)

if __name__ == "__main__":
armature_ui_register()
Loading

0 comments on commit 3ffef5f

Please sign in to comment.