0
$\begingroup$

I'm making animations based on smpl armature through several pose data. Divide people through person id and put pose data in the armature. However, person id 2 data is contained in all armatures and the rest of the pose data is ignored. Is there a way to solve it by looking at the code?

def setup_scene(model_path, fps_target, person_ids):
    scene = bpy.data.scenes['Scene']

    # Set up a dictionary to keep track of armature objects for each person_id
    armatures = {}

    ###########################
    # Engine independent setup
    ###########################

    scene.render.fps = fps_target

    # Remove default cube
    if 'Cube' in bpy.data.objects:
        bpy.data.objects['Cube'].select_set(True)
        bpy.ops.object.delete()

    # Import gender specific .fbx template file
    for person_id in range(person_ids):
        # Append a unique identifier to the armature name based on person_id
        armature_name = f'Armature_{person_id}'
        bpy.ops.import_scene.fbx(filepath=model_path)
        
        # Rename the imported armature object
        armature = bpy.data.objects['Armature']
        armature.name = armature_name
        armatures[person_id] = armature
        armature.location = Vector((0, 0, person_id * 2))
    # Now, armatures is a dictionary where keys are person_ids and values are corresponding armature objects
    return armatures

def process_pose(current_frame, pose, trans, person_id_, armature):

    

    mat_rots = [Rodrigues(rod_rot) for rod_rot in pose]
    
    
    
    print(f"Processing pose for person_id {person_id_} at frame {current_frame}")
        
    bones = armature.pose.bones
    bones[bone_name_from_index[0]].location = Vector((100 * trans[1], 100 * trans[2], 100 * trans[0])) #- pelvis_position

    bones['f_avg_root'].location = Vector(trans)
    bones[bone_name_from_index[0]].keyframe_insert('location', frame=current_frame)

    for index, mat_rot in enumerate(mat_rots, 0):
        if index >= 24:
            continue

        bone = bones[bone_name_from_index[index]]

        bone_rotation = Matrix(mat_rot).to_quaternion()
        quat_x_90_cw = Quaternion((1.0, 0.0, 0.0), radians(-90))
        quat_x_n135_cw = Quaternion((1.0, 0.0, 0.0), radians(-135))
        quat_x_p45_cw = Quaternion((1.0, 0.0, 0.0), radians(45))
        quat_y_90_cw = Quaternion((0.0, 1.0, 0.0), radians(-90))
        quat_z_90_cw = Quaternion((0.0, 0.0, 1.0), radians(-90))
        quat_z_180_cw = Quaternion((0.0, 0.0, 1.0), radians(-180))

        if index == 0:
            # Rotate pelvis so that avatar stands upright and looks along negative Y avis
            # bone.rotation_quaternion = bone_rotation
            bone.rotation_quaternion = (quat_x_90_cw @ quat_z_180_cw) @ bone_rotation
        else:
            bone.rotation_quaternion = bone_rotation

        bone.keyframe_insert('rotation_quaternion', frame=current_frame)

    return
    
    

    

    
    
    


def process_poses(
        input_path,
        gender,
        fps_source,
        fps_target,
        start_origin,
        person_id=1,
):
    
print('Processing: ' + input_path)

    file_data = np.load(input_path, allow_pickle=True)

    body_pose = file_data['smpl'][()]['body_pose']
    global_orient = file_data['smpl'][()]['global_orient'].reshape(-1, 1, 3)
    pred_cams = file_data['pred_cams'].reshape(-1, 3)
    person_ids = file_data['person_id']
    # keypoints_3d = file_data['keypoints_3d'][()]

    poses = []
    poses1 = []
    poses2 =[]
    trans = []
    # for i in range(body_pose.shape[0]):
    #     if person_ids[i] == 1:
    #         poses1.append(np.concatenate([global_orient[i], body_pose[i]], axis=0))
    #     elif person_ids[i] == 2:
    #         poses2.append(np.concatenate([global_orient[i], body_pose[i]], axis=0))
    #     else:
    #         poses.append(np.concatenate([global_orient[i], body_pose[i]], axis=0))
    for i in range(body_pose.shape[0]):
        poses.append(np.concatenate([global_orient[i], body_pose[i]], axis=0))
    #     #trans.append((keypoints_3d[i][8] + keypoints_3d[i][11])/2 * 5)
        trans.append(pred_cams[i])

    poses = np.array(poses)
    poses1 = np.array(poses1)
    poses2 = np.array(poses2)
    trans = np.array(trans)

    # trans = np.zeros((poses.shape[0], 3))

    if gender == 'female':
        model_path = female_model_path
        for k, v in bone_name_from_index.items():
            bone_name_from_index[k] = 'f_avg_' + v
           
    elif gender == 'male':
        model_path = male_model_path
        for k, v in bone_name_from_index.items():
            bone_name_from_index[k] = 'm_avg_' + v
            
    else:
        print('ERROR: Unsupported gender: ' + gender)
        sys.exit(1)

    # Limit target fps to source fps
    if fps_target > fps_source:
        fps_target = fps_source

    print(f'Gender: {gender}')
    print(f'Number of source poses: {str(poses.shape[0])}')
    print(f'Source frames-per-second: {str(fps_source)}')
    print(f'Target frames-per-second: {str(fps_target)}')
    print('--------------------------------------------------')

    armatures = setup_scene(model_path, fps_target, max(set(person_ids)) + 1)

    scene = bpy.data.scenes['Scene']
    sample_rate = int(fps_source / fps_target)
    scene.frame_end = (int)(poses.shape[0] / sample_rate)

    # Retrieve pelvis world position.
    # Unit is [cm] due to Armature scaling.
    # Need to make copy since reference will change when bone location is modified.
    bpy.ops.object.mode_set(mode='EDIT')
    #pelvis_position = Vector(bpy.data.armatures[0].edit_bones[bone_name_from_index[0]].head)
    bpy.ops.object.mode_set(mode='OBJECT')

    source_index = 0
    frame = 1
    
    offset = np.array([0.0, 0.0, 0.0])

    while source_index < poses.shape[0]:
        print('Adding pose: ' + str(source_index))

        if start_origin:
            if source_index == 0:
                offset = np.array([trans[source_index][0], trans[source_index][1], 0])
        
    # Go to new frame
        scene.frame_set(frame)
        if person_ids[source_index] == 6:
            source_index += sample_rate
            frame += 1
            continue
        
        armature = armatures[person_ids[source_index]]
        
            
        process_pose(frame, poses[source_index], (trans[source_index] - offset), person_ids[source_index],armature)
        source_index += sample_rate
        frame += 1
                
             
    return frame
               
            


def export_animated_mesh(output_path):
    # Create output directory if needed
    output_dir = os.path.dirname(output_path)
    if not os.path.isdir(output_dir):
        os.makedirs(output_dir, exist_ok=True)

    # Select only skinned mesh and rig
    bpy.ops.object.select_all(action='DESELECT')
    bpy.data.objects['Armature_0'].select_set(True)
    bpy.data.objects['Armature_0'].children[0].select_set(True)
    bpy.data.objects['Armature_1'].select_set(True)
    bpy.data.objects['Armature_1'].children[0].select_set(True)
    bpy.data.objects['Armature_2'].select_set(True)
    bpy.data.objects['Armature_2'].children[0].select_set(True)
    bpy.data.objects['Armature_4'].select_set(True)
    bpy.data.objects['Armature_4'].children[0].select_set(True)
    

    if output_path.endswith('.glb'):
        print('Exporting to glTF binary (.glb)')
        # Currently exporting without shape/pose shapes for smaller file sizes
        bpy.ops.export_scene.gltf(filepath=output_path, export_format='GLB', export_selected=True, export_morph=False)
    elif output_path.endswith('.fbx'):
        print('Exporting to FBX binary (.fbx)')
        bpy.ops.export_scene.fbx(filepath=output_path, use_selection=True, add_leaf_bones=False)
    else:
        print('ERROR: Unsupported export format: ' + output_path)
        sys.exit(1)

    return


if __name__ == '__main__':
    try:

        input_path = 'demo_result/inference_result_multi10.npz'
        output_path = 'test_trans6.fbx'
        fps_source = 30
        fps_target = 30
        gender = 'female'
        start_origin = 1
        person_id = 0

        startTime = time.perf_counter()

        
        cwd = os.getcwd()

        
        if not input_path.startswith(os.path.sep):
            input_path = os.path.join(cwd, input_path)

        if not output_path.startswith(os.path.sep):
            output_path = os.path.join(cwd, output_path)

        print('Input path: ' + input_path)
        print('Output path: ' + output_path)

        if not (output_path.endswith('.fbx') or output_path.endswith('.glb')):
            print('ERROR: Invalid output format (must be .fbx or .glb)')
            sys.exit(1)

        
        if input_path.endswith('.npz'):
            if not os.path.isfile(input_path):
                print('ERROR: Invalid input file')
                sys.exit(1)

            poses_processed = process_poses(
                input_path=input_path,
                gender=gender,
                fps_source=fps_source,
                fps_target=fps_target,
                start_origin=start_origin,
                person_id=person_id
            )
            export_animated_mesh(output_path)

        print('--------------------------------------------------')
        print('Animation export finished.')
        print(f'Poses processed: {str(poses_processed)}')
        print(f'Processing time : {time.perf_counter() - startTime:.2f} s')
        print('--------------------------------------------------')
        sys.exit(0)

    except SystemExit as ex:
        if ex.code is None:
            exit_status = 0
        else:
            exit_status = ex.code

        print('Exiting. Exit status: ' + str(exit_status))

        
        if bpy.app.background:
            sys.exit(exit_status)
$\endgroup$
1
  • $\begingroup$ Hello and welcome. Your question is vague and it's not really clear that the problem is. What do you mean by "However, person id 2 data is contained in all armatures and the rest of the pose data is ignored."? I don't understand the sentence (could be me). What is "person id 2 data"? And should the rest of the pose data be ignored or not? $\endgroup$
    – Blunder
    Commented Jan 14 at 17:22

0

You must log in to answer this question.

Browse other questions tagged .