Skip to content

CC5 avatar editor, cc5-shape crate and CC5 shader materials - #1

Open
matbeedotcom wants to merge 59 commits into
mainfrom
feat/cc5-avatar-editor
Open

matbeedotcom wants to merge 59 commits into
mainfrom
feat/cc5-avatar-editor

Conversation

@matbeedotcom

@matbeedotcom matbeedotcom commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Summary

  • crates/cc5-shape (Rust + CPython cc5_shape): apply Character Creator 5 shaping sliders outside CC5.
    • Evaluate a slider pack and write the shaped GLB (mesh, joints and inverse bind matrices).
    • CPU facial expressions: all ~480 CC5 morphs (more than Bevy's 64 per mesh), plus an ARKit-52 mapping.
    • HD (subdivided) characters: SubdivMap + shape_glb_hd drive CC5's level-1/2 mesh from the level-0 pack.
    • Fitting helpers in cc5_shape.fit.
  • examples/avatar_editor.rs: live CC5-style slider editor in Bevy.
    • Recipes, style layers, an expressions panel, --hd, and --snapshot for offscreen renders.
    • Studio lighting and look calibrated against CC5's viewport.
  • examples/shape_avatar.rs: headless shaping, weights JSON in, shaped GLB out.
  • src/cc_render/cc5_materials: Cc5MaterialsPlugin builds Bevy extended materials for CC5's shaders: RLHead/RLSkin, RLHair, RLEye, eye occlusion/tearline and teeth/tongue. It reads the shader maps and parameters the pipeline records in glTF material extras.
  • Cargo.toml: Bevy's experimental_pbr_pcss for soft key-light shadows.
  • docs/design/avatar-editor.md: pipeline, pack format and accuracy notes.

Inputs are built by RemoteMedia-SDK/remotemedia-sdk#36 (same branch name, feat/cc5-avatar-editor): scripts/avatars/cc5_editor/build_cc5_editor_pack.ps1.

Accuracy

  • Sliders vs CC5: linear and additive, as verified in CC5.
  • HD mesh vs CC5's own level-1 export:
    • sliders that only reshape the base mesh: 99% of vertices within 0.02–0.24 mm;
    • HD presets and large body sliders: 99% within ~0.8 mm, up to ~3 mm (they change the HD level directly).
  • Expressions vs Blender shape-key evaluation: within 0.00012 mm.

Test plan

  • cargo test -p cc5-shape: 11 pass.
  • maturin build --release; Python checks against CC5 exports.
  • cargo build --example avatar_editor.
  • Editor runs interactively and with --snapshot, for the base and --hd characters, with and without recipes.
  • End-to-end build_cc5_editor_pack.ps1 -HdLevel 1 from a fresh CC5 session.

🤖 Generated with Claude Code

matbeedotcom and others added 30 commits October 20, 2026 01:13
The avatar editor's studio key light uses PCSS (percentage-closer soft
shadows) to match Character Creator 5's soft shadowing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- crates/cc5-shape: Character Creator 5 shaping sliders outside CC5 (Rust +
  CPython module): slider pack evaluation, shaped GLB writing, CPU facial
  expressions (all ~480 CC5 morphs + ARKit mapping), and HD (subdivided)
  character support via a level-0 -> HD stencil map (SubdivMap,
  shape_glb_hd); Python fitting helpers in cc5_shape.fit.
- examples/avatar_editor.rs: live CC5 slider editor in Bevy with recipes,
  style layers, expressions, --hd for CC5's HD mesh, snapshot mode, and a
  studio look calibrated against CC5's viewport.
- examples/shape_avatar.rs: headless weights JSON -> shaped GLB.
- src/cc_render/cc5_materials: Cc5MaterialsPlugin builds Bevy extended
  materials for CC5's RLHead/RLSkin, RLHair, RLEye, eye occlusion/tearline
  and teeth/tongue shaders from the maps and parameters
  glb_cc5_materials.py records in glTF material extras.
- docs/design/avatar-editor.md: pipeline, pack format and accuracy notes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Smart-Hair-style hair parts (`--hair-lib`): strand parts converted from
CC5's Smart Hair groups, chosen per slot or by style, re-bound to our
skeleton and moved with the body on every shape / expression change.

- cc5-shape: `Conform` binds an uncaptured mesh to body anchor vertices
  (modes scalp / skin / head_box, calibrated against CC5's own placement
  on reshaped heads); Python binding.
- avatar_editor/hair.rs: catalog / styles / regions, per-mesh `follow`
  ("head_box" for layers CC5 moves rigidly, "bone:<joint>@x,y,z" for
  layers CC5 attaches to a bone, using per-slider bone rotation / scale
  from `bone_xf.json`), `bald` styles, own hair / brows hidden when replaced.
- avatar_editor: head view aims at our rig's eye joints only (hair parts'
  skeletons used to drag the camera).
- cc5_materials: mip chains for hair textures and a negative opacity mip
  bias for scalp hair, so strands stay resolved instead of aliasing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conform::bind compared every asset vertex with every anchor: 4.7 M hair
vertices x 4754 head anchors took 12-63 s per part in the avatar editor.
Anchors now sit in a uniform grid searched in cubic shells (exact k nearest,
ties by index) and vertices bind in parallel with rayon: 0.2 s. A test
checks the result against the brute force on random points inside and far
outside the anchor cloud.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
crates/cc5-hair ports hair_build.py's CC5 conversion out of Blender: Smart
Hair cards -> strands (clumps, acceptance, start at the texture's hairline,
depth shading), shape edits (length, comb, gravity, curl, frizz), kept CC5
card layers (brows, scalps), follow detection (head box / bone, from CC5's
shape OBJs and bone dumps) and part GLBs with quantized attributes. The
`cc5-hair` CLI bakes one spec or every Smart Hair group (smart_hair.json):
the whole library in ~15 s instead of ~25 min in Blender, matching the
Python build against CC5 within noise.

avatar_editor:
- `--hair-src/--hair-head/--hair-config`: a live hair panel (group, look,
  shape, colour); changes rebuild the part in the background (~1 s) and swap
  it in; colour edits only rebuild materials; Save writes the library part,
  catalog, style and settings. `--hair-edit` applies settings at start.
- `--snapshot-batch jobs.json`: many snapshots (style, recipe, hair edit,
  camera) in one process (~6 s each instead of a process per image).
- hair.rs: shared conform / bone-follow helpers; parts built in memory.
- cc5_materials: Cc5MapBase gives in-memory meshes the asset path their
  extras.cc5 maps resolve against.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…reads FBX

cc5-fbx reads a CC5 FBX export with ufbx and writes the GLB the avatar editor
loads (what Blender's import + glTF export made via fbx_to_glb.py): meshes per
material with _CCIDX, the skin in bind pose (FBX joint orientations, metres,
Y up), diffuse + opacity merged into the base colour, normal maps, roughness
from shininess. --dump writes fbx_to_glb.py's joints/weights/rest-position dump;
--cc5-json adds CC5's tints/opacity and extras.cc5 with its maps (TGA decoded
in-crate so the image crate's features, shared with Bevy, stay unchanged).

Against Blender on the beautiful reference and HD exports: positions within
2.4e-7 m, identical weights (and group order), joints, UVs, materials and
images; the dump builds the same editor pack (6.5e-7 m); editor renders match.
0.5 s per character instead of a Blender run.

cc5-hair's Source::load takes an FBX directly (converted in memory, CC5
settings from the sidecar JSON); an FBX head supplies its own CC5 material
settings. Smart Hair groups may hold character.glb or character.fbx. The own
hair baked from the raw FBX matches the GLB bake (117,860 vs 117,861 strands,
identical materials and follow modes).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n the vertex shader

cc5-hair writes strands as glTF LINES (one vertex per point: position, (ID, t)
UV, colour, half-width in TEXCOORD_1, skin) and flags their materials
extras.cc5.ribbons; `--ribbons` keeps the old triangle ribbons for comparison.
The library shrinks from 1044 to 437 MB.

The editor turns each LINES mesh (loaded or built live) into two vertices per
point at the point, TANGENT = (strand direction, -/+ half-width), and the
conform moves only the points (Ribbon::write expands them in parallel).
Cc5Hair gets a `ribbons` pipeline key: its specialize swaps in
hair_vertex.wgsl (forward + prepass, adding normal and tangent to the prepass
layout), which skins the centre like Bevy's mesh shader and offsets it across
the strand facing the view; the width follows the strand's facing halfway
(FACING 0.5) and is scaled by 2/pi in shadow maps, calibrated against CC5.
Card hair keeps Bevy's shaders. Lighting normals point out from the head (what
fixed ribbons showed through their back faces). Parts stay hidden until bound.

Parity vs CC5 (14 groups x alika / extreme): diff 12.00 vs 12.07 for triangle
ribbons, detail 6.04 vs 6.13 (CC5 6.62). Shape update 29 ms vs 34-47 ms.
Conform::apply runs in parallel.

Also strips a UTF-8 BOM from cc5-fbx/src/glb.rs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…editor

- `cc5-hair regions <character.fbx | dump.json> --lib`: the library's
  regions.json (port of hair_regions.py; identical output, also read straight
  from the FBX).
- `cc5-hair check --src <dir> <group>...`: the conform against CC5's own
  reshaped hair (port of check_conform_cc5.py; identical numbers, 8x faster).
- `bake --style <name>`: a style of the baked part (the own-hair "CC5 Converted").
- A library without atlas/<atlas>/atlas.json uses built-in RLHair defaults.
- Editor: `--snapshot-batch` jobs take `save: true` (the panel's Save, for
  scripted save -> restart -> load checks); hair-edit build failures are
  logged; a scripted edit's "group" key no longer lands in the saved settings.
- Docs point to cc5-fbx / cc5-hair instead of the removed Python scripts.

Verified: a library built only with cc5-fbx / cc5-hair from raw CC5 FBX
exports (no Blender on PATH) in 11 s, 34 gallery renders clean; live edit of a
group that is only a raw character.fbx; saved edit reloads as rendered live
(blurred diff 0.24 vs 1.20 to the unedited part).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nel-like scripted edits

- `cc5-fbx expressions <ref.fbx> <pack dir> <out dir>` writes expressions.json +
  .bin from the FBX's morph targets (ufbx blend shapes), replacing Blender's
  build_expression_pack.py: on the reference character the same 480
  expressions, same vertices, deltas within 3.7e-9 m, in 0.2 s.
- Snapshot-batch edits behave as the Hair -> Edit panel: settings add to the
  group being edited, colour variables alone recolour without a rebuild, a job
  with an edit keeps the edited part; build and recolour timings are logged.
  Side part wavy (largest): open 1.6 s, density 0.8 s, gravity 0.8 s, root
  colour 24 ms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ettings; opt-in input log

Driving the Hair -> Edit panel with real clicks and drags (group pick,
density, gravity, root colour, Reset to saved) showed settings the config
leaves out displayed at the slider's start (gravity -0.05 instead of 0):
they now show cc5-hair's own defaults. CC_DEBUG_INPUT=1 logs the window's
pointer input for scripted UI checks.

Panel timings on Side part wavy: open 1.4 s, density 0.4 s, gravity 0.5 s,
root colour without a rebuild, reset 1.3 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A synthetic character (two joints, a skinned CC_Base_Body quad) checks that
Body::skin_at returns normalised top-4 weights, and that a strand part written
as LINES (and with --ribbons as triangles) reads back with the gltf crate:
the head's skeleton by name, one vertex per point and consecutive segments,
half-widths in TEXCOORD_1, extras.cc5.ribbons, normalised weights.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A CC5 Smart Hair group (Viking) and an accessory (the earring) each bring a
joint named CC_Base_Pivot; Blender names the later one CC_Base_Pivot.001.
cc5-fbx kept both names, which collapsed them in the name-keyed dump and
would confuse rebinding by name. On a fresh Viking group export cc5-fbx now
matches Blender's fbx_to_glb.py: 107 joints by name within 7e-7 m, all 19
meshes within 3.6e-7 m, identical weights, UVs, materials and dump; the
part built from the raw FBX equals the library's (77,512 strands, same
bone follow).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dragging expression sliders in the editor (checking the cc5-fbx expression
pack) showed two layout bugs: the section's id came from its label, whose
"N active" count changes on the first move, so it collapsed under the
pointer; and the Neutral button appeared above the sliders once one was
active, shifting every row mid-drag. The header has a stable id now and the
button is always shown (disabled at neutral). With the cc5-fbx pack,
Eye_Blink_L/R at 1 close both eyes; V_Open reaches 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`--base none | neutral_f | neutral_m | <slider> | <recipe.json>` sets the body
the editor starts from and "Reset all" / per-slider reset return to. Without
it, a pack with CC5's neutral bases (pack_xl: avatar_neutral_f / _m) starts on
the neutral female; other packs on the captured character as before. The panel
shows the base, and changed sliders are counted against it.

Recipes keep the base apart from the changes: cc5-shape's recipe_on() writes
{"base": {...}, "sliders": {...}} and weights_from_recipe() applies both, so a
saved recipe gives the same body anywhere (plain recipes read as before).

Checked in the editor on pack_xl: starts as the neutral female with 0 sliders
changed; one change, Save, Reset all (back to 0) and Load (1 again) work.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without `character.glb pack_dir` the editor opens $CC5_EDITOR_DIR (default
D:\cc5_editor\beautiful_e2e, build_cc5_editor_pack.ps1's output): its
character.glb and pack_xl, else pack. With pack_xl's neutral bases that
starts on CC5's neutral female; the environment map already defaults to the
character's env folder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ers), CC5 camera/lights/IBL for comparisons

- Cc5Skin keeps the CC5 settings it was built from; set_vars rebuilds the uniform
- skin.rs: CC5's RLHead/RLSkin settings edited live, skin recipes (--skin), skin
  packs (--skin-pack, default <character dir>/skin): whole skins and SkinGen layers
  composited over the diffuse in the background; --hide-hair
- cc5_scene.rs / ibl.rs: --cc5-scene views (cc5:face) at CC5's camera, --cc5-lights
  with CC5's spot lights and its IBL HDR prefiltered in memory
- crates/cc5-skin: pack format, compositor, builder from CC5 captures

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- skin.wgsl: subsurface wrap and transmission for point and spot lights too;
  shader constants as SkinTune (Cc5Materials::skin_tune, CC5_SKIN_TUNE), new
  defaults from CC5 renders (full normal detail in the diffuse, specular 0.6)
- RLHead/RLSkin normal maps are DirectX-style: flip_normal_map_y (fixes lighting
  steps at UV seams: philtrum, nose)
- --cc5-lights: CC5's rect lights without inverse-square falloff, tube radii,
  calibrated intensities, tint, Top gain, saturation 1.6 (flat grey: dE 3.5)
- editor camera: contrast-adaptive sharpening 0.5 (CC5's crisp viewport detail)
- skin: flat albedo kept every frame; --hide-hair keeps brows (as CC5)
- cc5-skin: layer solve test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…uration

Fitted to CC5's baked exports (human colour: per-channel sRGB gains per
_Red/_Yellow/_Black/_Range, cc5_materials/human_color.rs; blend map: linear lerp)
and its renders (saturation about the max channel x(1+2s), brightness
exp(8b) on the linear albedo); against CC5's render changes: 2-9 dE on changes of
5-50. cc5-skin build: flat-image second base, held-out check base. Design doc:
Skin section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…within 1%); hide_brows for CC5 comparisons

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ted into the metallic-roughness texture

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d normal maps, blended and renormalized

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tick, blush, eyeshadow, contour, highlight, freckles, stubble), any colour, in recipes and the Skin panel

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tubble, lipstick keeps the lips' shading (Apply::detail)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd normal strength; generator pattern controls (dot size, density, variation); all in recipes and the Skin panel

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… where the character's own mole is, it lands on the same spot

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CC5's SkinGen bake composites onto its own base skin, so a flat diffuse set
with LoadImageToTexture never reaches the bake; the two bakes match and the
opacity solve degenerates to alpha 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… of the welded smooth normal (shape_glb and the editor, expressions too)

A reshape moved positions only, so a large one kept the capture's shading:
the neutral male base on a female capture rendered breasts on a flat chest
(old normals 24 deg off the surface across the chest, median).
On CC5's own neutral_m geometry the turned normals match CC5's exported
normals to p99 0.05 deg; unmoved vertices keep their normals bit for bit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SkinGen layers are not all normal blends: fitted on two baked skin bases,
tattoos, contour, tans, beards and freckles multiply and highlights screen
(errors 3-4 levels as normal, 0.2-0.6 with the right mode). The build solves
each mode and keeps the best per layer map; LayerImage carries the mode and
compose applies it, so strength and tint work for all modes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
matbeedotcom and others added 29 commits October 21, 2026 13:56
A SkinGen preset can hold layers in several modes (full makeup: the lipstick
multiplies, the rest is normal): the build keeps, per texel, another mode where
it explains the texel clearly better, as parts of the layer map sharing its
rect; compose lays the parts after the map. Full makeup: 0.97 -> 0.47 levels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CC5's response to colour changes (makeup, beards, foundation) matches ACES far
better than AgX with a saturation boost. Swept against CC5's renders: ACES
+0.9 EV, saturation 1.0, sharpening 0.15. Over 8 skins and 25 SkinGen layers:
mean dE 4.4 (layers 5.14 -> 4.30), error in the layers' change from the base
0.89 -> 0.61, detail 1.00. Docs: the dark second base and blend modes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er-layer second base

Blush, eyeshadow, contour, highlight, freckles and stubble take their shape
from a weighted sum of region-mask features (blurred, bands, moved down / away
from the face's centre line) fitted to CC5's preset layers (soft IoU against
them: 0.38->0.59, 0.57->0.77, 0.19->0.47, 0.13->0.28, 0.22->0.68, 0.39->0.54);
lipstick and spots keep their hand-made shapes. 'cc5-skin generate' exports each
generator for fitting; 'alt_for' in the build spec solves a layer on another
second base (redness, over CC5's 15-layer cap on the first).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ge, finish, decals)

As SkinGen's Layer Advanced Settings, on every layer: Adjust Color (hue,
saturation, brightness, contrast) and a Layer Mask (a head region and / or a
greyscale image, invertible). Generated layers: blend mode, Range (expansion,
blur, contrast), roughness finish, any number of each kind. Decals: an image
placed on a material (place, size, rotation, blend, strength, adjust, mask).
All in the recipe. Generator defaults (colour, strength, blend, stubble density)
fitted through their shapes to CC5's presets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ertical)

The editor's 25-degree lens (~53 mm) showed faces with more perspective than
CC5's viewport; distances scale with the FOV, so framing stays the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CC5's renders scale uniformly from ours (fitted silhouettes: 0.881 x, 0.881 y),
so CC5 fits the 36 x 24 mm gate's height to the image rather than stretching
the gate: the vertical angle is the gate's (17.06 deg at 80 mm) whatever the
image's aspect. Render at CC5's size (1651x961) and compare directly; the old
1651x1101 + resize made faces ~14% too wide.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…inst CC5

CC5's eye map paints the pupil at 0.375 of the iris; its render of Ariana shows
0.31 = 0.375 x Pupil Scale 0.96 / Iris UV Scale 1.161, with the iris edge in
place: Iris UV Scale now shrinks the pupil too (we ignored it: pupils ~45%
too big). IRIS_LIGHT 1.9 -> 6.5: the iris was 3.5x too dark against CC5 (L 7.5
vs 20, sclera matching), now L 21.5 vs 21.3.
Snapshots ignore mouse camera input (the window opens on the user's desktop; a
stray scroll had zoomed two batch frames).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…aps, CC5-mode hair gain

- CC5's SSS map is centred on mid grey (0.5 = full strength, as without a map):
  HD skins' ~0.5 maps halved the subsurface light (pale, grey 'ghost' faces).
  HD Neutral F dE 5.70 -> 4.97, HD Aaron 4.70 -> 3.83.
- Mip chains for every skin texture (and the composited diffuse): 2K-8K maps
  seen a few hundred pixels across aliased into blotches and harsh creases.
  Old skin dE 5.08 -> 4.69, detail 1.16 -> 1.04.
- cc5-skin build downscales skin maps to the pack's size (CC5 exports HD skins
  at 8192 from their 2K presets).
- Hair: diffuse / specular gains for scalp hair in CC5 mode (CC5_HAIR_GAIN,
  default 2, 1 with CC5's lights): hair regions' dE 11.8 -> 7.9.
- SkinTune: normal map strength and diffuse normal blur (off by default).
- Editor: compositing bases and region masks read the top mip level.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Blend::Overlay and SoftLight for generated layers and decals (captured
  layers keep the normal / multiply / screen they solve to).
- Generated layers and decals reorder (lay before the one above).
- CC5 mode: ambient 80 -> 140 and the skin's extra wrap 0.08 -> 0.16, fitted at
  CC5's framing over the bare skin and three skins: mean patch dE 5.04 -> 4.77.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(1, 0.92, 1.15) -> (1, 0.94, 1.10): patch dE bare skin 4.58 -> 4.23, HD
Neutral F 4.68 -> 3.88, HD Aaron 4.02 -> 3.29.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…erials

An occasional frame showed the character's own diffuse after a skin preset;
the snapshot now waits until every skin material shows its composite (and
warns when it had to).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e too

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scene.json records no rect size, so they cast hard shadows; fitted against
CC5's renders: patch dE bare skin 4.24 -> 4.12, HD Neutral F 3.88 -> 3.80, HD
Aaron 3.29 -> 3.18.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…terial extras)

Every layer (captured, generated, decal) can lay a metallic value (into the
metallic-roughness map's B), an occlusion (into the AO map) and a glow (an
emissive colour at a strength, composited into an emissive map), each through
its opacity; in the recipe as "extras".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CC5's stubble layer is ~0.1 opaque between hairs and ~0.45 on them; ours was
dots only (sub-pixel at a face view, averaged away). Against CC5's preset in
render: change error 1.26 -> 1.12 (CC5's change 1.6).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dots a fifth of a pixel across at a face view averaged into nothing: the
hairs are now short soft strokes (down the face, +-35 deg) in the hair colour
over a pale grey-beige haze (a part of the layer), as CC5's stubble looks.
Default hair colour (80, 68, 58) at 0.7. Against CC5's preset: visibly
stubble, detail 0.62 -> 0.70.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Key Light - Up 1.15, Left_Rim 1.3, Top 1.6 (was 2.5), Key Light - Down 1.3:
mean patch dE over the bare skin and three skins 4.09 -> 3.76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Snapshot jobs take "cc5": {tint, ambient, ibl, exposure, sat, gains,
skin_tune}; Cc5Live applies them live (grading, IBL re-prefiltered on a tint
change, lights, ambient, skin materials' SkinTune) and the shot waits until
they are on. A whole calibration sweep is one launch (~3 s a shot) instead of
one launch (~40 s start-up) per setting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ap / SSS / ambient

- Hair: a colour multiplier (Cc5Materials::hair_tint, CC5_HAIR_TINT), in CC5
  mode the light tint's inverse: neutral hair no longer reads pink-mauve
  (bangs a/b 10.9/7.1 -> 9.7/8.8; CC5 7.9/6.8).
- Skin wrap 0.16 -> 0.09, SSS falloff desaturation 0.35 -> 0.41, ambient
  140 -> 110: refitted on the whole face over five faces in batched launches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Flipped, the large-scale relief in SkinGen's full skins (cheeks, nasolabial
folds) shaded as dark blotches that CC5 doesn't have. Unflipped is better or
equal on all five check faces: patch dE 3.50 -> 2.79, face dE 7.53 -> 7.27.
CC5_NORMAL_FLIP_Y=1 restores the flip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bevy's PCSS sizes the penumbra from the blocker / receiver gap, so a nose
or eyelid shadowing skin about a centimetre away stays hard-edged at any
light radius. That gave a lighting step down the philtrum and dark
crescents under the eyes. In CC5 mode, Bevy's shadow sampling is replaced
by a vendored copy with a minimum blur of 25 (Bevy: 0.5), fitted on five
faces: face dE 7.27 -> 7.10, patches 2.79 -> 2.73.

Also: diagnostic knobs CC5_SHADOWS, CC5_SHADOW_OFF (light names) and
CC5_RADIUS_SCALE; the eye occlusion / tearline films are explicitly not
shadow casters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n CC5 mode

The hair shader's anisotropic strand lobes (primary, TRT, transmission)
only looped over directional lights. CC5's lights are all spot lights, so
CC5-mode hair had no strand highlights at all. Clustered lights now get
them too, through the same walk as the skin shader.

The root occlusion is now a Cc5Materials setting (hair_root_occlusion,
in the hair params' tint.w): studio 0.55, CC5 mode 0.3
(cc5_scene::HAIR_ROOT_OCCLUSION, knob CC5_HAIR_ROOT_OCC).

Five faces: face dE 7.10 -> 6.91; hair region (hair_metric.py) dE
10.33 -> 9.55, L* -7.8 -> -5.2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CC5's renders have a fixed screen-space backdrop (identical in face and
body framings): a grey-blue radial falloff. With `backdrop.png` next to
the CC5 scene file (fitted from CC5's renders, RMS 1.4 levels), the
camera's skybox becomes that image:
- a view-space cubemap at FOV_DEG and the image's aspect;
- texels pre-inverted through Bevy's ACES fitted tone mapping and the CC5
  grading exposure;
- turned with the camera every frame (cc5_backdrop_follow).

Renders match CC5's backdrop within about 2 levels (was up to 25 darker),
and hair edges blend over the same backdrop: five-face dE 5.18 -> 5.14
(character-masked).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r, blush, freckles

New fitted-shape feature a*b.p<r>: the product of two region masks,
each blurred by r, which is 1 where both are 0.5. That is their shared
border: the jaw line between neck and chin / cheek, the sideburns between
ear and cheek. Linear sums of single-region blurs could not express a band
there.

Refit against CC5's presets (gen_shape_fit.py), soft IoU:
- stubble 0.545 -> 0.631
- contour 0.475 -> 0.543
- freckles 0.682 -> 0.721
- blush 0.591 -> 0.601

Rendered against CC5 (gen_validate.py change error): stubble 1.28 -> 0.96
of 1.60, contour 0.75 -> 0.72. Eyeshadow and highlight fitted closer but
rendered worse (0.61 -> 0.67, 0.93 -> 0.97), so they keep their earlier
shapes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tubble refit

New fitted-shape feature g<u>,<v>,<sigma>: a Gaussian blob at (u, v) / 64
of the head texture, mirrored across the face's centre line. It places
patches the region masks have no feature for: the forehead centre and the
cheekbones of CC5's highlight, the beard band of its stubble. All CC5
heads share this UV layout.

Fit with blobs (gen_shape_fit.py GEN_FIT_BLOBS=1), soft IoU:
- contour 0.54 -> 0.88
- highlight 0.28 -> 0.56
- stubble 0.63 -> 0.93

Per kind, the fit that renders closest to CC5 is kept (gen_validate.py
change error):
- contour 0.72 -> 0.60
- highlight 0.93 -> 0.72
- stubble 0.96 -> 0.88
- blush, eyeshadow and freckles keep their fits (blobs rendered worse
  there)

Mean over the seven kinds: 0.75 -> 0.64.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CC5's beard_stubble is fine, dense, pale hairs. The stubble default is
now colour (105, 92, 80) (was (80, 68, 58)), density 3 (was 2), size 0.7
(was 1). Change error against CC5 (gen_validate.py) 0.88 -> 0.70 of 1.60.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…over time (weight gain)

A "Timelapse" section interpolates every slider weight linearly from a start
(the sliders when the editor opened, or the current sliders) to a target: a
preset ("Heavy (female)" = Female Heavy Full-body 1 + Face Heavy 0.5, "Heavy
(male)"), the current sliders, or a recipe. Time slider, Play / Pause,
duration, back-and-forth. `--timelapse heavy-female|heavy-male|recipe.json`
opens with it playing; a --snapshot-batch job's "time" renders a point of it.
Each frame is a plain slider mix, so Save GLB / recipe save what is shown.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant