From: Svjatoslav Agejenko Date: Sun, 20 Sep 2026 02:13:15 +0000 (+0300) Subject: Comment/doc truth pass: purge painter-era and double-buffer-era staleness X-Git-Tag: aukio-3d-1.0.0~9 X-Git-Url: http://www2.svjatoslav.eu/gitweb/?a=commitdiff_plain;h=766d099fa2299cb31851eb4c791063e68db1a464;p=aukio-3d.git Comment/doc truth pass: purge painter-era and double-buffer-era staleness Code comments/javadoc now match the z-buffer, triple-buffered reality: - RenderAggregator class javadoc (was painter's algorithm), ctor slot docs - ViewPanel frameContexts/frameParity comments (was double-buffer/parity) - RenderingContext depth comment (dropped dead -Daukio.zbuffer knob and 'Null in classic painter mode' — depth is always allocated) - TexturedTriangle/ShapeCollection/package-info: slot ranges 0..2, javadoc links retargeted off deleted painter span writers - AGENTS.org: removed dead BSP-painter and Agentic-development doc links, added Depth buffer doc, LightmappedCompositeShape + TriangleMeshBlock to the class catalog, render-pipeline overview now describes the radix-sort + two-pass z-buffer flow - TODO.org: dropped completed 'Add 3D mouse support' (SpaceMouse exists) No behavior change. --- diff --git a/AGENTS.org b/AGENTS.org index 2dc0fb8..f383da2 100644 --- a/AGENTS.org +++ b/AGENTS.org @@ -314,6 +314,8 @@ scene.addShape(clickableCube); | Class | File | Purpose | Key Methods | |--------------------------+------------------------------------+-----------------------+-------------------------------------------------------------------------------------------------| | ~AbstractCompositeShape~ | ~base/AbstractCompositeShape.java~ | Group shapes, CSG ops | ~.addShape()~, ~.subtract()~, ~.union()~, ~.intersect()~, ~.setShadingEnabled()~, ~.setColor()~ | +| ~LightmappedCompositeShape~ | ~composite/LightmappedCompositeShape.java~ | Composite that fan-triangulates and optionally carries GI lightmaps | ~.setLightmappingEnabled(true)~ | +| ~TriangleMeshBlock~ | ~basic/texturedpolygon/TriangleMeshBlock.java~ | SoA fast path for large textured triangle meshes (flat double[] arrays, one tight transform loop) | build from mesh data | ** Text (~shapes/composite/textcanvas/~) @@ -402,9 +404,10 @@ AbstractShape (base) #+begin_example ViewPanel.renderFrame() - 1. ShapeCollection.transformShapes() — apply camera transform - 2. ShapeCollection.sortShapes() — sort by Z (back-to-front) - 3. ShapeCollection.paintShapes() — painter's algorithm + 1. ShapeCollection.transformShapes() — apply camera transform, cull, queue + 2. ShapeCollection.sortShapes() — radix sort by Z (back-to-front) + 3. ShapeCollection.paintShapes() — tiled parallel paint, two-pass z-buffer + (opaque front-to-back with depth writes, then alpha back-to-front) 4. BufferStrategy.show() — page flip to display #+end_example @@ -566,9 +569,8 @@ rebuild the exact demo scene headlessly. | ~Documentation/Near plane clip/index.org~ | Near-plane polygon clipping (straddling geometry) | | ~Documentation/Global illumination/index.org~ | Progressive GI: lightmaps, bounces, convergence | | ~Documentation/Perspective correct textures/index.org~ | Texture mapping math | -| ~Documentation/Agentic development/index.org~ | Stub: headless-toolkit docs moved to ~Documentation/index.org~ :: Agentic development | | ~Documentation/Stereoscopic rendering/index.org~ | Side-by-side stereo: two passes, per-eye viewports, IPD | -| ~Documentation/BSP-tree painter's algorithm/index.org~ | BSP compile + rank traversal fixing average-Z sort | +| ~Documentation/Depth buffer/index.org~ | Two-pass z-buffer, zw, depth margin, Hi-Z pyramid, determinism | | ~Documentation/SDF textures/index.org~ | SDF text: glyph fields, coverage window, TextCanvas | Regenerate all HTML: ~Documentation/export-docs.sh~ (add ~--check~ for rendered diff --git a/TODO.org b/TODO.org index 33129ba..1e51ee8 100644 --- a/TODO.org +++ b/TODO.org @@ -1,8 +1,3 @@ -* Add 3D mouse support -:PROPERTIES: -:CUSTOM_ID: add-3d-mouse-support -:END: - * Demos :PROPERTIES: :CUSTOM_ID: demos diff --git a/src/main/java/eu/svjatoslav/aukio/e3d/gui/RenderingContext.java b/src/main/java/eu/svjatoslav/aukio/e3d/gui/RenderingContext.java index 22b90c2..627bc81 100644 --- a/src/main/java/eu/svjatoslav/aukio/e3d/gui/RenderingContext.java +++ b/src/main/java/eu/svjatoslav/aukio/e3d/gui/RenderingContext.java @@ -416,12 +416,12 @@ public class RenderingContext { final DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer(); pixels = dbi.getData(); - // Z-buffer mode (-Daukio.zbuffer=true): one w-depth (biased 1/z) - // value per pixel, cleared per tile in the paint workers. Depth - // turns the queue order into a performance heuristic only; - // correctness comes from the per-pixel test. (The queue itself - // stays painter back-to-front — Z descending, see - // RenderAggregator.) Null in classic painter mode. + // Z-buffer: one w-depth (biased 1/z) value per pixel, cleared per + // tile in the paint workers. Depth turns the queue order into a + // performance heuristic only; correctness comes from the per-pixel + // test. (The queue itself stays painter back-to-front — Z + // descending, see RenderAggregator.) Always allocated: the + // z-buffer path is the only renderer. depth = new float[width * height]; graphics = (Graphics2D) bufferedImage.getGraphics(); diff --git a/src/main/java/eu/svjatoslav/aukio/e3d/gui/ViewPanel.java b/src/main/java/eu/svjatoslav/aukio/e3d/gui/ViewPanel.java index 1b87b20..96bd4bf 100755 --- a/src/main/java/eu/svjatoslav/aukio/e3d/gui/ViewPanel.java +++ b/src/main/java/eu/svjatoslav/aukio/e3d/gui/ViewPanel.java @@ -155,14 +155,15 @@ public class ViewPanel extends Canvas { private RenderingContext renderingContext = null; /** - * Double-buffered frame contexts, indexed by frame parity. While frame N - * is still being painted from one buffer, frame N+1 already transforms - * into the other, so paint threads never idle waiting for the transform - * phase and transform threads never wait for the last tile. + * Triple-buffered frame contexts, indexed by pass counter modulo 3. + * While frame N is still being painted from one buffer, frame N+1 + * already transforms into another, so paint threads never idle waiting + * for the transform phase and transform threads never wait for the + * last tile. */ private final RenderingContext[] frameContexts = new RenderingContext[3]; - /** Parity (0/1) of the frame currently being prepared. */ + /** Slot index (0..2) of the frame context currently being prepared. */ private int frameParity = 0; /** diff --git a/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/RenderAggregator.java b/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/RenderAggregator.java index bb28b67..ad82495 100644 --- a/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/RenderAggregator.java +++ b/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/RenderAggregator.java @@ -19,9 +19,13 @@ import java.util.concurrent.Future; /** * Collects transformed shapes during a render frame and paints them in depth-sorted order. * - *

The {@code RenderAggregator} implements the painter's algorithm: shapes are sorted - * from back to front (highest Z-depth first) and then painted sequentially. This ensures - * that closer shapes correctly occlude those behind them.

+ *

Shapes are sorted from back to front (highest Z-depth first). Under the + * (unconditional) z-buffer, occlusion correctness comes from the per-pixel + * depth test; the queue order is a performance and coherence heuristic: + * pass 1 paints opaque shapes front-to-back (queue reversed) so the depth + * test rejects hidden fragments before the texture fetch, pass 2 paints + * alpha shapes back-to-front without depth writes so translucent overlap + * stays painter-coherent.

* *

When two shapes have the same Z-depth, their unique {@link AbstractCoordinateShape#shapeId} * is used as a tiebreaker to guarantee deterministic rendering order.

@@ -44,10 +48,10 @@ public class RenderAggregator { /** * Creates an aggregator bound to a projection buffer slot. Sorting and * tile binning read the shapes' screen state for this slot, so the - * double-buffered pipeline can fill one slot's aggregator while the - * other slot's aggregator is still being painted. + * triple-buffered pipeline can fill one slot's aggregator while the + * other slots' aggregators are still being painted. * - * @param slot the buffer slot (0 or 1) this aggregator serves + * @param slot the buffer slot (0..2) this aggregator serves */ public RenderAggregator(final int slot) { this.slot = slot; @@ -839,7 +843,7 @@ public class RenderAggregator { /** * Comparator that sorts shapes by Z-depth in descending order (farthest first) - * for the painter's algorithm. Uses shape ID as a tiebreaker. + * for the render queue. Uses shape ID as a tiebreaker. */ static class ShapesZIndexComparator implements Comparator, Serializable { diff --git a/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/ShapeCollection.java b/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/ShapeCollection.java index bf99292..5856d6b 100755 --- a/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/ShapeCollection.java +++ b/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/ShapeCollection.java @@ -425,7 +425,7 @@ public class ShapeCollection { /** * Sorts the given buffer slot's queued shapes by Z-depth. * - * @param slot buffer slot to sort (0 or 1) + * @param slot buffer slot to sort (0..2) */ public void sortShapes(final int slot) { aggregators[slot].sort(); @@ -464,9 +464,9 @@ public class ShapeCollection { /** * Slot-selecting variant of * {@link #binShapesForTiles(int, int, int, int, int, ExecutorService)} - * for the double-buffered pipeline. + * for the triple-buffered pipeline. * - * @param slot buffer slot whose queue gets binned (0 or 1) + * @param slot buffer slot whose queue gets binned (0..2) * @param tilesX tile columns across the viewport * @param tilesY tile rows down the viewport * @param originX X origin of the tiled viewport (eye offset in stereo) diff --git a/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/package-info.java b/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/package-info.java index a7e5fee..0d6a073 100755 --- a/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/package-info.java +++ b/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/package-info.java @@ -7,7 +7,7 @@ *
  • Wireframe rendering - lines and wireframe shapes
  • *
  • Solid polygon rendering - filled polygons with flat shading
  • *
  • Textured polygon rendering - polygons with texture mapping and mipmap support
  • - *
  • Depth sorting - back-to-front painter's algorithm using Z-index ordering
  • + *
  • Depth sorting - back-to-front Z-index ordering feeding the two-pass z-buffer paint
  • * * *

    Key classes in this package:

    diff --git a/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/shapes/AbstractCoordinateShape.java b/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/shapes/AbstractCoordinateShape.java index 70e466b..94fafb0 100644 --- a/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/shapes/AbstractCoordinateShape.java +++ b/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/shapes/AbstractCoordinateShape.java @@ -77,7 +77,7 @@ public abstract class AbstractCoordinateShape extends AbstractShape { /** * Average Z-depth of this shape in screen space after transformation, * per buffer slot. Used by the {@link RenderAggregator} to sort shapes - * back-to-front for correct painter's algorithm rendering. + * back-to-front (the queue order the two-pass z-buffer paint consumes). * Access via {@link #getZ(RenderingContext)} / {@link #getZ(int)}. */ private double onScreenZ0; diff --git a/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/shapes/basic/texturedpolygon/TexturedTriangle.java b/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/shapes/basic/texturedpolygon/TexturedTriangle.java index fb57245..7d46c34 100644 --- a/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/shapes/basic/texturedpolygon/TexturedTriangle.java +++ b/src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/shapes/basic/texturedpolygon/TexturedTriangle.java @@ -211,14 +211,14 @@ public class TexturedTriangle extends AbstractCoordinateShape { } /** - * Z-buffer variant of {@link #drawHorizontalLinePerspective}: the - * biased 1/z endpoint values ride the interpolators' zw channel, and - * every pixel is depth-tested BEFORE the texture fetch — rejected - * pixels cost one float compare instead of a texel read. Opaque - * texels (alpha 255) write depth; blended texels write color only, - * so translucency never occludes. Requires - * {@code renderBuffer.depth != null} and {@code setPointsZW} called - * on both interpolators. + * Z-buffer span writer: the biased 1/z endpoint values ride the + * interpolators' zw channel, and every pixel is depth-tested BEFORE + * the texture fetch — rejected pixels cost one float compare instead + * of a texel read. Opaque texels (alpha 255) write depth; blended + * texels write color only, so translucency never occludes. + * {@code renderBuffer.depth} is always allocated (the z-buffer path + * is the only renderer); requires {@code setPointsZW} called on both + * interpolators. */ private void drawHorizontalLinePerspectiveZ( final PerspectiveBorderInterpolator line1, @@ -315,10 +315,10 @@ public class TexturedTriangle extends AbstractCoordinateShape { // Alpha pass (depthPass 2): depth-test but never depth-write, // so cutout foliage cannot occlude later fragments final boolean writeDepth = renderBuffer.depthPass != 2; - // see drawHorizontalLine: null texture (unit tests) = clamp + // null texture (unit tests) = clamp final boolean wrap = texture != null && texture.wrap; - // Same adaptive-subdivision ladder as the painter variant + // Adaptive-subdivision perspective ladder (Quake-style stepping) final double ue1 = su1 / sw1; final double ue2 = su2 / sw2; final double ve1 = sv1 / sw1; @@ -1087,7 +1087,7 @@ public class TexturedTriangle extends AbstractCoordinateShape { /** * SDF scanline with Quake-style subdivided perspective correction — - * same stepping structure as {@link #drawHorizontalLinePerspective}, + * same stepping structure as {@link #drawHorizontalLinePerspectiveZ}, * with the coverage fetch replaced by the distance-field evaluation. */ private void drawHorizontalLinePerspectiveSdf( @@ -1305,9 +1305,9 @@ public class TexturedTriangle extends AbstractCoordinateShape { } /** - * Z-buffer variant of {@link #drawHorizontalLine}: per-pixel depth - * test (biased 1/z, linear along the span) BEFORE the texture fetch. - * Opaque texels write depth; blended texels write color only. + * Z-buffer span writer: per-pixel depth test (biased 1/z, linear + * along the span) BEFORE the texture fetch. Opaque texels write + * depth; blended texels write color only. */ private void drawHorizontalLineZ(final PolygonBorderInterpolator line1, final PolygonBorderInterpolator line2,