Commit Graph
6 Commits
Author SHA1 Message Date
KenM76andClaude Opus 5.5 c2d8c5f327 M12: prc-render: fully transparent triangles are not framed
Review fix from #6087. Bounds::of and Camera::fit_meshes framed every
finite triangle, but render skips those whose colour has zero alpha, so a
clear, distant mesh could shrink the visible model in the image. The
vertices they frame now skip fully transparent triangles, as render does.

Test, shown failing with the fix reverted:
a_fully_transparent_triangle_does_not_widen_the_box_or_the_fit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmHYx8FiWM5PcsoiErgp9
2026-11-04 06:53:36 -05:00
KenM76andClaude Opus 5.5 51b68a8b35 M12: prc-render: overflow-free projection and edges, shared near cuts, decode ceiling
- View::project divides by z (or the orthographic half-height) before it
  multiplies, so an on-screen corner no longer turns NaN when x times the
  focal length, or the half-height times the aspect ratio, overflows.
- View::clip cuts each edge from the same end whichever triangle meets it,
  so two triangles sharing an edge across the near plane get one cut point.
- Scene::draw takes each edge with vec3::span, which halves the
  difference when it overflows, so a finite triangle wider than f64::MAX
  keeps its face normal.
- assemble charges each file structure's meshes to the assembly ceilings
  as they are decoded, so decoding stops at the structure that passes one.

Tests, each shown failing with its fix reverted:
a_shared_edge_is_cut_at_the_same_point_from_either_triangle,
an_on_screen_triangle_is_drawn_when_projecting_it_would_overflow,
a_triangle_whose_edges_overflow_is_drawn,
span_keeps_the_direction_of_a_difference_that_overflows,
decoding_stops_at_the_structure_that_passes_the_ceiling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmHYx8FiWM5PcsoiErgp9
2026-11-04 05:12:00 -05:00
KenM76andClaude Opus 5.5 c336c59cfb M12: prc-render: scale-safe lengths, a render work ceiling, fit fixes
- vec3: length divides by the largest component before squaring, so
  a camera 1e200 away keeps a finite near plane; unit_cross normalizes
  each edge first, so edges of very different sizes keep their normal.
- render: MAX_RENDER_WORK (2^31) caps the pixel centres one render
  tests, charged per triangle's clipped bounding box before scanning;
  past it, RenderError::TooMuchWork.
- Bounds::centre halves each end before adding, finite for any finite
  box. Bounds::of and fit_meshes use only corners of triangles render
  draws. Camera::frame builds its basis from the direction, not from
  points near the model, so a small model far from the origin fits.

Each new test fails with its fix reverted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmHYx8FiWM5PcsoiErgp9
2026-11-04 00:03:28 -05:00
KenM76andClaude Opus 5.5 ca21d4fb7b M12: prc-render: scale a triangle's edges before their cross product
normalize already scales by the largest component, but the face normal
was the normalized cross product of two edges, and edges near 1e160
overflow that product to infinity first, so the triangle was dropped.
unit_cross divides both edges by their largest component before the
cross product. a_huge_square_is_drawn fails with the old line (white
instead of [190,192,200]).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmHYx8FiWM5PcsoiErgp9
2026-11-03 23:06:54 -05:00
KenM76andClaude Opus 5.5 ce393b276b M12: prc-render review fixes (missing tessellations, vertex ceiling, seams, perspective shade)
- assemble: a placement naming a tessellation its file structure does not
  have is now PrcError::Malformed instead of a silently missing part;
  wires, markups and compressed tessellations are still skipped.
- assemble: positions, normals and texture coordinates are charged against
  a new MAX_ASSEMBLED_VERTICES (2^24) with RenderError::TooManyVertices, so
  a one-triangle mesh with many vertices placed many times cannot outgrow
  the triangle ceiling's memory bound. A refused mesh spends nothing.
- raster: a field of view too small for a finite focal length is a Camera
  error, not a background-only image.
- raster: a pixel centre exactly on an edge belongs to one triangle only
  (the side the triangle lies on, +x first, then +y), so translucent
  quads no longer blend their diagonal twice.
- raster: under a perspective camera the shade is interpolated with the
  1/z depth key, so it follows the surface rather than the screen.
- vec3: normalize divides by the largest component first, so a cross
  product above ~1e154 (or a subnormal one) still normalizes.
- render docs and README state the near plane: 1/10,000 of the
  eye-to-target distance.

Each new test fails with its fix reverted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmHYx8FiWM5PcsoiErgp9
2026-11-03 21:41:05 -05:00
KenM76andClaude Opus 5.5 ea6d0c6bfb M12: pdfcraft-prc-render, a headless renderer for PRC models
New L3 crate over pdfcraft-prc: assemble places every product-tree
tessellation into world space with its colours (pure `place` does the
transform), Camera fits a view to the model, and render fills
depth-buffered triangles with headlight or unlit shading into an RGBA
image. Opaque triangles draw first, translucent ones blend over them;
perspective views clip at a near plane.

Never panics: MAX_RENDER_PIXELS and MAX_ASSEMBLED_TRIANGLES cap the
work, every pixel and vertex index is checked, and damage returns
RenderError. Single-threaded.

Tests: 24 unit tests (two drive the product-tree placement path) plus an end-to-end one that builds a synthetic
PRC stream in-test, renders it, and checks the background, the nearer
triangle and the farther one by pixel; every truncation of that stream
parses and assembles without panicking. Reverting the depth test or the
placement transform fails the matching tests.

Adapted from pdfcer (MIT, same author) at 912437c3, trimmed to
the camera, raster and headlight parts and rewritten to the
pdfcraft-prc types.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmHYx8FiWM5PcsoiErgp9
2026-11-03 20:50:36 -05:00