224 lines
10 KiB
Python
224 lines
10 KiB
Python
#!/usr/bin/env python
|
|
|
|
import os, sys, time
|
|
import bpy
|
|
from math import pi
|
|
import glob
|
|
import shutil
|
|
from mathutils import Vector, Matrix
|
|
from math import radians, pi
|
|
sys.path.insert(0, os.getcwd() + "/assets/blender/scripts")
|
|
from vrm import rename
|
|
from mixamo import mixamo_rig
|
|
from mixamo.lib.armature import *
|
|
#from mixamo.mixamoroot import import_armature
|
|
#from mixamo.import_mixamo_root_motion import import_mixamo_root_motion
|
|
from settings import VRMDataFemale, VRMDataMale, VRMDataMaleBabyShape, basepath
|
|
|
|
|
|
imports = [VRMDataFemale(), VRMDataMale(), VRMDataMaleBabyShape()]
|
|
|
|
|
|
class mkrig:
|
|
ik_arms = True
|
|
ik_legs = True
|
|
def __init__(self):
|
|
mixamo_rig._make_rig(self)
|
|
mixamo_rig.remove_temp_objects()
|
|
mixamo_rig.clean_scene()
|
|
def get_anim(filepath, root_bone_name="Root", hip_bone_name="mixamorig:Hips", remove_prefix=False, name_prefix="mixamorig:", insert_root=False, delete_armatures=False):
|
|
# current_context = bpy.context.area.ui_type
|
|
old_objs = set(bpy.context.scene.objects)
|
|
try:
|
|
import_armature(filepath, root_bone_name, hip_bone_name, remove_prefix, name_prefix, insert_root, delete_armatures)
|
|
imported_objects = set(bpy.context.scene.objects) - old_objs
|
|
if delete_armatures and num_files > 1:
|
|
deleteArmature(imported_objects)
|
|
except Exception as e:
|
|
log.error("[Mixamo Root] ERROR get_all_anims raised %s when processing %s" % (str(e), filepath))
|
|
# bpy.context.area.ui_type = current_context
|
|
bpy.context.scene.frame_start = 0
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
def create_root_bone(anim_obj):
|
|
bpy.context.view_layer.objects.active = anim_obj
|
|
bpy.ops.object.mode_set(mode='EDIT')
|
|
root_bone = anim_obj.data.edit_bones.new("Root")
|
|
root_bone.tail.y = 0.5
|
|
anim_obj.data.edit_bones["mixamorig:Hips"].parent = anim_obj.data.edit_bones["Root"]
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
def hips_to_root(anim_obj):
|
|
for fc in anim_obj.animation_data.action.fcurves:
|
|
if "mixamorig:Hips" in fc.data_path:
|
|
if "location" in fc.data_path:
|
|
print(fc, fc.data_path, fc.array_index)
|
|
if fc.array_index in [0, 2]:
|
|
fc.data_path = fc.data_path.replace("mixamorig:Hips", "Root")
|
|
# if fc.array_index == 2:
|
|
# for kp in fc.keyframe_points:
|
|
# kp.co.z = min(0, abs(kp.co.z))
|
|
# hip_curves = [fc for fc in anim_obj.animation_data.action.fcurves if hip_bone_name in fc.data_path and fc.data_path.startswith('location')]
|
|
# print(hip_curves)
|
|
def hips_to_root(anim_obj):
|
|
for fc in anim_obj.animation_data.action.fcurves:
|
|
if "mixamorig:Hips" in fc.data_path:
|
|
if "location" in fc.data_path:
|
|
print(fc, fc.data_path, fc.array_index)
|
|
if fc.array_index in [0, 2]:
|
|
fc.data_path = fc.data_path.replace("mixamorig:Hips", "Root")
|
|
def hips_to_root2(anim_obj):
|
|
for fc in anim_obj.animation_data.action.fcurves:
|
|
if "Ctrl_Hips" in fc.data_path:
|
|
if "location" in fc.data_path:
|
|
print(fc, fc.data_path, fc.array_index)
|
|
if fc.array_index in [0, 2]:
|
|
data_path = fc.data_path[:]
|
|
# fc.data_path = data_path.replace("Ctrl_Hips", "Ctrl_Master")
|
|
fcr = anim_obj.animation_data.action.fcurves.new(data_path = data_path.replace("Ctrl_Hips", "Root"), index = fc.array_index)
|
|
keys = [0] * (2 * len(fc.keyframe_points))
|
|
fcr.keyframe_points.add(len(fc.keyframe_points))
|
|
fc.keyframe_points.foreach_get("co", keys)
|
|
fcr.keyframe_points.foreach_set("co", keys)
|
|
print("ROOT")
|
|
# fc.data_path = data_path.replace("Ctrl_Hips", "Root")
|
|
# for fcr in anim_obj.animation_data.action.fcurves:
|
|
# if "Root" in fcr.data_path:
|
|
# fcr.array_index = fc.array_index
|
|
# print("ROOT")
|
|
|
|
for imp in imports:
|
|
bpy.ops.wm.read_homefile(use_empty=True)
|
|
for o in bpy.data.objects:
|
|
bpy.data.objects.remove(o)
|
|
print(basepath + "/assets/vroid/" + imp.path)
|
|
result = bpy.ops.import_scene.vrm(filepath=(basepath + "/assets/vroid/" + imp.path))
|
|
if result != {"FINISHED"}:
|
|
raise Exception(f"Failed to import vrm: {result}")
|
|
armature_count = 0
|
|
for obj in bpy.data.objects:
|
|
if (obj.type == "ARMATURE"):
|
|
armature_count += 1
|
|
if armature_count > 1:
|
|
raise Exception("Bad scene data")
|
|
main_armature = None
|
|
for obj in bpy.data.objects:
|
|
if (obj.type == "ARMATURE"):
|
|
main_armature = obj
|
|
break
|
|
if main_armature == None:
|
|
raise Exception("Bad scene data")
|
|
print("Renaming...")
|
|
main_armature.select_set(True)
|
|
bpy.context.view_layer.objects.active = main_armature
|
|
rename.rename_bones(main_armature)
|
|
main_armature.select_set(False)
|
|
main_armature.name = imp.armature_name
|
|
main_armature["VRM_IMPORTED_NAME"] = "female"
|
|
if main_armature.animation_data is None:
|
|
main_armature.animation_data_create()
|
|
main_armature.select_set(True)
|
|
bpy.context.view_layer.objects.active = main_armature
|
|
mkrig()
|
|
main_armature.select_set(False)
|
|
bpy.context.view_layer.objects.active = None
|
|
|
|
for anim in imp.mixamo_animations:
|
|
anim_path = imp.mixamo_animation_path + anim + ".fbx"
|
|
print("Load BVH..." + anim_path)
|
|
old_objs = set(bpy.context.scene.objects)
|
|
bpy.ops.import_scene.fbx(filepath=anim_path, global_scale=imp.fbx_scale)
|
|
#import_mixamo_root_motion(bpy.context, anim_path, True, True, False, False, False, 'COPY_HIPS', True, True, True)
|
|
#get_anim(anim_path)
|
|
imported_objects = set(bpy.context.scene.objects) - old_objs
|
|
for anim_obj in imported_objects:
|
|
if anim_obj == main_armature:
|
|
continue
|
|
if "VRM_IMPORTED_NAME" in anim_obj:
|
|
continue
|
|
if main_armature == anim_obj or anim_obj.type != "ARMATURE":
|
|
continue
|
|
# create_root_bone(anim_obj)
|
|
# hips_to_root(anim_obj)
|
|
if anim_obj.animation_data == None:
|
|
print("Bad object: " + anim_obj.name + " " + anim_obj.type)
|
|
bpy.data.objects.remove(anim_obj)
|
|
continue
|
|
if anim_obj.animation_data.action == None:
|
|
print("Bad object: " + anim_obj.name + " " + anim_obj.type)
|
|
bpy.data.objects.remove(anim_obj)
|
|
continue
|
|
print("importing: " + anim_obj.animation_data.action.name)
|
|
mixamo_rig._import_anim(anim_obj, main_armature, True)
|
|
print("===" + main_armature.animation_data.action.name)
|
|
main_armature.animation_data.action.name = anim
|
|
hips_to_root2(main_armature)
|
|
track = main_armature.animation_data.nla_tracks.new()
|
|
action = main_armature.animation_data.action
|
|
track.name = action.name
|
|
track.strips.new(action.name, int(action.frame_range[0]), action)
|
|
track.mute = True
|
|
track.lock = True
|
|
bpy.data.objects.remove(anim_obj)
|
|
imported_objects.clear()
|
|
imported_objects = set(bpy.context.scene.objects) - old_objs
|
|
for anim_obj in imported_objects:
|
|
bpy.data.objects.remove(anim_obj)
|
|
|
|
# bpy.ops.import_scene.fbx(filepath=anim_path,
|
|
# directory='', filter_glob='*.fbx',
|
|
# files=None, ui_tab='MAIN',
|
|
# use_manual_orientation=False,
|
|
# global_scale=1.0, bake_space_transform=False,
|
|
# use_custom_normals=True, colors_type='SRGB',
|
|
# use_image_search=True, use_alpha_decals=False,
|
|
# decal_offset=0.0, use_anim=True, anim_offset=1.0,
|
|
# use_subsurf=False, use_custom_props=True,
|
|
# use_custom_props_enum_as_string=True,
|
|
# ignore_leaf_bones=False, force_connect_children=False,
|
|
# automatic_bone_orientation=False, primary_bone_axis='Y',
|
|
# secondary_bone_axis='X', use_prepost_rot=True,
|
|
# axis_forward='-Z', axis_up='Y')
|
|
# bpy.context.object.name = anim
|
|
# bpy.context.object.animation_data.action.name = anim
|
|
# _zero_out(main_armature)
|
|
main_armature.animation_data.action = bpy.data.actions.new(name="default")
|
|
default_action = main_armature.animation_data.action
|
|
bpy.context.view_layer.objects.active = main_armature
|
|
main_armature.select_set(True)
|
|
layers = enable_all_armature_layers()
|
|
bpy.ops.object.mode_set(mode='POSE')
|
|
for b in main_armature.pose.bones:
|
|
b.location = [0,0,0]
|
|
b.rotation_euler = [0,0,0]
|
|
b.rotation_quaternion = [1,0,0,0]
|
|
b.scale = [1,1,1]
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
|
|
bpy.ops.object.mode_set(mode='POSE')
|
|
for b in main_armature.data.bones:
|
|
if b.name.find("Ctrl_") < 0 and b.name.find("ctrl_") < 0:
|
|
continue
|
|
main_armature.pose.bones[b.name].matrix_basis.identity()
|
|
main_armature.pose.bones[b.name].keyframe_insert(data_path='location', frame=1)
|
|
rotation_mode = main_armature.pose.bones[b.name].rotation_mode
|
|
if rotation_mode == "QUATERNION":
|
|
main_armature.pose.bones[b.name].keyframe_insert(data_path='rotation_quaternion', frame=1)
|
|
elif rotation_mode == "AXIS_ANGLE":
|
|
main_armature.pose.bones[b.name].keyframe_insert(data_path='rotation_axis_angle', frame=1)
|
|
else:
|
|
main_armature.pose.bones[b.name].keyframe_insert(data_path='rotation_euler', frame=1)
|
|
main_armature.pose.bones[b.name].keyframe_insert(data_path='scale', frame=1)
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
track = main_armature.animation_data.nla_tracks.new()
|
|
action = main_armature.animation_data.action
|
|
track.name = action.name
|
|
track.strips.new(action.name, int(action.frame_range[0]), action)
|
|
track.mute = True
|
|
track.lock = True
|
|
restore_armature_layers(layers)
|
|
main_armature.animation_data.action = default_action
|
|
|
|
main_armature.select_set(False)
|
|
bpy.context.view_layer.objects.active = None
|
|
bpy.ops.wm.save_as_mainfile(filepath=(basepath + "/assets/blender/" + imp.outfile))
|
|
|