|
import os |
|
from glob import glob |
|
|
|
import bpy |
|
from tqdm import tqdm |
|
|
|
from utils import ( |
|
HiddenPrints, |
|
get_all_armature_obj, |
|
get_rest_bones, |
|
load_file, |
|
mesh_quads2tris, |
|
remove_all, |
|
select_objs, |
|
) |
|
|
|
|
|
def rename_maxiamo_bone(armature_obj): |
|
"""Replace name like 'mixamorig10:xxx' to 'mixamorig:xxx, so that character can be correctly animated.'""" |
|
import re |
|
|
|
pattern = re.compile(r"mixamorig[0-9]+:") |
|
for bone in armature_obj.data.bones: |
|
bone.name = re.sub(pattern, "mixamorig:", bone.name) |
|
return armature_obj |
|
|
|
|
|
if __name__ == "__main__": |
|
input_dir = "." |
|
keep_texture = False |
|
output_dir = os.path.join(input_dir, "character_refined") |
|
if keep_texture: |
|
output_dir += "_textured" |
|
os.makedirs(output_dir, exist_ok=True) |
|
character_list = sorted(glob(os.path.join(input_dir, "character", "*.fbx"))) |
|
character_list_upgraded = sorted(glob(os.path.join(input_dir, "character_fbx_upgraded", "*.fbx"))) |
|
character_list_upgraded = {os.path.basename(x): x for x in character_list_upgraded} |
|
for i, path in enumerate(character_list): |
|
path_upgraded = character_list_upgraded.get(os.path.basename(path)) |
|
if path_upgraded is not None: |
|
character_list[i] = path_upgraded |
|
animation_list = sorted(glob(os.path.join(input_dir, "animation", "*.fbx"))) |
|
unposed_list_file = "character_unposed.txt" |
|
if os.path.isfile(unposed_list_file): |
|
with open(unposed_list_file, "r") as f: |
|
unposed_list = f.readlines() |
|
unposed_list = [x.strip() for x in unposed_list if x.strip() != ""] |
|
else: |
|
unposed_list = None |
|
logfile = "character_bones.txt" |
|
|
|
bones_name_list = [] |
|
for file in tqdm(character_list, dynamic_ncols=True): |
|
try: |
|
with HiddenPrints(): |
|
remove_all() |
|
obj_list = load_file(file) |
|
armature_obj = get_all_armature_obj(obj_list) |
|
assert len(armature_obj) == 1, "Armature number is not 1" |
|
armature_obj = armature_obj[0] |
|
if unposed_list is None or file in unposed_list: |
|
rename_maxiamo_bone(armature_obj) |
|
rest_bones, bones_idx_dict = get_rest_bones(armature_obj) |
|
|
|
|
|
select_objs(obj_list, deselect_first=True) |
|
bpy.ops.export_scene.fbx( |
|
filepath=os.path.join(output_dir, os.path.basename(file)), |
|
check_existing=False, |
|
use_selection=True, |
|
use_triangles=True, |
|
add_leaf_bones=False, |
|
bake_anim=False, |
|
path_mode="COPY", |
|
embed_textures=keep_texture, |
|
) |
|
bones_name_list += list(bones_idx_dict.keys()) |
|
with open(logfile, "a") as f: |
|
f.write(f"{file}: {len(bones_idx_dict)}\n") |
|
except Exception as e: |
|
|
|
tqdm.write(f"{file}: {e}") |
|
with open(logfile, "a") as f: |
|
f.write(f"{file}: {e}\n") |
|
|
|
|
|
print(sorted(set(bones_name_list))) |
|
|
|
|
|
|
|
with open(logfile, "a") as f: |
|
|
|
for v in sorted(set(bones_name_list)): |
|
f.write(f"{v}: {bones_name_list.count(v)}/{len(character_list)}\n") |
|
|