Skip to content

1.2.0: opt-in MToon finish, outline minimum width, hair band, contact shadow, crease AO - #448

Open
arkavo-com wants to merge 4 commits into
mainfrom
issue/447-opt-in-surface-features
Open

arkavo-com wants to merge 4 commits into
mainfrom
issue/447-opt-in-surface-features

Conversation

@arkavo-com

@arkavo-com arkavo-com commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Closes #447

Summary

Five presentation features for 1.2.0, all off by default:

  • Stylized glTF metallic/roughness finish (RendererConfig.enableMaterialFinish).
  • VRMRenderer.outlineScale and outlineMinimumPixels (a minimum outline width).
  • Hair highlight (HairHighlightConfig).
  • Contact shadow (enableContactShadows).
  • Crease AO (enableSSAO).

With those features off, rendering is byte-identical to 18d6050, the last commit before them. The one exception is the transparentWithZWrite change described below.

This PR also includes every fix from a max-effort code review of the first implementation:

  • The finish was on by default.
  • Skinned shaders kept a stale 240-byte material struct. The structs and the outline extrusion now live in a shared MToonShared.h.
  • Skinned meshes fed a dummy view vector to the finish and the hair band.
  • Contact shadow: inherited depth bias, encoder state-cache bypass, T-pose sizing, ignoring hips motion, and drawing over translucent surfaces and outlines.
  • The minimum outline width ignored the width mask.
  • Inverted roughness mapping, and thresholds that differed between Swift and the shader.
  • FP16 banding on glossy metal.
  • The hair band's light scaling grew with intensity squared.
  • The silhouette-mode leak.
  • A gitignored fixture, and tests that could not fail.
  • The pin script edited consumers half-way before failing.
  • Smaller cleanups.

Changes from GoM group testing:

  • The leather sheen peaked at 55% of the incident light in white, so typical leather values read as silver. It now peaks at 10% (dielectric strength) in the base colour's hue.
  • The hair band's tint now follows the base colour on dark hair (fully up to linear luminance 0.05, easing back to 35% by 0.5), so dark hair no longer gets a grey streak.
  • GoM validated eb19bfa on a local checkout (Lisa: black leather at metallic 0.22 / roughness 0.36, dark brown hair). Merge waits for GoM's full test pass on the pushed commit.

Behaviour change

Materials with VRMC_materials_mtoon.transparentWithZWrite (or VRM 0.x _BlendMode = 3) now write depth, as three-vrm does. Before, the flag only changed render-queue order, so an outlined translucent material was covered by its own outline. Plain BLEND materials are unchanged on purpose: three-vrm and UniVRM also draw the outline after a surface that writes no depth, so the outline covers it. MToonTransparentOutlineTests guards that. None of the bundled AvatarSample/VRoid fixtures set the flag.

Per the release policy, publish 1.2.0 as a GitHub pre-release until Muse has validated its assets.

Test plan

  • make shaders: all five slices build with -Werror. The committed metallibs match a rebuild from these sources byte for byte.
  • swift test --parallel: 2252 tests. The only failures are the 4 SpringBoneRegressionTests trajectory baselines, which fail the same way on unmodified main.
  • MToonLegacyGoldenTests: byte-exact frames captured at 18d6050 through VRMRenderer. They cover rigid and skinned fixtures, the merged and dedicated outline hulls, and default and widened outlines.
  • MToonMaterialLayoutReflectionTests: Metal reflection confirms every MToon vertex and fragment entry point sees the Swift MToonMaterialUniforms stride.
  • Mutation checks: each test below failed with the original bug put back and passes with the fix.
    • Hair band visible from behind (the dummy view vector).
    • Linear light scaling (the intensity-squared hair band).
    • Smooth glossy band edge (the half-precision normal).
    • Translucent surfaces and outline culling (shadow drawn after the model).
    • Host-drawn floor (the inherited depth bias).
    • transparentWithZWrite outline coverage (94% covered before the fix).
    • Dielectric sheen strength and hue (the 0.55 white sheen peaked at 90/255 of a unit light, hue 1:1:1).
    • Hair band hue on a dark base (the fixed 35% tint gave a grey 1:0.98:0.98 band).
  • AvatarSample_U.png regenerated. Before the refresh, it was pixel-identical to a render from unmodified main.
  • scripts/sync_consumer_pins.sh 1.1.2 --musecore 0.41.0 --dry-run finds every pin, including both pins in the GameOfMods Xcode project. It refuses 1.2.0 until that tag is on origin.

Notes for review

  • Finish cost on an M4 Max: +0.25 ms (+23%) for a full-viewport metal sphere at 4096², up from the first implementation's +0.13 ms. The increase comes from the full-precision normal, the camera-derived view vector and, since the GoM feedback, a separate tint per lobe (+0.03 ms). With function constants, materials that don't use an extension pay nothing for it. The fallback pipeline costs +0.08 ms when an extension is compiled in.
  • metallicOverride, ssaoPassMs and finishSpecularMs never shipped and were removed, so their removal breaks no API.
  • The consumer pin bump has two stages, because GameOfMods pulls MuseCore remotely. See docs/releases/1.2.0.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QMsmW9ToChEmkribgzuVhx

arkavo-com and others added 3 commits October 18, 2026 15:52
…shadow and crease AO (1.2.0)

Adds five presentation features, all off by default. Default output stays
byte-identical to 1.1.2 (MToonLegacyGoldenTests: rigid and skinned fixtures,
merged and dedicated outline hulls).

- Stylized glTF metallic/roughness finish behind
  RendererConfig.enableMaterialFinish: MToon, UniVRM and three-vrm ignore the
  pair and VRoid exports write metallicFactor = 1.0 everywhere. Roughness
  narrows both lobes over 0...1; thresholds are shared with
  MToonSpecularMode. Shades from a float normal and a camera-derived view
  vector, so skinned meshes and FP16 slices match the rigid path.
- MToonShared.h holds the uniform/material layouts and the outline
  extrusion for MToonShader.metal and SkinnedShader.metal; a reflection test
  checks every entry point's MToonMaterial size against the Swift stride.
- outlineScale and outlineMinimumPixels on every hull path; the floor is
  scaled by the width mask and never adds a line to a zero-width outline.
- Hair band along the UV v axis; finish and band scale linearly with light
  and follow the normalization factor like the rim.
- Contact shadow drawn before the model with zero bias and a state-cache
  reset; humanoids are grounded at the feet, other models at per-node bounds.
- Extensions are a function constant compiled only into materials that use
  them. Silhouette mode suppresses finish and hair. Benchmark flags reach the
  visionOS bench and the JSON report; misleading ssao/finish CPU phases
  removed.
- sync_consumer_pins.sh checks everything before editing and handles the
  GameOfMods Xcode project in a second stage after a MuseCore release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QMsmW9ToChEmkribgzuVhx
main is past the 1.1.2 tag with rendering changes (#429, #437, #444), so
the goldens prove the opt-in features leave the pre-feature main unchanged,
not that output matches 1.1.2. Also notes that the pin script's --dry-run
fetches the MuseCore tag it inspects.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QMsmW9ToChEmkribgzuVhx
… test (#447)

- Non-face BLEND draws with VRMC_materials_mtoon.transparentWithZWrite (or
  VRM 0.x _BlendMode 3) now write depth, as three-vrm does. Their own
  outline hull no longer covers them. Plain BLEND keeps the reference
  draw order (three-vrm and UniVRM draw the outline after a non-depth-writing
  surface), now guarded by MToonTransparentOutlineTests.
- The contact-shadow floor test draws the host floor with its own unbiased
  pipeline and the model without outlines, so a shadow that inherits a model
  draw's depth bias fails it. The VRMRenderer-drawn floor fixture is removed.
- Refresh AvatarSample_U.png.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QMsmW9ToChEmkribgzuVhx

@gitar-bot gitar-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gitar has auto-approved this PR (configure)

@github-actions

github-actions Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

⚠️ Claude Code Review ran on eb19bfa — result: success.
Review completed. Tool permission denials: 8. Denied tools: Bash. Denied Bash programs: NEW, PR, before, cd, do, done, echo, for, formerly, git, grep, head, issue, no, now, previous, review, used, was, wc. Turns: 13. Duration: 150s.

Do not interpret missing findings as a clean review; inspect the execution diagnostics.
Findings are posted as review comments. Run log.

The finish's sheen lobe peaked at 0.55 of the incident light in white, so
typical leather values (metallic ~0.2-0.4) rendered as polished silver. It
now peaks at 10% of the incident light, inside the 4-10% a dielectric
reflects, in the base colour's hue (each channel over the largest, so a dark
base keeps its colour without its darkness; neutral and black give white).

The hair band blended its tint only 35% toward the base colour, which laid a
grey streak over dark hair. The blend now follows the base colour fully up to
linear luminance 0.05 and eases back to 35% by 0.5, so light hair keeps its
pale band and dark hair is brightened in its own hue.

New tests measure the added light at a unit key light with normalization
off. At full sheen weight (metallic 0.4) the leather sheen stays under
27/255, about 10.5% (a 0.16 reflectance reaches 40), with hue
(1, 0.45, 0.25) against the base's (1, 0.46, 0.26). On a dark brown base
the band peaks at +18 over lit hair at 13, hue (1, 0.54, 0.33) against
(1, 0.58, 0.33). With the old 0.55 white sheen and fixed 0.35 hair tint both
tests fail (sheen peak 90/255, hues ~1:1:1).

Finish cost at 4096x4096 on M4 Max is now +0.253 ms (was +0.224 ms); the
compiled-in fallback cost is unchanged at +0.075 ms. Default rendering is
unchanged (MToonLegacyGoldenTests).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QMsmW9ToChEmkribgzuVhx
@gitar-bot

gitar-bot Bot commented Oct 18, 2026

Copy link
Copy Markdown
Code Review ✅ Approved

🟡 Medium risk · Adding opt-in material finish, hair, shadow, and AO effects plus changing transparentWithZWrite depth handling could alter appearance or occlusion for affected avatars.

Adds five opt-in presentation features for 1.2.0 (MToon finish, outline minimum width, hair band, contact shadow, crease AO), all disabled by default so rendering stays byte-identical to 18d6050 when they are off. No issues found.

Verification

Rules No rules evaluated

Functional validation Not enabled

Set up

Auto-approval Approved

For more verification details, comment gitar display:verbose.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing compact verification results.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

This branch has not been deployed

No deployments
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.2.0: opt-in MToon finish, outline minimum width, hair band, contact shadow, crease AO

1 participant