#1328 Snapshot: avatars only, transparent background (phase 1) #1341
No reviewers
Labels
No labels
amd
avatars
bug
builder
cannot-reproduce
crash
epic
feature
from-viewer
gl-removal
known-limitation
monitoring
parity
perf
platform
priority
critical
priority
high
priority
low
priority
medium
provenance
rendering
rt
status
in-progress
status
testing
status
up-next
triage
ui
upstream
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
sky_line/Slipstream!1341
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "TheSlowly/Slipstream:snapshot-avatars-1328"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Part of #1328 (phase 1). The existing "Avatar (Transparent)" snapshot layer becomes "Avatars only (transparent background)":
A fresh review was done and its findings are fixed. Tested in-world.
Possible follow-ups, not in this PR: studio lighting, a shadow catcher, saving to SL, and other avatars' flexi attachments.
The layer's alpha was not opacity. Each avatar-only recording read its avatar-id pass and depth back to the host and the CPU counted covered pixels; alpha-blended hair or lace counted as covered at 50 % texel alpha or more, so a soft edge became a hard cut, or the hair's blend over black kept full alpha and showed as a dark fringe. The colour was then unpremultiplied after the tonemap, in sRGB bytes, which is only an approximation. The alpha now travels with the colour, as coverage in the HDR scene's A: - After the opaque scene and the composites over it (camera medium, volumetric fog, precipitation veil), a compute clears every pixel with no avatar surface or with the world in front of it, and sets A = 1 on the rest (clean_snap_holdout.comp). Fog and haze on an avatar therefore stay; what they painted over the background goes. - The world occluder comes from the warm-up recording on the GPU: its depth wherever its avatar-id pass shows none of the layer's avatars. A fullscreen depth draw merges it into the depth before the transparent layers, so each hair or lace fragment behind the world fails its own depth test. A soft fringe in front of a wall stays soft. - The alpha pipelines already composite A "over" and the supersampling already averages RGBA, so the scene ends as premultiplied colour plus antialiased coverage. A tonemap variant (TONEMAP_STRAIGHT_ALPHA) unpremultiplies in linear HDR before the exposure and the tonemapper, writes straight colour and A, and renderOffscreen reads RGBA back. Alpha below half an 8-bit step is the floor: transparent black. That also bounds the division (x510 at most). The mattes are this alpha. The HDR alpha had another meaning: the medium noFade bit, written by the deferred lighting and consumed by clean_medium_apply.comp, which runs before the holdout. Its other readers in these recordings are the snapshot accumulation and the new tonemap, plus the motion blur, which is now off here. Nothing in the layer carries coverage for light in the air or over the background, so these are off in its avatar-only recordings: god rays, falling precipitation, the snow surface mesh in the main view (it still casts), effects (HDR and display), CAS / RCAS sharpening, motion blur. Bloom, glow, lens effects and FXAA / SMAA already were. The alpha-depth pre-pass is also off: the holdout reads the depth after pass 1 as the avatars' opaque surfaces. An RLVa vision sphere still applies; its pass writes opaque pixels, so the layer then has no alpha (logged once). Normal frames are untouched: every change is gated on an avatar-only recording, and the normal tonemap's SPIR-V is byte-identical. All the work is on the GPU: one compute after the warm-up, then one compute and one depth draw per recording. The id pass now runs in the warm-up only. A 1080p shot with 16 antialias frames no longer reads about 200 MB of ids and depth back or loops over them on the CPU, so preview refreshes get cheaper. The occluder costs 4 bytes per pixel of video memory for the shot, allocated softly: without it, walls do not cut avatars (logged). Test-Plan: Snapshot floater, Capture: the transparent avatar layer, Save to disk (PNG); antialias on (default). Open it over a checkerboard or a bright colour in an image editor: - long alpha-blended hair: soft, partly transparent strands, no hard cut and no dark outline; sheer or lace clothing is see-through; - stand behind a table or half behind a wall: the hidden part is cut, the hair in front of the wall keeps its soft edge; - glowing attachments, bloom on: no halo around the avatar in the PNG; - with fog or heavy haze: the avatar keeps its tint, the background is fully transparent; in snow, no ground snow and no flakes in the PNG; - the two matte layers match the PNG's alpha. A colour snapshot of the same view looks as before. With antialias off the layer still has alpha (aliased edges). Test-Settings: SnapshotAntialias = 1, RenderSnapshotTemporalFrames = 16 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>The occluder took the warm-up's depth wherever its avatar-id pass showed none of the layer's avatars. That pass draws the legacy rigged buckets only, and with the cluster LOD path owning rigged meshes (the default) those avatars have no ids. A chosen cluster-drawn avatar's own depth then became its occluder: see-through seams along its internal silhouettes (an arm over the torso, jittered), and the body behind its own hair cut out. Such avatars were also missing from the seen set, so the layer dropped them altogether. The id pass also counted alpha-blended hair at 50 % texel alpha as avatar, which lifted the occluder there: a chosen avatar's legs behind a table showed through its own long hair. The layer no longer uses avatar ids: - the warm-up keeps its opaque depth (no alpha-blend depth pre-pass anywhere in the sequence, so hair is not in it); - each avatar-only recording takes the warm-up's surface at a pixel as one of the layer's avatars when its own avatar-only depth matches it within the tolerance somewhere in the 3x3 pixels around (the recordings are jittered by up to half a pixel). Anything else there is world: the occluder. It covers avatars on the cluster path, avatars the layer leaves out (drawn in the warm-up only) and hair over a table; - depths are compared as linear view distances through the projection's z terms. The 0.5 % tolerance relative to 1/z became about a metre in an orthographic view, where walls and tables close in front of an avatar failed to cut it; - the seen set goes: the per-pixel holdout already cuts an avatar a wall hides entirely. So do the host-written slot bits and the warm-up's id pass. Translucent (alpha-blended) world surfaces, such as glass and blended foliage, no longer cut the avatars; opaque and alpha-masked ones do. Test-Plan: With the default cluster LOD settings (RenderVKClusterLOD and RenderVKClusterRigged on), take the transparent avatar layer of a mesh avatar, antialias on: - no see-through lines along an arm in front of the body, and the head and body behind long hair are whole; - another avatar on the cluster path in "All" or ticked in "Selected" shows in the layer; - stand behind a table with long hair hanging in front of it: the legs behind the table are cut, the hair over the table stays soft; - in the orthographic camera, a wall a few centimetres in front of an avatar cuts it. Test-Settings: RenderVKClusterLOD = 1, RenderVKClusterRigged = 1 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>920d11e3d6to9132304638Rebased onto current main (
9132304638). The only conflict was the test registrations inindra/newview/CMakeLists.txt, and I kept both sides. The commits are otherwise unchanged.Thanks! All of this is on main through the Beta 6 port, with main-side adaptations (plus
287e381f58on top), so merging would only undo those. Closing as landed.Pull request closed