BLENDER_ASSEMBLY_GUIDE.md

pipelines/BLENDER_ASSEMBLY_GUIDE.md

Blender assembly guide — head swap, proportions, photoreal finish

Written 2026-08-13 for Josh doing the 3D assembly manually. Everything here was measured on this

project's own assets during the 2026-08-12/13 sitting, not copied from a tutorial. Where a number

is a measurement it says so; where it is a starting point it says that too.

---

0. What you have coming out of Meshy

A head task and a body task, each ~1.9M triangles, with an 8192 base colour plus metallic,

roughness and normal maps. The body arrives with an adult head Meshy invented — that is

expected, not a failure, and it gets cut off.

Both halves must be cut at the same anatomical ring or they will not meet. That ring is the

neck's narrowest cross-section, and it is the one landmark that exists in every view including the

back of a head.

---

1. Find the neck ring (do this on both meshes)

Do not eyeball it and do not use a fixed height — a constant cuts a 7-year-old through the jaw and

an 18-year-old through the collarbone. The neck is the **narrowest horizontal cross-section between

the jaw and the shoulders**.

In Blender:

1. Select the mesh, N panel → note the Z extent (Dimensions).

2. In Edit Mode, box-select a thin horizontal band at roughly 60–70% of the head-to-shoulder span

and read the X width in the N panel.

3. Move the band down in small steps. The width falls, reaches a minimum, then rises sharply as the

shoulders begin. The minimum is the ring.

4. On this project's ladder that ring measures 0.32–0.38 of the head's maximum width, consistent

across all 28 head views and all 21 body plates. If your band reads much outside that, you are on

the jaw (too high) or the shoulders (too low).

---

2. Cut and weld

1. Body: Ctrl+R a loop cut at the ring, or use Bisect (Edit Mode → Mesh → Bisect) with the

plane at the ring height. Delete everything above it — that removes Meshy's invented adult head.

2. Head: same bisect at its own ring. Keep a collar of neck below the ring rather than

cutting flush; a bust that ends exactly at the seam has nothing to weld with.

3. Align: snap the head's ring centroid to the body's ring centroid (`Shift+S → Cursor to

Selected on one, then Selection to Cursor` on the other). Match rotation before scale.

4. Scale to fit: scale the head uniformly until its ring diameter matches the body's. Uniform

only — non-uniform scaling changes the skull proportions you approved.

5. Join (Ctrl+J), then in Edit Mode select both ring loops and M → Merge by Distance with a

threshold just above the gap. Check the vertex count drops by roughly the loop's vertex count —

if it does not, they did not weld.

6. Close the seam: a Shrinkwrap modifier on the joined band, or F to bridge, then Smooth on

the seam vertices only (not the face).

---

3. Proportions

Meshy returns a mesh at its own scale, and per-rung scale will not agree across the ladder.

then apply scale (Ctrl+A → Scale). Do this before any other proportion work or every later

measurement is in different units.

API). With split parts you scale limbs and torso independently. Without it, select by region and

use proportional editing (O) with Connected falloff.

the failed ladders got wrong — the old set compressed the age range by 40%, which is what made

every rung read like the same person at different sizes.

---

4. Retopo and UVs — the step that decides texel density

Do not put head and body on one atlas. This is arithmetic, not preference:

layouttexel size
one 4096 over a whole ~1.7 m² figure at 0.57 UV utilisation0.42 mm/texel — cannot hold a pore
head alone (~0.09 m²) on its own 40960.095 mm
head alone on 81920.047 mm — roughly one texel per follicle

So: head 8192, body 4096, hair/garment 4096, as separate objects with separate material slots.

Retopo with QuadriFlow (Object → Quad Remesh in Blender 5.x): head 15–25k tris with loops

around eyes and mouth, body 30–50k. Then UV: Smart UV Project with island margin 0.003, or

xatlas if you want tighter packing.

---

5. Bake — this is where photoreal comes from

Bake from the ~1.9M Meshy mesh onto your retopo low-poly. Meshy's own maps are a starting point;

the detail lives in the high-poly.

Settings, each one measured on this project:

proportional cage was 32.6 mm of extrusion, which sends nose-bridge rays into the eyeball and

in-ear rays into the skull. Head: 1.5 mm cage, 3 mm ray. Body: keep the larger cage.

and higher samples cost time for an identical result.

camera pulls back.

narrowed to roughly 0.42–0.58 (pointiness clusters near 0.5; widening it gives you a flat grey

useless map). You need this — it is the mask that makes micro-detail land in creases instead of

uniformly over a mannequin.

THE GREEN CHANNEL — the single most expensive mistake in this project

Blender bakes OpenGL (+Y, green up). Unreal expects DirectX (−Y, green down).

Set Render Properties → Bake → Normal Space: Tangent, and swizzle G to −Y. Measured proof: a

control bake of a plane tilted a known 20° returned green 171/255 — the OpenGL prediction — not 84.

880 normal maps in this project were inverted because of it, and inverted normals read in-engine as

exactly the flat waxy plastic you are trying to escape.

The project rule: every normal map on disk is DirectX. Flip at the bake, never per-consumer.

In UE, leave *Flip Green Channel* off — the file is already correct.

---

6. Micro-detail

Below ~0.40 mm the source carries no signal, so that last octave is authored once and reused,

never inferred per asset. There is a tiling skin normal + cavity pair at

build/3d/shared/skin_microdetail/ — 2048, tiles by construction (measured wrap seam 1.019× the

interior discontinuity), born DirectX.

Blend it in the material masked by the baked curvature, not uniformly. Uniform micro-detail

reads as noise wrapped over a mannequin; masked, it reads as skin. Scale the UVs per subject so the

pore pitch stays physically plausible.

---

7. What MetaHuman is for, and where it enters

MetaHuman is not a look tool — Meshy and TRELLIS own the look, and a MetaHuman face is not better

geometry than a good sculpt. MetaHuman is the rig, LOD and performance layer for humans in UE5,

and that is the only reason it is in the plan:

expression on every human in the game

and you keep everything above

So the division of labour is: your sculpt is the character, MetaHuman is the actor. Without it,

~1,500 named characters each need bespoke rigging and facial animation, which is not a thing one

person does. Creatures never route through it — the topology is human-only.

Where it enters your bench flow: after the head/body weld and the retopo, not before. You hand

Mesh-to-MetaHuman a clean neutral-expression head; it wants topology it can conform to, and the

1.9M raw Meshy mesh is not that.

Three things that are true and worth knowing before you queue a roster behind it:

since UE 5.6, is the surviving route. Build one end-to-end before that date.

throughput at roster scale. At 1,500 characters that is the real unknown — measure it on one.

Pointed ears — a fairy-realm asset, not a roster problem

Only CHAR_0001 and the fairy-realm cast have pointed ears; the fairy realm is his origin world and

appears in the Prologue, Ch 1, and Ch 70-77. Every one of the 76 real-world regions is human-eared.

The route: conform MetaHuman on the human-eared head, then edit the ear vertices on LOD0 in

Blender. The ear is a small, isolated vertex island on a fixed topology, so the skin weights carry

and the face rig is untouched. Sculpt it once, reuse the shape across the whole fairy cast — about

80 rows, not the roster.

---

8. Checks before you call a rung done

python harness/asset_factory/identity_lens.py --ref <approved>.png --probe <render>.png

Render the mesh under lighting matched to the plate first — scoring a clay render on black

against a soft-lit portrait is not a valid comparison and will read low regardless.

Six ratios below the hairline; detector noise floor is 2.27%, so under ~8% is the same skull.

chest, the lost ears, the slab — was caught by eye. Every one of them passed a number first.

Generated by harness/site/structure_site.py — the URL path is the repo path. review root