Visibility
Planned order inside the GPU-driven milestone (P5):
- Frustum culling of meshlet spheres against the camera (JRV-0026). Accepted 2026-09-25. The test reads the uploaded bounds. It does not walk triangles. The RHI compute pass is still unsupported, so this reference runs on the CPU and the meshlet draw submits only the passing clusters.
- Occlusion of those surviving meshlet spheres (JRV-0027). Accepted 2026-09-26 for conservative correctness, not for occlusion efficiency. This is the CPU conservative occlusion reference. A closer sphere used to reject the visible front of townshop. The reference now keeps any cluster it cannot prove is hidden. It splats the far side of a sphere into a 64 by 36 reversed-Z buffer, builds a min mip chain, and rejects a cluster only when every base sample and the mip over its whole rect are clearly in front of that cluster's near side. Reversed-Z treats a larger stored value as closer. A cluster whose sphere crosses the near plane or the camera plane stays submitted even when a side plane would reject its center. A cluster that sits partly off screen, projects to fewer than 2 pixels or more than 12, or otherwise has an ambiguous bound is flag 4 and is still drawn. It is not used as an occluder. Flag 1 is visible, flag 3 is occluded, flag 0 is a frustum reject. The pyramid is meshlet bounds, not the rendered image, and there is no GPU dispatch. Production visibility, after this correctness stage passes, is GPU scene, frustum, a depth-pyramid occlusion test, screen-space error and hierarchy selection, residency, then indirect meshlet submission. Production GPU occlusion, page streaming, and RFC-0002 stay unstarted. RFC-0001 hierarchy selection is a separate acceptance. Its parent-geometry slice is not accepted.
- Cluster LOD. Hierarchy selection over the accepted meshlets is human accepted. A later slice stores simplified parent triangles and draws a selected parent instead of its leaves. That slice is not accepted. See virtual-geometry.md.
Do not drop whole entities on the CPU and call that hierarchical-Z. Builtins have no meshlet records, so the floor, the triangles, and the spheres are not occluders in this test. The shop can hide its own farther clusters. Virtual geometry and page streaming are not part of this test.
View > Frustum Cull Meshlets and View > Occlusion Cull Meshlets are on by default. Occlusion runs only while frustum culling is also on. The status line shows instances visible/total, meshlets submitted/total, frustum rejects, occlusion rejects, triangles in the submitted clusters, and the CPU time for both tests. On the 2026-09-25 debug editor that CPU time was 82–147 ms. That number is the reference cost. It is not a budget for the shipping path. Turning frustum culling off submits every stored meshlet. Turning occlusion off keeps the frustum result and clears the occlusion rejects.
View > Show Meshlet Colors paints the classification over whichever draw is active. It does not require Draw From Meshlets. Visible clusters are green, conservative-visible clusters are amber, frustum rejects are red, and occluded clusters are blue. A cluster the cut never classified is magenta. An opaque overlay culls back faces. A two-sided material still draws both sides. Amber is drawn by the meshlet path. Blue is not. The status cons count is the amber set. From far away, most townshop clusters are smaller than 2 pixels on the 64 by 36 buffer, so cons is high and occ is low. That is the reference choosing to draw. A hole in the yellow canopy while this overlay is on is not an occlusion reject. Townshop's material is double-sided, and the shaded path already keeps both sides.
Acceptance for this correctness stage is a pair of shots from the same camera. Leave frustum and occlusion on. Turn Show Meshlet Colors off. One shot is Draw From Meshlets on, so the submitted clusters use the imported material. The other shot is Draw From Meshlets off, which is the ordinary indexed mesh and is never culled. Orbit the awning edges, hanging cloth, ropes, signs, railings, wheel, windows and doorways, roof silhouette, underside, and thin trim. There should be no hole, missing silhouette piece, delayed reveal, flicker, or pop on a small camera move. Hide part of the shop behind foreground geometry, then move sideways until it is visible again. Rejected meshlets have to return on that move. The first material pair dropped the facade with fru 0 and occ 42236. After the conservative correction, later Intel UHD views keep the canopy from above, from the side, and from underneath on the ordinary draw, with occ 0 in each. The underside shots include 57498/61702 at 61.9 ms and, with the shop raised, 60400/61702 at 90.3 ms on colors off | draw original. The yellow meshlet shots at that raised height were 61681/61702 and 60979/61702, also occ 0. Those are not the four-state fixed-camera comparison. The canopy is visible because the shared standard master draws both sides. Townshop's only material is doubleSided: true and alphaMode: OPAQUE, the node is identity, and a negative scale is what would flip winding. The meshlet color overlay used to cull back faces and now draws both sides. Acceptance is still one unmoved camera in the four states below.
Streaming feedback (which pages were wanted but missing) belongs in this stage once virtual resources exist. The world streaming priority function is a CPU heuristic for cells, not a substitute for GPU visibility.
Per-view cluster cut
The cut belongs to the camera that asked for it. It is not a flag on the mesh, and it does not remove the entity, the collider, or any other view's result.
For one RenderView the order is: the cluster hierarchy, then frustum rejection of a whole subtree, then hierarchical depth, then the screen-space LOD cut on what remains. A parent cluster is drawn only when every leaf it stands for is visible to that view and the parent triangles contain every child center. A parent that fails that coverage test is not submitted, and its leaves are. A new build does not pack a parent whose bounds miss the children. A sidecar already on disk is judged again when it is uploaded, so a bad parent does not stay in the cut. A hidden or off-screen branch submits no triangles even when another branch of the same mesh is on screen. A distant visible branch may use its parent. A close visible branch uses finer nodes. Anything the occlusion test cannot prove is hidden stays drawn. Page streaming is not part of this cut. Einstein detail is a separate mode, ADR-0061, and is not forced on by visibility. Einstein does not repair a hole in the base mesh.
View > Pipeline and View > Visualization are two radios. The pipeline chooses the triangles. The visualization only recolors those triangles. View > Freeze Diagnostic Frame keeps the editor camera where it is and reuses that cut, including the Einstein account already captured, until the pipeline changes or the freeze is cleared. View > Reset Rendering Debug sets Pipeline to Normal and Visualization to None, clears the freeze, and turns frustum, occlusion, and the cluster hierarchy back on.
While a pipeline other than Normal is selected, Show Meshlet Colors, Draw From Meshlets, Frustum Cull Meshlets, Occlusion Cull Meshlets, Freeze Meshlet Visibility, Cluster Hierarchy, and Microtriangle Colors leave those switches alone. The pipeline owns them until Normal or Reset.
Leaf Truth draws every leaf meshlet of the selected mesh in a stable color. Hierarchy, frustum, and occlusion are off for that view. The ordinary index buffer is not drawn under those leaves. Frustum Only is that same leaf set with camera-frustum rejection enabled and nothing else. A cluster outside the frustum is not drawn. A cluster inside it stays a leaf. Hierarchy (no occlusion) enables the parent cut and frustum, and leaves occlusion off. The scene should stay geometrically complete. uncov above 0, or a hole in that view, is parent coverage. Hierarchy + Occlusion adds the CPU hierarchical-Z. Geometry may disappear only when nearer opaque geometry proves it hidden for this view. False-visible is allowed. False-hidden is not. Depth-writing Einstein meshes are suspended for every pipeline other than Normal. A visualization may still recolor the cut.
Cut Reasons, Hierarchy Levels, and the Einstein class colors do not change which triangles are submitted. They recolor the pipeline's own draw: the same vertex buffer, the same index buffer, the same index range, and the same depth write. Cut Reasons paints submitted clusters green when visible and amber when conservative. Magenta was not classified. Occluded clusters stay in the status count and are not drawn as a second mesh. Hierarchy Levels paints those same triangles by parent level. Cyan is a fine node. Yellow and orange are coarser parents. A parent packet keeps the 60-byte parent vertex buffer. It is not read at a 24-byte stride, and it is not a second mesh. Each submitted run stores its first triangle before the color pass, and that draw reads its own record. A reflection-probe capture keeps the shaded material and does not take the diagnostic shader. At a frozen camera, switching visualization keeps the same triangle ids, the same depth buffer, and the same cut. Only the colors change. The status line names the pipeline and the visualization, and it counts legacy, meshlet, parent, and micro triangles. uncov is leaves the cut neither drew nor covered. Acceptance for the cut is uncov 0.
Einstein Active Detail, Eligible Surfaces, LOD / Error, State, and Reject Reason recolor surfaces the selected pipeline submitted. They do not return the pipeline to Normal and they do not build a new cut. Detail Debug is an overlay on that same cut. It tests scene depth and does not write depth. Gray on an Eligible surface is a submitted cluster that is not a detail candidate. A cluster the pipeline did not submit is left unpainted, so gray is not a missing triangle. While microgeometry is on, the status line accounts for every drawn cluster: elig = det + below + def + unsup, and unclass stays 0. Clusters that are a hierarchy parent, occluded, outside the frustum, or an incompatible material stay in their own counters. miss 0 only means every requested patch arrived. It is not a claim that every visible surface received detail. req, ready, and pub separate a request from a published patch. That account does not change which clusters are selected and does not raise the patch budget. Einstein State paints the same packets by lifecycle: drawn, pending, rejected, or not eligible. A parent shell in that view is not eligible. The status line also prints ein eligible, drawn, rejected, pending, and unclassified. For that tighter set, unclassified is 0 and eligible = drawn + pending + rejected.
compare_pipeline_coverage projects the same cluster bounds for Leaf Truth, Frustum Only, the in-frustum leaf set, and hierarchical occlusion. It reports visible pixels, submitted triangles, selected leaves, selected parents, frustum rejects, and occlusion rejects. Frustum may drop a cluster only when its bounds miss the camera. A leaf pixel that is inside the frustum and becomes background in the hierarchy mask is a coverage failure. Occlusion may drop a pixel only when a nearer drawn cluster covers it. This mask is a CPU disc of cluster bounds. It does not build parent triangles and it is not a GPU framebuffer. Parent coverage remains the parent-mesh test.
View > Compare Against Leaf Truth rasters the triangles each pipeline stage would submit. The stages are Leaf Truth, Frustum Only, Hierarchy (no occlusion), Hierarchy + Occlusion, and Normal. One flat depth test is used. Diagnostic colors are not an input. The raster may be smaller than the window. The parent cut still uses the window height. A stage may submit fewer triangles. It may drop off-screen geometry, back faces, and a surface that is fully behind something nearer. It may not leave empty a pixel Leaf Truth covered. The image is black where coverage matches, red where Leaf Truth has a pixel and the stage does not, and blue where the stage covers a pixel Leaf Truth leaves empty. Red is the defect. The first stage with a red pixel owns it. Normal in this compare is the shipping base cut. Einstein triangles are not in the buffer. Parent positions are kept on the CPU up to 2,000,000 vertices so the raster can draw a parent. Above that cap the hierarchy stages are reported as not compared. The images go to C:\temp\jarvig_debug as leaf-compare-*.bmp. This is not a GPU framebuffer and it does not read the depth target.
An opaque color overlay culls back faces, so the back of a coarse parent shell does not paint through the shaded mesh. A two-sided material still draws both sides. That is what keeps a double-sided canopy visible from below.
Hierarchical depth
The view path calls hierarchical_occlusion_cull. The buffer is half the viewport, even, clamped to 96–384 by 54–216. It stores the far side of a cluster sphere in reversed-Z and keeps a min mip chain. An occluder writes texels inside its bounding circle, which is the smaller radius/depth estimate, so a square does not cover a neighbor. A cluster is rejected only when every sample inside its expanded silhouette is clearly in front of its near side. Near-plane crossings, sub-2-pixel bounds, partial off-screen bounds, and non-finite depth stay conservative and are not used as occluders. A large on-screen cluster is tested. The JRV-0027 function occlusion_cull_meshlets is still the 64 by 36 reference with the 12 px and 16 px caps. The renderer does not call that reference for a view.
An actor whose clusters fit in one sphere is rejected together when that sphere is fully outside the frustum, or when the hierarchical test proves the whole sphere hidden. A sphere that only partly overlaps the frustum or the depth buffer falls through to the clusters. One mesh can therefore be partly visible. The test does not remove the entity.
This is a CPU hierarchical-Z of cluster bounds. It does not read the depth target, does not dispatch a compute shader, and is not a GPU HZB. Page streaming stays unstarted. False-visible is allowed. False-hidden is not. Einstein and microgeometry debug draws test that same scene depth and cull back faces. They are not a second visibility pass and they do not build a GPU pyramid.
The status line reports candidate clusters, frustum rejects, occlusion rejects, conservative clusters, selected parents, selected leaves, submitted triangles, and the buffer size as hz WxH. View > Show Meshlet Colors paints the same four results: green visible, amber conservative, red frustum, blue occluded. That overlay is not replaced by the LOD colors while it is on.