Skip to content

v0.2.1 — the blank-render fix

Choose a tag to compare

@musharna musharna released this 01 Aug 00:07
d0d41cd

0.2.0 rendered a uniform grey frame with no model in it for small models — anything spanning less than ~4.5 cm, roughly 11 studs. This release fixes that. (This sentence originally read “for every input”; see the correction at the bottom.)

What was wrong

The camera distance was derived from the scene bounds; the camera clip planes were not. ImportLDraw imports at real-world metre scale — two 2×4 bricks genuinely span 3.2 cm — so distance = span * 2.2 placed the camera 7 cm from the model, inside Blender's default clip_start of 0.1 m. Every mesh was clipped away before shading, and the frame rendered as the bare white world, which AgX maps to a plausible grey.

Nothing failed along the way. The import succeeded (472 vertices per brick, nothing hidden from rendering), Blender exited 0, and the PNG was well-formed. The fault was a parameter that was never set, so no line of code reads wrong on inspection — only rendering and measuring the pixels found it.

The fix

Both clip planes are now derived from the same distance the camera position already uses. That holds at any model scale, rather than special-casing small models with a fixed tiny near plane that would quietly cost depth precision on large ones.

Measured on an otherwise identical scene:

max pixel deviation pixels differing >40
clip_start = 0.1 (before) 6 0 / 40000
derived from span 195 13010 / 40000

Verified from the built wheel in a clean environment, not just the source tree: max deviation 412, 105023 of 320000 pixels.

Also

  • The blank-frame eval's control had never run in CI. It sat under a module-level skipif(not is_available()) and CI runners have no Blender, so the one check proving the detector can tell a blank frame from a drawn one was skipped exactly where it mattered — while its docstring claimed it ran without a renderer. The skip now applies only to the test that drives Blender, and numpy (which that control imports) joins the test extra instead of being present by luck.
  • server.json's fourth version copy is now guarded. _meta.publisher-provided.version was not covered by the version-sync test that exists precisely because unchecked version sources drift.

Fixes #14.


Correction (2026-08-01)

This note originally said the bug affected "every input". Measured, that is false: the
failure is size-dependent. A model is clipped only when span * 2.2 falls below
Blender's default 0.1 m near plane — about 4.5 cm, roughly 11 studs across.

Measured on 0.2.0's own code:

model span camera distance result
single 2×4 brick 32 mm 0.070 m blank — 0 pixels differ from background
two bricks, 56 mm apart 56 mm 0.123 m renders correctly
two bricks, 192 mm apart 192 mm 0.422 m renders correctly

So small models — the single part, the demo, the test case — were broken, while larger
builds were always fine.

The same correction applies to 0.1.0, 0.1.1 and 0.1.2: none of them set the clip planes
either (verified against the published 0.1.0 sdist, which has no git tag), so every release
before 0.2.1 carries the defect under that size threshold.

Separately, main now rejects a blank render instead of returning it as a success — the
render path had no output postcondition, which is why this shipped invisibly in the first
place (#18).