Goal
Hero characters that deform well up close. Linear blend skinning in the vertex shader, the engine's only path today, collapses at twisted wrists and loses volume at bent elbows (the "candy wrapper" artefact), and it runs again in every pass that draws the mesh: G-buffer, three shadow cascades, transparency, wireframe. On a headset where the character stands a metre from the eyes, both show.
The goal is a compute deformation stage that skins position, normal and tangent streams once per frame into buffers every pass binds, so shadows, picking and wireframe all see the same geometry, with three skinning modes selectable per entity: linear blend for crowds, dual quaternion for limbs, Direct Delta Mush for the closest characters, baked in the background and falling back to linear blend until ready. On top of it, blend shapes: shape keys authored in Blender, exported as sparse float16 deltas in forward-compatible .untold chunks, and applied ahead of skinning so morphs compose with every mode, with pose-space drivers exported for a later runtime. Entities that do not opt in keep the vertex-shader path byte for byte.
Status
| Step |
Plan |
Status |
| Binding helpers |
Shared per-mesh vertex-stream binding across the model and shadow passes |
Merged (#1130) |
| Deformation pass |
DeformationComponent, deformSkinLBS kernel, deformation graph node ahead of shadows, setEntityDeformation / removeEntityDeformation, CPU parity test |
Ready, PR pending |
| DQS and DDM |
SkinningMode: dual quaternions built on the GPU each frame; Direct Delta Mush baked in the background (LBS until the bake lands); GPU tests |
Ready, PR pending |
| Morph targets |
Three .untold chunks (targets, sparse float16 deltas, pose-space drivers), Blender --export-shapekeys, MorphTargetSet accumulating the strongest 16 weights, setEntityMorphTargetWeight; format docs |
Ready, PR pending |
| Guide |
docs/API page: which mode to pick, DDM bake latency, the exporter flag |
Not started |
| Pose-space deformation |
Drive morph weights from the exported driver records |
Not started |
| Visibility gate |
Skip the dispatch for entities off screen (perf candidate C5) |
Not started |
| Demo |
CoolMirror switches modes and morphs live |
Ready, PR pending (untoldengine/UntoldArcade#31) |
Next steps
- Three pull requests in order: deformation pass, DQS + DDM, morph targets.
- Guide with the first PR; pose-space drivers when a character needs them.
Goal
Hero characters that deform well up close. Linear blend skinning in the vertex shader, the engine's only path today, collapses at twisted wrists and loses volume at bent elbows (the "candy wrapper" artefact), and it runs again in every pass that draws the mesh: G-buffer, three shadow cascades, transparency, wireframe. On a headset where the character stands a metre from the eyes, both show.
The goal is a compute deformation stage that skins position, normal and tangent streams once per frame into buffers every pass binds, so shadows, picking and wireframe all see the same geometry, with three skinning modes selectable per entity: linear blend for crowds, dual quaternion for limbs, Direct Delta Mush for the closest characters, baked in the background and falling back to linear blend until ready. On top of it, blend shapes: shape keys authored in Blender, exported as sparse float16 deltas in forward-compatible
.untoldchunks, and applied ahead of skinning so morphs compose with every mode, with pose-space drivers exported for a later runtime. Entities that do not opt in keep the vertex-shader path byte for byte.Status
DeformationComponent,deformSkinLBSkernel,deformationgraph node ahead of shadows,setEntityDeformation/removeEntityDeformation, CPU parity testSkinningMode: dual quaternions built on the GPU each frame; Direct Delta Mush baked in the background (LBS until the bake lands); GPU tests.untoldchunks (targets, sparse float16 deltas, pose-space drivers), Blender--export-shapekeys,MorphTargetSetaccumulating the strongest 16 weights,setEntityMorphTargetWeight; format docsdocs/APIpage: which mode to pick, DDM bake latency, the exporter flagNext steps