import bpy, random import os import sys import pdb import math from mathutils import Vector def gc(): for i in range(10): bpy.ops.outliner.orphans_purge() def clear(): [bpy.data.objects.remove(bpy.data.objects[x]) for x in list(bpy.data.objects.keys())] gc() def importVrm(importVrmPath): old_objs = set(bpy.context.scene.objects) result = bpy.ops.import_scene.vrm(filepath=importVrmPath) return [x for x in set(bpy.context.scene.objects)-old_objs if x.type=="ARMATURE"][0] def importFbx(importFbxPath): old_objs = set(bpy.context.scene.objects) result = bpy.ops.import_scene.fbx(filepath=importFbxPath) return list(set(bpy.context.scene.objects)-old_objs)[0] def get_keyframes(obj_list): keyframes = [] for obj in obj_list: anim = obj.animation_data if anim is not None and anim.action is not None: for fcu in anim.action.fcurves: for keyframe in fcu.keyframe_points: x, y = keyframe.co if x not in keyframes: keyframes.append(int(x)) return keyframes def retarget(source_armature,target_armature): bpy.context.view_layer.objects.active = source_armature bpy.context.scene.source_rig=source_armature.name bpy.context.scene.target_rig=target_armature.name bpy.ops.arp.build_bones_list() bpy.ops.arp.import_config(filepath=os.path.abspath("remap_mixamo.bmap")) bpy.ops.arp.auto_scale() keyframes=get_keyframes([source_armature]) bpy.ops.arp.retarget(frame_end=int(max(keyframes))) def look_at(obj_camera, point): direction = point - obj_camera.location rot_quat = direction.to_track_quat('-Z', 'Y') obj_camera.rotation_euler = rot_quat.to_euler() def render_4_views(folder, origin = (0, 0, 0)): bpy.context.scene.render.film_transparent = True bpy.context.scene.render.resolution_x = 768 bpy.context.scene.render.resolution_y = 768 camera_positions = { 'front': (0, -2.5, 0.5), 'back': (0, 2.5, 0.5), 'left': (-2.5, 0, 0.5), 'right': (2.5, 0, 0.5), } camera_data = bpy.data.cameras.new(name='MyCamera') camera_data.angle = math.radians(40) camera_object = bpy.data.objects.new('MyCamera', camera_data) bpy.context.collection.objects.link(camera_object) bpy.context.scene.camera = camera_object camera = bpy.data.objects['MyCamera'] for angle, position in camera_positions.items(): camera.location = Vector(position) + Vector(origin) look_at(camera, Vector(origin)) bpy.context.scene.render.filepath = f'{folder}/{angle}.png' bpy.ops.render.render(write_still=True) def changeApose(armature): bones = armature.pose.bones if "J_Bip_L_UpperArm" in bones: L_arm_name = "J_Bip_L_UpperArm" R_arm_name = "J_Bip_R_UpperArm" L_leg_name = "J_Bip_L_UpperLeg" R_leg_name = "J_Bip_R_UpperLeg" elif "腕上_L.002" in bones: L_arm_name = "腕上_L.002" R_arm_name = "腕上_R.002" L_leg_name = "太もも_L.001" R_leg_name = "太もも_R.001" elif "Left arm" in bones: L_arm_name = "Left arm" R_arm_name = "Right arm" L_leg_name = "Left leg" R_leg_name = "Right leg" elif "upper_arm.L" in bones: L_arm_name = "upper_arm.L" R_arm_name = "upper_arm.R" L_leg_name = "upper_leg.L" R_leg_name = "upper_leg.R" elif "LeftArm" in bones: L_arm_name = "LeftArm" R_arm_name = "RightArm" L_leg_name = "LeftUpLeg" R_leg_name = "RightUpLeg" elif "Arm_L" in bones: L_arm_name = "Arm_L" R_arm_name = "Arm_R" L_leg_name = "UpLeg_L" R_leg_name = "UpLeg_R" elif "mixamorig:LeftArm" in bones: L_arm_name = "mixamorig:LeftArm" R_arm_name = "mixamorig:RightArm" L_leg_name = "mixamorig:LeftUpLeg" R_leg_name = "mixamorig:RightUpLeg" elif "UpperArm_L" in bones: L_arm_name = "UpperArm_L" R_arm_name = "UpperArm_R" L_leg_name = "UpperLeg_L" R_leg_name = "UpperLeg_R" else: import pdb; pdb.set_trace() if L_arm_name in bones: bones[L_arm_name].rotation_mode = "XYZ" bones[L_arm_name].rotation_euler = (-math.pi / 4, 0.0, 0.0) bones[L_arm_name].keyframe_insert(data_path="rotation_euler",frame=0) if R_arm_name in bones: bones[R_arm_name].rotation_mode = "XYZ" bones[R_arm_name].rotation_euler = (-math.pi / 4, 0.0, 0.0) bones[R_arm_name].keyframe_insert(data_path="rotation_euler",frame=0) if L_leg_name in bones: bones[L_leg_name].rotation_mode = "XYZ" bones[L_leg_name].rotation_euler = (-math.pi / 30, 0.0, 0.0) bones[L_leg_name].keyframe_insert(data_path="rotation_euler",frame=0) if R_leg_name in bones: bones[R_leg_name].rotation_mode = "XYZ" bones[R_leg_name].rotation_euler = (-math.pi / 30, 0.0, 0.0) bones[R_leg_name].keyframe_insert(data_path="rotation_euler",frame=0) def move_origin_to_center(obj): local_bbox_center = 0.125 * sum((Vector(b) for b in obj.bound_box), Vector()) scale_factor = max(obj.dimensions) return local_bbox_center #print(local_bbox_center) #local_bbox_center = 0.125 * sum((Vector(b) for b in obj.bound_box), Vector()) #global_bbox_center = obj.matrix_world @ local_bbox_center # for cur_obj in bpy.context.scene.objects: # if cur_obj.type != "MESH": # continue # print(cur_obj.name, cur_obj.type) # import pdb; pdb.set_trace() # global_bbox_center = local_bbox_center @ cur_obj.matrix_world # cur_obj.location -= global_bbox_center #cur_obj.scale /= scale_factor #obj.scale /= max(obj.dimensions) # # bpy.ops.object.select_all(action='DESELECT') # # cur_obj.select_set(True) # # bpy.context.view_layer.objects.active = cur_obj # # bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='BOUNDS') def export(armature,exportFileNamePattern,apose=False,origin=None): bpy.ops.object.select_all(action='DESELECT') [x.select_set(True) for x in armature.children if(x.type=="MESH")] if apose: changeApose(armature) os.makedirs(folder + "/apose",exist_ok=True) bpy.ops.wm.obj_export(filepath=folder + "/apose.obj",export_animation=True,start_frame=0,end_frame=0, export_selected_objects=True,export_materials=False,export_colors=False,export_uv=False,export_normals=False) render_4_views(folder + "/apose", origin) else: keyframes = get_keyframes([armature]) #rand_frame = int(random.choice(keyframes)) os.makedirs(folder + "/pose",exist_ok=True) bpy.ops.wm.obj_export(filepath=folder + "/pose.obj",export_animation=True,start_frame=0,end_frame=0, export_selected_objects=True,export_materials=False,export_colors=False,export_uv=False,export_normals=False) render_4_views(folder + "/pose", origin) def exportAnimatedMesh(importVrmPath,importFbxPath,folder,apose): clear() human=importVrm(importVrmPath) # resize human if apose: origin = move_origin_to_center(human) export(human, folder, True, origin) else: anim = importFbx(importFbxPath) retarget(anim, human) origin = move_origin_to_center(human) export(human, folder, False, origin) #bpy.data.objects.remove(anim) #gc() #bpy.data.objects.remove(human) #gc() if(__name__=="__main__"): argv = sys.argv if("--" in argv): argv = argv[argv.index("--") + 1:] importVrmPath, importFbxPath, folder, apose=argv else: raise Exception("no args") print("importVrmPath:", importVrmPath) exportAnimatedMesh(importVrmPath, importFbxPath, folder, int(apose))