Shadow deformation policy - #130
Merged
Merged
Conversation
…asured on a pose they are never in SH-03 threaded per-view shadow LOD through the renderer and, in doing so, applied it to every caster: object.cpp built each request with the frame's LOD toggle and nothing else. The simplifier measures deviation on the mesh as authored — bind pose, base weights, the vertex buffer at build time — so for a skinned caster that number describes geometry that is never rasterised. This is not a loose estimate. A joint rotation can carry a vertex arbitrarily far from where its rest-pose deviation was taken, so the error is unbounded, and SH-02 was careful to call the metric an estimate precisely because it could not cover this case. It was live rather than theoretical. BrainStem logged a shadow-level transition on a skinned caster within seconds of starting, and the shadow-LOD demo's skinned self-shadow caster was drawing 184 of its 1248 triangles on the strength of that claim. ShadowGeometryRequest now carries a ShadowCasterDeformation classification. Deliberately not expressed as lodEnabled = false, which would have reported LodDisabled and conflated a user's toggle with a safety fallback — the panel would then answer "why is this caster at full detail?" with somebody else's reason. It defaults to Deformable on the same principle as worldScale's NaN: a producer that forgets the field must not receive the optimistic answer. That default immediately caught every existing resolver fixture, which is the intended behaviour on its first day. The resolver answers with DeformableFallback: the whole mesh, and an INFINITE projected error rather than zero, because zero would rank a deformable caster as the most accurate in the frame. Precedence runs InvalidCaster, LodDisabled, DeformableFallback, SingleLevel, then selection — a producer bug outranks a property of well-formed geometry, and a global switch is the operative fact about every caster rather than a deformable one being more disabled than the rest. Deformation is checked before chain length so a single-level deformable caster still reports why it may not select. No hysteresis history is staged, which the Selected-only staging rule already guaranteed and a test now pins. Classification covers all three carriers that deform a mesh after measurement: skinned or morph-weighted instances, morph-CAPABLE geometry independent of its current weights, and storage-vertex geometry a compute pass rewrites. Weights are this frame's value, not a property — classifying by them would swap a caster's error model mid-animation. Cloth is storage-vertex and single-level, so it was safe by accident; classifying it explicitly stops that accident being load-bearing the day storage-vertex geometry gains an LOD chain. It lives in its own header rather than as an Object member so classification and the resolver's response to it are tested separately, and neither is proven only by the other. Object::shadowGeometry is removed rather than documented as unsafe. It was unused and it was a public route around every rule above: substituting a proxy silently substitutes its topology, its deformation carriers and its bounds, with nothing checking that any of them match. A validated proxy API — deformation compatibility, an explicit morph contract, proxy-derived bounds, enforced at load time — is the remaining half of SH-04, and no route in beats an unchecked route in. The calibration was re-run rather than assumed to survive, since ShadowLodDemo carries a skin and a morph primitive by design. Cost moved as expected: the self-shadow caster went from 184/1248 triangles to 1248/1248, and the cascade group from 59.9% to 68.2% of full detail at budget 1. The error column did not move at all — not one figure — and the reason is a limitation of the metric rather than the fix being inert: the panel reports 13 deformable resolutions scene-wide but 0 in cascade 0, and --debug-shadow only visualises primary directional visibility, so the metric never saw the self family these casters live in. The pre-registered 0.1% threshold was re-applied unchanged and still selects budget 1; budget 2 becoming eligible was a live possibility worth checking, and it did not happen. Reversals remain 0.00 at every ratio, so the dead band stays disabled. Also corrected in this change: five contracts that still described pre-SH-03 behaviour (LodDisabled's switch, the request's mirrored flag, --no-lod seeding two switches, the tint flags and the fixed camera-derived defect in onboarding), and the dead shadow-proxy scaffolding the removed setter left behind — the binding's shadowGeometry field and its branches are gone, while shadowGeneration stays in the hysteresis key as reserved for the validated proxy API, now covered by a test since nothing else calls it.
Missed updating that.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.