Blender → UE Skeletal Mesh Rig Transfer¶
Summary: How to take a mesh authored/rigged for one skeleton (e.g. a FAB/marketplace armor set on standard Mannequin) and re-rig it onto a different target skeleton (e.g.
SK_Als) so it deforms correctly via leader pose. Covers the Blender reshape + weight-transfer pass, FBX export settings, and the MCP/Python import flow into Unreal — including the non-obvious traps that will silently break the result.
Table of Contents¶
- When To Use This
- Pipeline Overview
- Stage 1 — Blender: Reshape + Weight Transfer
- Stage 2 — FBX Export
- Stage 3 — Unreal Import
- Critical Gotchas
- Scripts
- Worked Example: Knight Armor → SK_Als
- Source References
- Related Systems
- Recent Changes
When To Use This¶
| Situation | Use this? |
|---|---|
| Mesh rigged to Skeleton A, must deform on Skeleton B (different bone count / rest pose / spine subdivision) | Yes |
| Mesh already on the target skeleton, just needs re-export | No — straight export/import |
| Driving equipment that stays on its own skeleton at runtime | No — use a UE IK Retargeter instead (per-frame cost, no re-rig) |
Equipment that leader-poses off the player body must share the player's exact Skeleton asset — bone names matching is not enough; a different rest pose / bone hierarchy distorts. That is why re-rigging (not retargeting) is the chosen path for fixed body armor. See EquipmentVisualConfig.DeformingMeshes (Source/ProjectEternal/Public/EquipmentManagement/Data/EquipmentVisualConfig.h).
Pipeline Overview¶
BLENDER UNREAL
┌──────────────────────────────┐ ┌───────────────────────────────┐
│ target body mesh + target rig│ │ delete old SK (if reskinning │
│ (weight source, e.g. SKM_Male3)│ │ an existing asset in place) │
└───────────────┬──────────────┘ └───────────────┬───────────────┘
│ align (pose rig to mesh) │ fresh import (NOT reimport)
▼ ▼ force target Skeleton via
┌──────────────────────────────┐ export ┌───────────────────────────────┐
│ 1. reshape armor → rig rest │ ───FBX──▶│ FbxImportUI.skeleton = target │
│ 2. transfer body weights │ │ run on Slate post-tick (async)│
│ 3. bind to target rig │ │ reassign materials by slot │
└──────────────────────────────┘ └───────────────────────────────┘
Key principle: the armor's base mesh must sit in the target skeleton's reference pose, skinned with the body's weights. Everything below serves that.
Stage 1 — Blender: Reshape + Weight Transfer¶
The marketplace mesh is modeled in its source skeleton's rest pose. The target skeleton's rest pose differs, so the mesh must be reshaped before weights are transferred.
| Step | Action | Why |
|---|---|---|
| Prep | Apply Mirror and any generative modifiers; delete dead ones |
Weight transfer + export need final geometry |
| Align | Pose the target rig (Pose Mode, never Edit Mode) so the body overlaps the armor | Surface mapping samples current positions |
| Reshape | Surface Deform on each armor piece → target body; bind while aligned; reset rig to rest → armor follows body into the rest pose; Apply the modifier |
Bakes the armor into the target rest pose, preserving bulk |
| Weights | Data Transfer body → armor: POLYINTERP_NEAREST (Nearest Face Interpolated), by-name, use_object_transform=True |
Maps each armor vertex to nearest body surface; handles unit-scale differences |
| Bind | Point each armor Armature modifier at the target rig |
Deform via target bones |
| Verify | Pose the rig, render (OpenGL render works; screenshot tools hang in this project) | Confirm deformation before export |
Notes: - Pose Mode, not Edit Mode — Edit Mode changes the rest/bind and breaks existing weights. - Weights are per-vertex (pose-independent); only the mapping uses current surface positions, so alignment matters only at transfer time. - A bulky armor over a thin body is fine — Nearest-Face maps regardless of thickness.
Stage 2 — FBX Export¶
Recommended export_scene.fbx settings (UE-friendly):
| Setting | Value |
|---|---|
use_selection |
True (select armature + the meshes for that piece) |
object_types |
{'ARMATURE','MESH'} |
add_leaf_bones |
False |
bake_anim |
False |
primary_bone_axis / secondary_bone_axis |
Y / X |
apply_scale_options |
FBX_SCALE_NONE |
axis_forward / axis_up |
-Z / Y |
The armature OBJECT name becomes the skeleton's root bone in the FBX. Name it exactly what the target skeleton's root bone is called (UE Mannequin/ALS = root). See Critical Gotchas.
Group meshes per target SK asset (one FBX each). A combined-mesh FBX imports as one SK with multiple material slots.
Stage 3 — Unreal Import¶
Import is driven by Python (FbxImportUI), not the MCP native import or the MCP py console directly — both have blocking issues (see gotchas). The flow:
| Step | Detail |
|---|---|
| Capture | Before deleting an existing SK, record its material slot → MaterialInstance mapping |
| Delete | Delete the old SK asset (fresh import is required to set a new skeleton) |
| Import | FbxImportUI.skeleton = <target>, import_materials=False, scheduled on a Slate post-tick callback |
| Materials | Reassign MaterialInterface per slot from the captured mapping |
| Save | EditorAssetLibrary.save_loaded_asset |
References to the SK that are TSoftObjectPtr resolve by path, so delete + fresh-import to the same path relinks automatically — no reference repair needed. Hard (TObjectPtr) refs would need consolidation instead.
Critical Gotchas¶
| Symptom | Cause | Fix |
|---|---|---|
cannot merge bone tree with the existing skeleton / incompatible Skeleton |
FBX skeleton root doesn't match target. The armature object name becomes the root bone — root.036 exports a stray root_036 above the real bones |
Rename the armature object to the target root bone name (root); ensure a single top bone with pelvis/ik_foot_root/ik_hand_root as its children (not 3 separate roots) |
Imported mesh keeps the old skeleton despite setting FbxImportUI.skeleton |
Reimport-in-place ignores the skeleton param — only fresh imports honor it | Delete the asset first, then fresh-import |
Property 'Skeleton' ... is read-only |
SkeletalMesh.skeleton cannot be reassigned from Python |
Must (re)import to change skeleton |
| New skeleton asset created instead of binding to target | MCP native manage_asset import ignores the skeleton param |
Use Python FbxImportUI with skeleton set |
Editor crash: Assertion failed: ++Queue(QueueIndex).RecursionGuard == 1 |
Heavy FBX import run synchronously inside the MCP py console handler → taskgraph re-entrancy |
Defer the import to unreal.register_slate_post_tick_callback (runs on a clean game-thread tick) — see [[reference_ue_async_import_slate_tick]] |
| Armor 100× too small/large vs rig in Blender | Mesh authored in meters, rig at 0.01 (cm) scale; reassigning obj.parent via the data API drops the compensating matrix_parent_inverse |
Set obj.matrix_parent_inverse = rig.matrix_world.inverted() after reparenting |
VB ... virtual bones in the target skeleton |
Engine-side bones; not exported from Blender, not needed in the FBX | Ignore |
MCP py returns no stdout |
Console output isn't captured | unreal.log_warning('TAG ...') and read Saved/Logs/ProjectEternal.log — always read the log after a Python run |
Scripts¶
| Script | Runs in | Purpose |
|---|---|---|
Tools/Blender/skeletal_rig_transfer.py |
Blender | Reshape (Surface Deform), weight transfer, bind, per-group FBX export. Edit the CONFIG block. |
Tools/Python/ue_skeletal_import.py |
Unreal (editor Python / MCP py) |
Async FbxImportUI import forcing a target skeleton + material reassignment. Edit the CONFIG/JOBS block. |
Both are parameterized at the top (collection names, armature name, target skeleton path, FBX↔asset job list). They are skeleton-agnostic — set the target skeleton path for non-ALS rigs.
Worked Example: Knight Armor → SK_Als¶
| Item | Value |
|---|---|
| Target skeleton | /ALS/ALS/Character/SK_Als (the player body SKM_Male3_Rigged uses it) |
| Source skeleton (wrong) | SK_Mannequin — different spine subdivision → distortion |
| SK assets (reimported in place) | SK_Knight_Helm, _Hands, _Feet, _BodyArmor, _Cloak |
| Material slots | M_Knight19_N → MI_Knight_N (1–4); Cloak only slot 4 |
| Consumers | EquipmentVisualConfig (Knight_BodyArmor/Feet/Hands/Helm), via soft refs — auto-relinked |
| Cloak note | Exclude the low-poly cloth proxy; export the real cloak mesh only |
Full session detail (incl. the crash + broken-asset recovery) is in agent memory project_knight_armor_als_rerig.
Source References¶
Scripts¶
| Component | Location |
|---|---|
| Blender reshape + transfer + export | Tools/Blender/skeletal_rig_transfer.py |
| Unreal async force-skeleton import | Tools/Python/ue_skeletal_import.py |
Unreal¶
| Component | Location |
|---|---|
| Equipment mesh refs (leader pose) | Source/ProjectEternal/Public/EquipmentManagement/Data/EquipmentVisualConfig.h |
Related Systems¶
- Blender Room Workflow — the other Blender↔UE pipeline (level rooms / USD)
- Asset Naming & Organization — SK_ / SKM_ / MI_ conventions
- Equipment System — how equipped meshes attach (leader pose)
Recent Changes¶
| Date | Change | Impact |
|---|---|---|
| 2026-05-29 | Initial doc — knight armor re-rig to SK_Als | Establishes repeatable Blender→UE skeletal re-rig flow |