Skip to content

Latest commit

 

History

History
787 lines (510 loc) · 35.2 KB

File metadata and controls

787 lines (510 loc) · 35.2 KB

RigService

Overview

RigService provides a comprehensive collection of static methods for working with armatures, rigs, bones, bone constraints, poses, and vertex weights. It is the primary service for all skeletal operations in MPFB, handling everything from rig creation and bone manipulation to weight painting and pose management.

The service supports multiple rig types: the MPFB default rig (with and without individual toes), game engine rigs, Rigify metarigs and generated rigs, Mixamo, CMU Motion Builder, OpenPose rigs, and custom rigs saved to the user library. Rig type identification is based on the presence of characteristic bone names, with custom rigs identified via their "identifying_bones" list obtained from AssetService. Custom rigs are reported with a "custom." prefix (e.g., "custom.my_rig"). The service provides weight-loading fallback chains so that weights from compatible rig types can be reused.

RigService also manages armature refitting — the process of adjusting bone positions to match a morphed basemesh — provides bone visualization tools for displaying bones as empties, NURBS paths, or UV spheres, and owns the Rigify generation pipeline via generate_rigify_rig, which is the single implementation shared by every UI path that turns a Rigify meta rig into a generated control rig. All methods are static; the class should never be instantiated.

Source

src/mpfb/services/rigservice.py

Dependencies

Dependency Usage
LogService Logging via LogService.get_logger("services.rigservice")
LocationService Resolving paths to pose files, weight files, and rig definitions
SystemService Checking for Rigify addon availability
TargetService Baking shape keys during rest pose application
ObjectService Object activation, selection, children queries, Rigify detection
SkeletonObjectProperties Reading/writing skeleton custom properties (extra bones)
Rig Rig entity for armature refitting (imported at call time)
GeneralObjectProperties Reading UUID properties for subrig refitting (imported at call time)
ClothesService Finding clothes asset paths for subrig refitting (imported at call time)
AssetService Querying custom rig definitions for identification and refitting (imported at call time)

Rig Type Identifiers

The identify_rig() method returns one of these string identifiers:

Type Description
"default" MPFB default rig with individual toes
"default_no_toes" MPFB default rig without individual toes
"game_engine" Game engine rig (UE-style bone names)
"game_engine_with_breast" Game engine rig with breast bones
"cmu_mb" CMU Motion Builder rig
"mixamo" Mixamo rig
"mixamo_unity" Mixamo rig with Unity naming and breast bones
"openpose" OpenPose rig
"rigify.human" Rigify metarig (human, no toes)
"rigify.human_toes" Rigify metarig (human, with toes)
"rigify_generated.game_engine" Generated Rigify rig from game engine metarig
"rigify_generated.human" Generated Rigify rig (human, no toes)
"rigify_generated.human_toes" Generated Rigify rig (human, with toes)
"rigify.unknown" Rigify metarig of unknown subtype
"rigify_generated.unknown" Generated Rigify rig of unknown subtype
"unknown" Unrecognized rig type
"custom.<name>" A custom rig saved to user data, where <name> is the bare filename (e.g., "custom.my_rig")

Public API

Rig Creation and Setup

create_rig_from_skeleton_info(name, data, parent=None, scale=0.1)

Create a new armature object from a skeleton information dictionary. The data dictionary must contain a "bones" key with hierarchical bone definitions including head/tail positions, optional matrices or roll values, and children. Bones are positioned with Z-up coordinate conversion.

Argument Type Default Description
name str The name for the new armature
data dict Skeleton info dictionary with bone data
parent bpy.types.Object None Optional parent object
scale float 0.1 Scale factor for bone positions

Returns: bpy.types.Object — The created armature object.


ensure_armature_modifier(obj, armature_object, *, move_to_top=True, subrig=None)

Ensure a mesh object has an armature modifier pointing to the given armature. Creates the modifier if it doesn't exist, or updates the target if it does. Also handles preserve-volume modifiers (using mhmask-preserve-volume vertex group) and subrig modifiers (using mhmask-subrig vertex group), ensuring correct modifier stacking order.

Argument Type Default Description
obj bpy.types.Object The mesh object to modify
armature_object bpy.types.Object The armature to link
move_to_top bool True Move the armature modifier to the top of the stack
subrig bpy.types.Object None Optional subrig armature for a secondary modifier

Returns: None


ensure_armature_has_bone_shape_objects_as_children(armature_object)

Ensure the armature has hidden empty objects for bone custom shapes (circle, sphere, arrow) as children. Creates any that are missing.

Argument Type Default Description
armature_object bpy.types.Object The armature to check

Returns: None


normalize_rotation_mode(armature_object, rotation_mode="XYZ")

Set the rotation mode of all pose bones in the armature to the specified mode.

Argument Type Default Description
armature_object bpy.types.Object The armature to normalize
rotation_mode str "XYZ" The Euler rotation order to set

Returns: None


ensure_global_poses_are_available()

Copy built-in MPFB pose files (JSON) from the source data directory to the user data directory if they don't already exist. Creates subdirectories as needed.

Returns: None


Bone Lookup and Activation

find_pose_bone_by_name(name, armature_object)

Find a pose bone by name in the armature's pose bone collection.

Argument Type Default Description
name str The bone name to find
armature_object bpy.types.Object The armature object

Returns: bpy.types.PoseBone or None — The pose bone, or None if not found.


find_edit_bone_by_name(name, armature_object)

Find an edit bone by name. Requires the armature to be in Edit mode.

Argument Type Default Description
name str The bone name to find
armature_object bpy.types.Object The armature object

Returns: bpy.types.EditBone or None — The edit bone, or None if not found.


activate_pose_bone_by_name(name, armature_object, also_select_bone=True, also_deselect_all_other_bones=True)

Activate a specific pose bone, making it the active bone in the armature. Optionally selects the bone and deselects all others.

Argument Type Default Description
name str The bone name to activate
armature_object bpy.types.Object The armature object
also_select_bone bool True Also select the bone
also_deselect_all_other_bones bool True Deselect all other bones first

Returns: bpy.types.PoseBone — The activated pose bone.


get_world_space_location_of_pose_bone(bone_name, armature_object)

Get the head and tail positions of a pose bone in world space by transforming through the armature's world matrix.

Argument Type Default Description
bone_name str The bone name
armature_object bpy.types.Object The armature object

Returns: dict{"head": Vector, "tail": Vector} in world space.


find_pose_bone_tail_world_location(bone_name, armature_object)

Find the world-space location of a pose bone's tail.

Argument Type Default Description
bone_name str The bone name
armature_object bpy.types.Object The armature object

Returns: Vector — The tail position in world space.


find_pose_bone_head_world_location(bone_name, armature_object)

Find the world-space location of a pose bone's head.

Argument Type Default Description
bone_name str The bone name
armature_object bpy.types.Object The armature object

Returns: Vector — The head position in world space.


Bone Constraints

add_bone_constraint_to_pose_bone(bone_name, armature_object, constraint_name)

Add a constraint of the specified type to a pose bone.

Argument Type Default Description
bone_name str The bone to constrain
armature_object bpy.types.Object The armature object
constraint_name str The constraint type (e.g., 'COPY_ROTATION', 'IK')

Returns: bpy.types.Constraint — The created constraint.


remove_all_constraints_from_pose_bone(bone_name, armature_object)

Remove all constraints from a pose bone and reset all IK lock and limit flags.

Argument Type Default Description
bone_name str The bone to clear constraints from
armature_object bpy.types.Object The armature object

Returns: None


add_copy_rotation_constraint_to_pose_bone(bone_to_restrain_name, bone_to_copy_from_name, armature_object, copy_x=True, copy_y=True, copy_z=True)

Add a Copy Rotation constraint to a pose bone. The constraint copies rotation from another bone in the same armature in local space.

Argument Type Default Description
bone_to_restrain_name str The bone to add the constraint to
bone_to_copy_from_name str The bone to copy rotation from
armature_object bpy.types.Object The armature object
copy_x bool True Copy rotation around X axis
copy_y bool True Copy rotation around Y axis
copy_z bool True Copy rotation around Z axis

Returns: bpy.types.Constraint — The created constraint.


add_rotation_constraint_to_pose_bone(bone_name, armature_object, limit_x=False, limit_y=False, limit_z=False)

Add a Limit Rotation constraint to a pose bone in local space.

Argument Type Default Description
bone_name str The bone to constrain
armature_object bpy.types.Object The armature object
limit_x bool False Limit rotation around X axis
limit_y bool False Limit rotation around Y axis
limit_z bool False Limit rotation around Z axis

Returns: bpy.types.Constraint — The created constraint.


add_ik_rotation_lock_to_pose_bone(bone_name, armature_object, lock_x=False, lock_y=False, lock_z=False)

Lock a pose bone's rotation on specified axes during IK solving.

Argument Type Default Description
bone_name str The bone to lock
armature_object bpy.types.Object The armature object
lock_x bool False Lock X axis rotation
lock_y bool False Lock Y axis rotation
lock_z bool False Lock Z axis rotation

Returns: bpy.types.PoseBone — The modified pose bone.


add_ik_constraint_to_pose_bone(bone_name, armature_object, target, chain_length=2)

Add an Inverse Kinematics constraint to a pose bone. The target can be either an external object or a pose bone within the same armature (in which case the armature becomes the target with the bone as subtarget).

Argument Type Default Description
bone_name str The bone to constrain
armature_object bpy.types.Object The armature object
target bpy.types.Object or bpy.types.PoseBone The IK target
chain_length int 2 Number of bones in the IK chain

Returns: bpy.types.Constraint — The created IK constraint.


set_ik_rotation_limits(bone_name, armature_object, axis, min_angle=0, max_angle=0)

Set IK rotation limits for a pose bone on a specified axis. Angles are provided in degrees and converted to radians internally.

Argument Type Default Description
bone_name str The bone to set limits on
armature_object bpy.types.Object The armature object
axis str The axis to limit ("x", "y", or "z")
min_angle float 0 Minimum angle in degrees
max_angle float 0 Maximum angle in degrees

Returns: None


Bone Orientation and Measurement

get_bone_orientation_info_as_dict(armature_object)

Retrieve the orientation information of all bones in an armature, including head/tail positions, matrices, roll, length, and parent names. Collects data from both pose mode and edit mode.

Argument Type Default Description
armature_object bpy.types.Object The armature to analyze

Returns: dict{"pose_bones": {name: {head, tail, matrix}}, "edit_bones": {name: {head, tail, matrix, roll, length, parent}}}.


set_bone_orientation_from_info_in_dict(armature_object, new_bone_orientation)

Set bone orientations from a dictionary (as returned by get_bone_orientation_info_as_dict). Processes bones in parent-to-child order to maintain correct hierarchical positioning.

Argument Type Default Description
armature_object bpy.types.Object The armature to update
new_bone_orientation dict Orientation data dictionary

Returns: None


find_leg_length(armature_object)

Calculate the total length of the right leg bones (upperleg01.R, upperleg02.R, lowerleg01.R, lowerleg02.R). Only implemented for the default rig type.

Argument Type Default Description
armature_object bpy.types.Object The armature to measure

Returns: float — Total leg bone length.

Raises: ValueError if not a default rig or if bones are missing.


find_arm_length(armature_object)

Calculate the total length of the right arm bones (upperarm01.R, upperarm02.R, lowerarm01.R, lowerarm02.R). Only implemented for the default rig type.

Argument Type Default Description
armature_object bpy.types.Object The armature to measure

Returns: float — Total arm bone length.

Raises: ValueError if not a default rig or if bones are missing.


Weight Management

get_weights(armature_objects, basemesh, exclude_weights_below=0.0001, all_groups=False, all_bones=False, all_masks=True)

Create an MHW-compatible weights dictionary from the current vertex group weights on a basemesh. The dictionary includes metadata fields (copyright, description, license, name, version) for compatibility with the MakeHuman weight format.

Argument Type Default Description
armature_objects bpy.types.Object or list The armature(s) to use for bone matching
basemesh bpy.types.Object The mesh to extract weights from
exclude_weights_below float 0.0001 Minimum weight to include
all_groups bool False Include all vertex groups, not just bone-matching ones
all_bones bool False Include all deform bones even without vertex groups
all_masks bool True Include mhmask-* vertex groups

Returns: dict — MHW-format weights dictionary with "weights" key.


load_weights(armature_objects, basemesh, mhw_filename, *, all=False, replace=False)

Load vertex weights from a JSON file and apply them to the basemesh.

Argument Type Default Description
armature_objects bpy.types.Object or list The armature(s) for bone matching
basemesh bpy.types.Object The mesh to apply weights to
mhw_filename str Path to the MHW JSON file
all bool False Load all groups even without matching bones
replace bool False Replace existing weights entirely

Returns: None


apply_weights(armature_objects, basemesh, mhw_dict, *, all=False, replace=False)

Apply weights from a dictionary to the basemesh. Maps weight group names to bones with automatic DEF- prefix fallback and common toe matching. Groups are processed in bone topology order.

Argument Type Default Description
armature_objects list[bpy.types.Object] or bpy.types.Object The armature(s) for bone matching
basemesh bpy.types.Object The mesh to apply weights to
mhw_dict dict MHW-format weights dictionary
all bool False Load all groups even without matching bones
replace bool False Replace existing weights entirely

Returns: None


mirror_bone_weights_to_other_side_bone(armature_object, source_bone_name, target_bone_name)

Mirror vertex weights from a source side bone to the corresponding target side bone.

Argument Type Default Description
armature_object bpy.types.Object The armature containing the bones
source_bone_name str Name of the source bone
target_bone_name str Name of the target bone

Returns: None


mirror_bone_weights_inside_center_bone(armature_object, bone_name, left_to_right=False)

Mirror vertex weights within a center bone (a bone that spans both sides of the mesh).

Argument Type Default Description
armature_object bpy.types.Object The armature containing the bone
bone_name str Name of the center bone
left_to_right bool False If True, mirror from left to right

Returns: None


symmetrize_all_bone_weights(armature_object, left_to_right=False, rig_type=None)

Symmetrize all bone weights across the rig. Identifies side bones by their suffix (e.g., .L / .R) and mirrors weights from the source side to the destination side. Center bones are mirrored internally.

Argument Type Default Description
armature_object bpy.types.Object The armature to symmetrize
left_to_right bool False If True, mirror from left to right
rig_type str None Rig type for suffix detection (auto-detected if None)

Returns: None


Extra Bones / Rigify

set_extra_bones(armature_object, extra_bones)

Store a list of extra bone names as a custom property on the armature. Used to track bones that will be generated by Rigify but don't exist in the metarig.

Argument Type Default Description
armature_object bpy.types.Object The armature to set the property on
extra_bones list[str] or None List of bone names, or None to remove the property

Returns: None


get_extra_bones(armature_object)

Retrieve the list of extra bone names stored on the armature's custom properties.

Argument Type Default Description
armature_object bpy.types.Object The armature to query

Returns: list[str] — List of extra bone names (empty list if not set).


get_deform_group_bones(armature_object)

Get all bones that should have vertex groups: bones marked use_deform plus any extra bones from find_extra_bones.

Argument Type Default Description
armature_object bpy.types.Object The armature to query

Returns: list[str] — List of deform group bone names.


find_extra_bones(armature_object)

Identify deform bones that will be generated by Rigify but are not present in the metarig. Compares the metarig's deform bones against the generated rig's DEF- prefixed bones. Falls back to stored extra bones if no generated rig exists.

Argument Type Default Description
armature_object bpy.types.Object The metarig to analyze

Returns: list[str] or None — Sorted list of extra bone names, or None.


generate_rigify_rig(meta_rig, *, name="", meta_rig_action="hide")

Run Rigify generation on a meta rig and return the generated control rig. This helper is the single implementation shared by the UI operator mpfb.generate_rigify_rig, the auto-generate path in mpfb.add_rigify_rig, and the post-deserialize auto-generate path in mpfb.human_from_presets.

The caller is responsible for verifying that meta_rig is a Rigify meta rig (typically via RigService.identify_rig(), which should return a value starting with "rigify.") and that the Rigify addon is enabled (typically via SystemService.check_for_rigify()). As a final gate the helper additionally calls rigify.utils.rig.is_valid_metarig; if Rigify itself considers the meta rig invalid the helper returns None without running pose.rigify_generate, so the caller can emit a {'WARNING'} of its own. The import of is_valid_metarig is guarded so MPFB still loads cleanly when Rigify is not enabled.

The helper handles renaming a .rig-suffixed meta rig back to .metarig, applying the optional name as rigify_rig_basename, the legacy issue-#17 basename workaround, selecting the meta rig and switching to object mode, running pose.rigify_upgrade_face when available, calling pose.rigify_generate (which will update the existing rig in place when meta_rig.data.rigify_target_rig is already set), re-parenting the resulting rig to match the meta rig's parent, calling RigifyHelpers.adjust_children_for_rigify, copying object_type onto the rigify rig via GeneralObjectProperties, applying the requested meta_rig_action, and leaving the generated rig active in object mode.

meta_rig_action controls what happens to the meta rig after generation:

Value Behaviour
"keep" Leave the meta rig untouched.
"hide" (default) Keep the meta rig in the scene but set hide_viewport = True and hide_render = True. Preserves Rigify's in-place re-generation target while keeping the outliner uncluttered.
"delete" Remove the meta rig from bpy.data.objects. In-place re-generation is no longer possible after this.
Argument Type Default Description
meta_rig bpy.types.Object The Rigify meta rig armature
name str "" Optional basename for the generated rig
meta_rig_action str "hide" What to do with the meta rig after generation: "keep", "hide", or "delete". Unknown values fall back to "hide" with a warning.

Returns: bpy.types.Object or None — The generated (or in-place updated) rigify rig, or None if is_valid_metarig rejected the meta rig.


Rig Identification

identify_rig(armature_object)

Identify the rig type by checking for characteristic bone names. Uses a prioritized matching table where later matches override earlier ones. Falls back to Rigify detection and Mixamo name pattern matching. If the rig still cannot be identified as a built-in type, it queries AssetService.get_custom_rigs() and checks whether all bones listed in each custom rig's "identifying_bones" are present in the armature. The first matching custom rig wins and is returned as "custom.<name>". Built-in rigs always take precedence over custom rigs.

Argument Type Default Description
armature_object bpy.types.Object The armature to identify

Returns: str — One of the rig type identifiers (see Rig Type Identifiers section), including "custom.<name>" for user-defined rigs.


infer_metarig_type_from_generated(rigify_object)

Infer the corresponding rigify meta-rig type for a generated rigify rig. This is the inverse of the rigify_generated.* rows in identify_rig and is used when a generated rigify rig must be serialized back to a meta-rig type string — for example when saving a character whose only remaining rig is a generated one. The caller is responsible for verifying that the input is in fact a generated rigify rig, typically via ObjectService.object_is_generated_rigify_rig.

Bones present on the generated rig Returns
ORG-brow.T.R.002 AND ORG-toe2-1.L "rigify.human_toes"
ORG-brow.T.R.002 (no toes marker) "rigify.human"
anything else None
Argument Type Default Description
rigify_object bpy.types.Object The generated rigify rig armature

Returns: str or None — A "rigify.<variant>" meta-rig type string, or None if no signature matches. Callers should fall back to a sensible default and emit a warning when None is returned.


get_rig_weight_fallbacks(rig_type)

Get an ordered list of rig types to try when loading weights. Provides fallbacks so that compatible weight files can be used across similar rig types (e.g., toes vs. no-toes variants).

Argument Type Default Description
rig_type str The primary rig type

Returns: list[str] — Ordered list of rig types to try.


Pose Management

set_pose_from_dict(armature_object, pose, from_rest_pose=True)

Apply a pose from a dictionary of bone rotations and translations. For the default rig, translations are scaled based on the ratio between the current spine/shoulder dimensions and the original dimensions stored in the pose. If from_rest_pose is True, all bones are cleared to rest pose first.

Rotation handling is mode-aware: each bone's rotation_mode is set from pose["bone_rotation_modes"][name] (or inferred from the array length when the legacy format omits the modes map — 4 floats → "QUATERNION", 3 floats → "XYZ"), then the rotation is written to the matching attribute (rotation_quaternion, rotation_axis_angle, or rotation_euler). This is what makes the function work on generated Rigify rigs, where many control bones default to quaternion mode.

Argument Type Default Description
armature_object bpy.types.Object The armature to pose
pose dict Pose dictionary with bone_rotations, bone_translations, skeleton_type and optionally bone_rotation_modes
from_rest_pose bool True Clear to rest pose before applying

Returns: None


get_pose_as_dict(armature_object, root_bone_translation=True, ik_bone_translation=True, fk_bone_translation=False, onlyselected=False)

Serialize the current pose to a dictionary. Includes bone rotations, selected bone translations, rig type, and spine/shoulder measurements for proportional retargeting. Each bone's rotation is captured in its native representation (3-element euler, 4-element quaternion, or 4-element axis-angle), and the per-bone rotation mode is recorded under bone_rotation_modes. Bones whose rotation is effectively identity are omitted.

Argument Type Default Description
armature_object bpy.types.Object The armature to read
root_bone_translation bool True Include root bone translation
ik_bone_translation bool True Include IK bone translations
fk_bone_translation bool False Include FK bone translations
onlyselected bool False Only include selected bones

Returns: dict — Pose dictionary.


apply_pose_as_rest_pose(armature_object)

Apply the current pose as the new rest pose. For each child mesh: bakes shape keys on basemeshes, applies armature modifiers, applies the pose as rest pose, then recreates armature modifiers.

Argument Type Default Description
armature_object bpy.types.Object The armature to apply

Returns: None


copy_pose(from_armature, to_armature, only_rotation=True)

Copy the pose from one armature to another by matching bone names. By default only copies rotations, but can also copy translations and scales.

Argument Type Default Description
from_armature bpy.types.Object Source armature
to_armature bpy.types.Object Target armature
only_rotation bool True If True, only copy rotations; if False, also copy translations and scales

Returns: None


Rig Refitting

refit_existing_armature(armature_object, basemesh)

Refit an armature to a new basemesh shape. For Rigify generated rigs, automatically finds and refits the metarig instead, then regenerates. For custom rigs (identified by "custom." prefix), looks up the rig JSON file via AssetService.get_custom_rigs() and calls the internal refit helper directly. Uses rig JSON definition files to determine bone-to-vertex mappings.

Raises ValueError("Cannot refit a generated rigify rig") when the input is a generated rigify rig and no meta rig is present in the scene; reconstructing the meta rig in that case is more invasive than is justified, so the user-visible remedy is to enable "Keep meta rig" before generating. Callers — for instance HumanService.refit, which accepts an operator keyword for exactly this purpose — should catch the ValueError and surface it as an operator-level {'ERROR'} report rather than letting it propagate.

Argument Type Default Description
armature_object bpy.types.Object The armature to refit
basemesh bpy.types.Object The target basemesh

Returns: None

Raises: ValueError if the rig type cannot be identified, if it's a generated Rigify rig (should refit the metarig instead), or if the custom rig is no longer present in user data.


refit_existing_subrig(armature_object, parent_rig)

Refit a subrig (secondary armature for clothes/accessories) to match its parent rig. Finds the associated asset mesh and uses the .mpfbskel file alongside the asset for bone positioning.

Argument Type Default Description
armature_object bpy.types.Object The subrig to refit
parent_rig bpy.types.Object The parent rig to fit to

Returns: None

Raises: ValueError if the asset mesh or asset file cannot be found.


Bone Visualization

display_pose_bone_as_empty(armature_object, bone_name, empty_type="SPHERE", scale=1.0)

Set a pose bone's custom shape to an empty object. Ensures the required bone shape empty objects (circle, sphere, arrow) exist as children of the armature.

Argument Type Default Description
armature_object bpy.types.Object The armature
bone_name str The bone to display
empty_type str "SPHERE" Type of empty ("SPHERE", "CIRCLE", "SINGLE_ARROW")
scale float 1.0 Scale factor for the custom shape

Returns: None


add_path_object_to_bone(armature_object, bone_name, bevel_depth=0.015)

Create a NURBS path object parented to a bone. The path runs from the bone's head to its tail with a bevel for visual thickness. Useful for bone visualization and debugging.

Argument Type Default Description
armature_object bpy.types.Object The armature
bone_name str The bone to attach the path to
bevel_depth float 0.015 Bevel depth for the NURBS path

Returns: bpy.types.Object — The created NURBS path object.

Raises: ValueError if the bone is not found.


add_uv_sphere_object_to_bone(armature_object, bone_name, sphere_scale=0.01, tail_rather_than_head=False)

Create a UV sphere object parented to a bone at its head or tail position. Useful for visualizing joint positions.

Argument Type Default Description
armature_object bpy.types.Object The armature
bone_name str The bone to attach the sphere to
sphere_scale float 0.01 Scale of the UV sphere
tail_rather_than_head bool False Place at tail instead of head

Returns: bpy.types.Object — The created sphere object.

Raises: ValueError if the bone is not found.


Examples

Creating and Setting Up a Rig

from mpfb.services.rigservice import RigService

# Create a rig from skeleton data
armature = RigService.create_rig_from_skeleton_info(
    "MyRig", skeleton_data, parent=basemesh, scale=0.1
)

# Add armature modifier to the basemesh
RigService.ensure_armature_modifier(basemesh, armature)

# Identify the rig type
rig_type = RigService.identify_rig(armature)
print(f"Rig type: {rig_type}")

Working with Poses

from mpfb.services.rigservice import RigService
import json

# Ensure built-in poses are available
RigService.ensure_global_poses_are_available()

# Save the current pose
pose = RigService.get_pose_as_dict(armature)
with open("/path/to/pose.json", "w") as f:
    json.dump(pose, f)

# Load and apply a pose
with open("/path/to/pose.json", "r") as f:
    saved_pose = json.load(f)
RigService.set_pose_from_dict(armature, saved_pose)

# Copy pose between armatures
RigService.copy_pose(source_armature, target_armature, only_rotation=True)

Managing Weights

from mpfb.services.rigservice import RigService

# Extract weights from current setup
weights = RigService.get_weights(armature, basemesh)

# Save weights to file
import json
with open("/path/to/weights.json", "w") as f:
    json.dump(weights, f)

# Load weights from file
RigService.load_weights(armature, basemesh, "/path/to/weights.json")

# Get the weight loading fallback chain for a rig type
fallbacks = RigService.get_rig_weight_fallbacks("default_no_toes")
# Returns: ["default_no_toes", "default"]