Skip to content

Commit

Permalink
Merge pull request #24 from daz3d/shape-keys-fixes
Browse files Browse the repository at this point in the history
Ready For Testing
  • Loading branch information
samjay3d authored Mar 26, 2021
2 parents beac83c + 4d44710 commit 33fa9b2
Show file tree
Hide file tree
Showing 22 changed files with 3,792 additions and 2,758 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
import bpy
import mathutils
from . import Global
from . import Versions
from . import DataBase

class Animations:
total_key_count = 0

def update_total_key_count(self,key_count):
if key_count > self.total_key_count:
self.total_key_count = key_count


def reset_total_key_count(self):
self.total_key_count = 0


def has_keyframe(self, ob):
anim = ob.animation_data
if anim is not None and anim.action is not None:
return True
return False


def get_or_create_fcurve(self, action, data_path, array_index=-1, group=None):
for fc in action.fcurves:
if fc.data_path == data_path and (array_index < 0 or fc.array_index == array_index):
return fc

fc = action.fcurves.new(data_path, index=array_index)
fc.group = group
return fc


def add_keyframe_euler(self, action, euler, frame, bone_prefix, group):
for i in range(len(euler)):
fc = self.get_or_create_fcurve(
action, bone_prefix + "rotation_euler",
i,
group
)
pos = len(fc.keyframe_points)
fc.keyframe_points.add(1)
fc.keyframe_points[pos].co = [frame, euler[i]]
fc.update()


def fcurves_group(self, action, data_path):
for fc in action.fcurves:
if fc.data_path == data_path and fc.group is not None:
return fc.group
return None


def frames_matching(self, action, data_path):
frames = set()
for fc in action.fcurves:
if fc.data_path == data_path:
fri = [kp.co[0] for kp in fc.keyframe_points]
frames.update(fri)
return frames


def convert_quaternion_to_euler(self, action, obj):
# Get all the bones with quaternion animation data
bone_prefixes = set()
for fcurve in action.fcurves:
if fcurve.data_path == "rotation_quaternion" or fcurve.data_path[-20:] == ".rotation_quaternion":
bone_prefixes.add(fcurve.data_path[:-19])

for bone_prefix in bone_prefixes:
if (bone_prefix == ""):
bone = obj
else:
# get the bone using the data path prefix
bone = eval("obj." + bone_prefix[:-1])

data_path = bone_prefix + "rotation_quaternion"
frames = self.frames_matching(action, data_path)
group = self.fcurves_group(action, data_path)

for fr in frames:
# Get quaternion keyframe value
quat = bone.rotation_quaternion.copy()
for fcurve in action.fcurves:
if fcurve.data_path == data_path:
quat[fcurve.array_index] = fcurve.evaluate(fr)

# Calculate euler equivalent for the quaternion
order = self.get_rotation_order(bone.name)
euler = quat.to_euler(order)

# Add euler keyframe and set correct rotation order
self.add_keyframe_euler(action, euler, fr, bone_prefix, group)
bone.rotation_mode = order

# delete all the curves with quaternion data
quat_fcurves = []
for fcurve in action.fcurves:
if fcurve.data_path[-20:] == ".rotation_quaternion":
quat_fcurves.append(fcurve)
for fcurve in quat_fcurves:
action.fcurves.remove(fcurve)


def get_rotation_order(self, node_name):
bone_limits = Global.get_bone_limit()
for bone_limit in bone_limits:
if bone_limit[0] in node_name:
return bone_limit[1]
return "XYZ"

def convert_rotation_orders(self):
Versions.active_object(Global.getAmtr())
Global.setOpsMode('POSE')
for bone in Global.getAmtr().pose.bones:
order = bone.rotation_mode
if order == 'XYZ':
bone.rotation_mode = 'ZXY'
elif order == 'XZY':
bone.rotation_mode = 'YZX'
elif order == 'YZX':
bone.rotation_mode = 'YZX'
elif order == 'ZXY':
bone.rotation_mode = 'XYZ'
elif order == 'ZYX':
bone.rotation_mode = 'YZX'


def clean_animations(self):
Versions.active_object(Global.getAmtr())
Global.setOpsMode('POSE')
scene_size = Global.get_size()

#Choose Action
armature = Global.getAmtr()
action = armature.animation_data.action

# Convert rotation animation data from quaternion to euler angles
self.convert_quaternion_to_euler(action, Global.getAmtr())

# Convert animation data from Studio to Blender
curve_count = len(action.fcurves)
index = 0
while index < curve_count:
fcurve = action.fcurves[index]
start_index = fcurve.data_path.find('[')
end_index = fcurve.data_path.find(']')
if (start_index == -1 or end_index == -1):
# Convert Figure root bone animation data
if "Genesis" in action.name:
if fcurve.data_path == "rotation_euler":
for point in fcurve.keyframe_points:
point.co[1] = 0
if fcurve.data_path == "scale":
for point in fcurve.keyframe_points:
point.co[1] = 1.0
# Convert non Figure root bone animation data
else:
if fcurve.data_path == "location":
fcurve_x = action.fcurves[index + 0]
fcurve_y = action.fcurves[index + 1]
fcurve_z = action.fcurves[index + 2]
point_count = len(fcurve_x.keyframe_points)

for i in range(point_count):
# Y invert (-Y)
fcurve_y.keyframe_points[i].co[1] = -fcurve_y.keyframe_points[i].co[1]

# Z invert (-Z)
fcurve_z.keyframe_points[i].co[1] = -fcurve_z.keyframe_points[i].co[1]

index += 2
else:
node_name = fcurve.data_path[start_index + 2 : end_index - 1]
property_name = fcurve.data_path[end_index + 2 :]
rotation_order = self.get_rotation_order(node_name)

# Convert location animation data for all the non root bones
if property_name == "location":
fcurve_x = action.fcurves[index + 0]
fcurve_y = action.fcurves[index + 1]
fcurve_z = action.fcurves[index + 2]
point_count = len(fcurve_x.keyframe_points)
self.update_total_key_count(point_count)

for i in range(point_count):
# Y invert (-Y)
fcurve_y.keyframe_points[i].co[1] = -fcurve_y.keyframe_points[i].co[1]

# Z invert (-Z)
fcurve_z.keyframe_points[i].co[1] = -fcurve_z.keyframe_points[i].co[1]

# Get skeleton scale and set to location animation data
skeleton_data = DataBase.get_skeleton_data()
skeleton_scale = skeleton_data["skeletonScale"]
skeleton_scale *= scene_size # To match armature scale
for i in range(point_count):
fcurve_x.keyframe_points[i].co[1] *= skeleton_scale
fcurve_y.keyframe_points[i].co[1] *= skeleton_scale
fcurve_z.keyframe_points[i].co[1] *= skeleton_scale

index += 2

# Convert rotation animation data for all the non root bones
if property_name == "rotation_euler":
fcurve_x = action.fcurves[index + 0]
fcurve_y = action.fcurves[index + 1]
fcurve_z = action.fcurves[index + 2]
point_count = len(fcurve_x.keyframe_points)
self.update_total_key_count(point_count)

if rotation_order == 'XYZ':
for i in range(point_count):
# YZ switch (Y <-> Z)
temp = fcurve_y.keyframe_points[i].co[1]
fcurve_y.keyframe_points[i].co[1] = fcurve_z.keyframe_points[i].co[1]
fcurve_z.keyframe_points[i].co[1] = temp

# XY switch (X <-> Y)
temp = fcurve_x.keyframe_points[i].co[1]
fcurve_x.keyframe_points[i].co[1] = fcurve_y.keyframe_points[i].co[1]
fcurve_y.keyframe_points[i].co[1] = temp

if(node_name.startswith("r")):
# Y invert (-Y)
fcurve_y.keyframe_points[i].co[1] = -fcurve_y.keyframe_points[i].co[1]

# Z invert (-Z)
fcurve_z.keyframe_points[i].co[1] = -fcurve_z.keyframe_points[i].co[1]

elif rotation_order == 'XZY':
for i in range(point_count):
# XY switch (X <-> Y)
temp = fcurve_x.keyframe_points[i].co[1]
fcurve_x.keyframe_points[i].co[1] = fcurve_y.keyframe_points[i].co[1]
fcurve_y.keyframe_points[i].co[1] = temp

# X invert (-X)
fcurve_x.keyframe_points[i].co[1] = -fcurve_x.keyframe_points[i].co[1]

if(node_name.startswith("r")):
# Y invert (-Y)
fcurve_y.keyframe_points[i].co[1] = -fcurve_y.keyframe_points[i].co[1]

# Z invert (-Z)
fcurve_z.keyframe_points[i].co[1] = -fcurve_z.keyframe_points[i].co[1]

elif rotation_order == "YZX":
# Bones that are pointed down with YZX order
# TODO: remove hardcoding
if node_name in ["hip", "pelvis", "lThighBend", "rThighBend", "lThighTwist", "rThighTwist", "lShin", "rShin"]:
for i in range(point_count):
# Y invert (-Y)
fcurve_y.keyframe_points[i].co[1] = -fcurve_y.keyframe_points[i].co[1]

# Z invert (-Z)
fcurve_z.keyframe_points[i].co[1] = -fcurve_z.keyframe_points[i].co[1]

elif rotation_order == "ZXY":
for i in range(point_count):
# XY switch (X <-> Y)
temp = fcurve_x.keyframe_points[i].co[1]
fcurve_x.keyframe_points[i].co[1] = fcurve_y.keyframe_points[i].co[1]
fcurve_y.keyframe_points[i].co[1] = temp

# YZ switch (Y <-> Z)
temp = fcurve_y.keyframe_points[i].co[1]
fcurve_y.keyframe_points[i].co[1] = fcurve_z.keyframe_points[i].co[1]
fcurve_z.keyframe_points[i].co[1] = temp

elif rotation_order == "ZYX":
for i in range(point_count):
# YZ switch (Y <-> Z)
temp = fcurve_y.keyframe_points[i].co[1]
fcurve_y.keyframe_points[i].co[1] = fcurve_z.keyframe_points[i].co[1]
fcurve_z.keyframe_points[i].co[1] = temp

# X invert (-X)
fcurve_x.keyframe_points[i].co[1] = -fcurve_x.keyframe_points[i].co[1]

index += 2

index += 1

self.convert_rotation_orders()

# Update Name
action.name = "{0} Animation".format(Global.get_asset_name())
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ def makeCustomBone(self):
pb.use_custom_shape_bone_size = True
if pb.custom_shape_scale == 1.0:
pb.custom_shape_scale = 0.3

pb.custom_shape_transform = pb
def find_bone_roop(self,bone_group,rootbone):
for b in bone_group:
if len(b.children) > 0:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from . import Global
import os

bone_limits_dict = dict()
skeleton_data = dict()

def load_bone_limits():
input_file = open(Global.getHomeTown() + Global.getFileSp() + "FIG_boneLimits.csv", "r")
input_file = open(os.path.join(Global.getHomeTown(), "FIG_boneLimits.csv"), "r")
lines = input_file.readlines()
input_file.close()

Expand All @@ -27,7 +28,7 @@ def get_bone_limits_dict():
return bone_limits_dict

def load_skeleton_data():
input_file = open(Global.getHomeTown() + Global.getFileSp() + "FIG_skeletonData.csv", "r")
input_file = open(os.path.join(Global.getHomeTown(),"FIG_skeletonData.csv"), "r")
lines = input_file.readlines()
input_file.close()

Expand Down
Loading

0 comments on commit 33fa9b2

Please sign in to comment.