From 7fff9256f21844eacdb1db3abf810eb938784e51 Mon Sep 17 00:00:00 2001 From: fOuttaMyPaint Date: Sun, 19 Jul 2026 21:56:02 -0400 Subject: [PATCH] fix: make uv-layer-grid self-witness its render and restage the clipped hero MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The still was the visual proof of the hazard but nothing asserted its pixels, and both panels were clipped by the frame. The script now re-reads its own render at each panel's projected center — the hazard panel must be one flat teal (spread <= 0.02, b>g>r) and the repair a high-contrast checker (spread >= 0.25) — falsified twice with measured errors. Restaged per VISUAL-STYLE: both panels fully in frame and grounded, contained warm wedge, mean luminance 0.274 inside the calibration range. Verified live on 5.1.2 and 4.5.11 LTS. Signed-off-by: fOuttaMyPaint --- README.md | 3 +- docs/gallery/assets/uv-layer-grid-hero.webp | Bin 18284 -> 20086 bytes .../contact-sheets/uv-layer-grid-restage.webp | Bin 0 -> 50456 bytes docs/gallery/index.html | 2 +- docs/gallery/uv-layer-grid/index.html | 117 +++++++++++++++--- examples/gallery.json | 2 +- examples/uv-layer-grid/README.md | 11 +- examples/uv-layer-grid/preview.webp | Bin 16472 -> 14614 bytes examples/uv-layer-grid/uv_layer_grid.py | 111 ++++++++++++++--- 9 files changed, 205 insertions(+), 41 deletions(-) create mode 100644 docs/gallery/contact-sheets/uv-layer-grid-restage.webp diff --git a/README.md b/README.md index 64cfb5e..ab4aaac 100644 --- a/README.md +++ b/README.md @@ -213,7 +213,8 @@ result is watertight (every edge borders exactly two faces). `bmesh.ops.create_grid(..., calc_uvs=True)` is a silent no-op unless a UV layer already exists — without one an Image Texture samples texel (0, 0) everywhere. Asserts the hazard, -the pre-create repair against closed-form grid UVs, and an explicit assignment fallback. +the pre-create repair against closed-form grid UVs, and an explicit assignment fallback — +then re-reads its own render and fails unless the pixels prove the flat-vs-checker split. diff --git a/docs/gallery/assets/uv-layer-grid-hero.webp b/docs/gallery/assets/uv-layer-grid-hero.webp index b44dbeb0b9e5b2e87d412fed51aea61cf3891ff8..9de215024e3c8ad8faef133d5cdb0eafa844f56a 100644 GIT binary patch literal 20086 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 literal 18284 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 diff --git a/docs/gallery/contact-sheets/uv-layer-grid-restage.webp b/docs/gallery/contact-sheets/uv-layer-grid-restage.webp new file mode 100644 index 0000000000000000000000000000000000000000..966ca21dea98e27694f1d0b9136ed1aff42a9211 GIT binary patch literal 50456 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

uv-layer-grid

The UV-layer authoring hazard — bmesh.ops.create_grid(..., calc_uvs=True) is a silent no-op unless a UV layer already exists; without one an Image Texture samples texel (0,0) everywhere.

-

witnesses calc_uvs=True alone leaves 0 UV layers; pre-create + calc_uvs fills loops to the closed-form grid UVs ((x/size+1)/2, (y/size+1)/2) within 1e-6; explicit loop assignment is the calc_uvs-free fallback.

+

witnesses calc_uvs=True alone leaves 0 UV layers; pre-create + calc_uvs fills loops to the closed-form grid UVs ((x/size+1)/2, (y/size+1)/2) within 1e-6; explicit loop assignment is the calc_uvs-free fallback. The still is self-witnessing: the script re-reads its render and exits non-zero unless the hazard panel is one flat teal and the repaired panel a high-contrast checker.

View example
diff --git a/docs/gallery/uv-layer-grid/index.html b/docs/gallery/uv-layer-grid/index.html index 69b6189..e4a6058 100644 --- a/docs/gallery/uv-layer-grid/index.html +++ b/docs/gallery/uv-layer-grid/index.html @@ -177,7 +177,7 @@

uv-layer-grid

uv-layer-grid render

Rendered headless by the example itself — click to zoom.

-
witnesses calc_uvs=True alone leaves 0 UV layers; pre-create + calc_uvs fills loops to the closed-form grid UVs ((x/size+1)/2, (y/size+1)/2) within 1e-6; explicit loop assignment is the calc_uvs-free fallback.
+
witnesses calc_uvs=True alone leaves 0 UV layers; pre-create + calc_uvs fills loops to the closed-form grid UVs ((x/size+1)/2, (y/size+1)/2) within 1e-6; explicit loop assignment is the calc_uvs-free fallback. The still is self-witnessing: the script re-reads its render and exits non-zero unless the hazard panel is one flat teal and the repaired panel a high-contrast checker.
blender --background --python examples/uv-layer-grid/uv_layer_grid.py --
@@ -188,9 +188,9 @@

uv-layer-grid

What it witnesses: three related contracts on the same grid topology (SEG×SEG faces, (SEG+1)² verts, size 1.0 → coords in [-1, 1]):

1. Silent no-opcreate_grid(..., calc_uvs=True) with no prior bm.loops.layers.uv.new(...) leaves len(bm.loops.layers.uv) == 0 and mesh.uv_layers empty after to_mesh. 2. Pre-create repair — create the UV layer first, then calc_uvs=True fills every loop. UVs must match the closed form u = (x/size + 1)/2, v = (y/size + 1)/2 within 1e-6, both on the BMesh and after persisting to mesh.uv_layers.active.data. 3. Explicit assignment fallbackcalc_uvs=False, then uv.new("UVMap") and a loop write of the same closed form. Does not depend on calc_uvs at all; same tolerance.

What each check catches on failure:

-
  • *Silent no-op* — calc_uvs=True starts creating a layer on its own (falsified: expecting n_layers == 0 fails if a layer appears; temporarily pre-creating a layer before the hazard probe exits 3).
  • *Topology* — create_grid segment/size contract drift (wrong face/vert counts).
  • *Closed-form UVs* — calc_uvs filling a different parameterization, or a one-texel shift (falsified: adding 0.1 to every U exited 6 with measured error 0.1).
  • *Mesh persistence* — UV layer or loop data lost across to_mesh.
  • *Explicit path* — loop assignment or the closed form itself regressing.
+
  • *Silent no-op* — calc_uvs=True starts creating a layer on its own (falsified: expecting n_layers == 0 fails if a layer appears; temporarily pre-creating a layer before the hazard probe exits 3).
  • *Topology* — create_grid segment/size contract drift (wrong face/vert counts).
  • *Closed-form UVs* — calc_uvs filling a different parameterization, or a one-texel shift (falsified: adding 0.1 to every U exited 6 with measured error 0.1).
  • *Mesh persistence* — UV layer or loop data lost across to_mesh.
  • *Explicit path* — loop assignment or the closed form itself regressing.
  • *Pixel witness* (with --output) — the saved PNG is read back and probed at each panel's projected center: the hazard panel must be one flat teal (per-channel spread ≤ 0.02, ordering b>g>r), the repaired panel a high-contrast checker (spread ≥ 0.25). Falsified twice: secretly giving the hazard panel UVs exited 11 with measured spread 0.7333; repainting texel (0,0) magenta exited 12 with measured rgb (0.927, 0.118, 0.536).

Version divergence: none probed — the silent no-op and closed-form UV fill assert identically on Blender 4.5 LTS and 5.1. The only gate in the file is the EEVEE engine id for the optional render (BLENDER_EEVEE_NEXT on 4.x, BLENDER_EEVEE on 5.x).

-

Render: two easel panels sharing one neon checker image. Left is the hazard (no UV layer) — flat teal of texel (0, 0). Right is the repair (pre-create + calc_uvs) — full magenta/cyan checker. If the UV contract failed, both panels would read the same.

+

Render: two easel panels sharing one neon checker image. Left is the hazard (no UV layer) — flat teal of texel (0, 0). Right is the repair (pre-create + calc_uvs) — full magenta/cyan checker. If the UV contract failed, both panels would read the same — and the still is not just an illustration: the script re-reads its own render and exits non-zero unless the pixels prove the flat-vs-checker split (measured on 5.1.2: hazard spread 0.0078, repair spread 0.7294).

Run

# Cheap correctness check (no render) — the CI check:
 blender --background --python uv_layer_grid.py --
@@ -218,7 +218,10 @@ 

Source

repair path against a closed-form UV grid, and an explicit loop-assignment fallback that does not depend on `calc_uvs` at all. Pass --output to also render a still that stages the broken (flat) panel beside the repaired -(checker) panel so the failure mode is visible at a glance: +(checker) panel — and then *witnesses the render itself*: the saved PNG is +read back and probed at each panel's projected center, asserting the broken +panel is one flat teal (texel (0,0)) while the repaired panel carries both +checker colors. If the UV contract failed, the pixels would say so: blender --background --python uv_layer_grid.py -- blender --background --python uv_layer_grid.py -- --output uv.png @@ -374,7 +377,7 @@

Source

def make_uv_testcard(name, w=256, h=256): - """Neon checker + corner marker. Texel (0,0) is a flat teal so a missing UV + """Neon checker whose single texel (0,0) is a flat teal, so a missing UV layer reads as one solid color instead of a bright false-positive checker.""" img = bpy.data.images.new(name, w, h, alpha=False) px = [0.0] * (w * h * 4) @@ -451,15 +454,13 @@

Source

# Left: the hazard — calc_uvs alone, no UV layer → flat teal of texel (0,0). broken = textured_plane("Broken", card, with_uvs=False) - broken.location = (-1.22, 0.0, 1.18) - broken.rotation_euler = (math.radians(62), 0.0, math.radians(10)) - broken.scale = (1.15, 1.15, 1.15) + broken.location = (-1.18, 0.0, 0.94) + broken.rotation_euler = (math.radians(62), 0.0, math.radians(8)) # Right: the repair — pre-create UV layer, then calc_uvs fills it. fixed = textured_plane("Fixed", card, with_uvs=True) - fixed.location = (1.22, 0.0, 1.18) - fixed.rotation_euler = (math.radians(62), 0.0, math.radians(-10)) - fixed.scale = (1.15, 1.15, 1.15) + fixed.location = (1.18, 0.0, 0.94) + fixed.rotation_euler = (math.radians(62), 0.0, math.radians(-8)) floor_me = bpy.data.meshes.new("Floor") bm = bmesh.new() @@ -498,20 +499,21 @@

Source

ob.rotation_euler = tuple(math.radians(a) for a in rot) scene.collection.objects.link(ob) - light("Key", (-3.8, -4.8, 5.8), 360.0, 4.5, (1.0, 0.96, 0.9), (52, 0, -32)) - light("Fill", (4.8, -2.8, 1.6), 70.0, 9.0, (0.75, 0.85, 1.0), (72, 0, 52)) - light("Rim", (0.2, 4.0, 2.8), 220.0, 3.2, (0.6, 0.78, 1.0), (-62, 0, 178)) - # Between the panels and the wall so it only rakes the backdrop. - light("Wedge", (0.5, 5.2, 2.8), 520.0, 7.0, (1.0, 0.72, 0.42), (-78, 0, 180)) + light("Key", (-3.8, -4.8, 5.8), 300.0, 4.5, (1.0, 0.96, 0.9), (52, 0, -32)) + light("Fill", (4.8, -2.8, 1.6), 55.0, 9.0, (0.75, 0.85, 1.0), (72, 0, 52)) + light("Rim", (0.2, 4.0, 2.8), 90.0, 3.2, (0.6, 0.78, 1.0), (-62, 0, 178)) + # Between the panels and the wall so it only rakes the backdrop: a + # contained warm pool, corners falling off to dark. + light("Wedge", (0.3, 5.4, 1.9), 380.0, 3.6, (1.0, 0.68, 0.38), (-72, 0, 180)) aim = bpy.data.objects.new("Aim", None) - aim.location = (0.0, 0.0, 1.1) + aim.location = (0.0, 0.0, 0.95) scene.collection.objects.link(aim) cam_data = bpy.data.cameras.new("Cam") cam_data.lens = 45.0 cam = bpy.data.objects.new("Cam", cam_data) - cam.location = (0.0, -5.4, 2.2) + cam.location = (0.0, -6.6, 2.1) con = cam.constraints.new("TRACK_TO") con.target = aim con.track_axis = "TRACK_NEGATIVE_Z" @@ -537,6 +539,77 @@

Source

return os.path.exists(path) and os.path.getsize(path) > 0 +def patch_stats(px, w, h, cx, cy, half): + """Mean RGB and per-channel min/max spread of a (2*half)^2 pixel patch.""" + sums = [0.0, 0.0, 0.0] + lo = [1.0, 1.0, 1.0] + hi = [0.0, 0.0, 0.0] + n = 0 + for y in range(max(0, cy - half), min(h, cy + half)): + for x in range(max(0, cx - half), min(w, cx + half)): + i = (y * w + x) * 4 + for c in range(3): + v = px[i + c] + sums[c] += v + lo[c] = min(lo[c], v) + hi[c] = max(hi[c], v) + n += 1 + mean = [s / n for s in sums] + spread = max(hi[c] - lo[c] for c in range(3)) + return mean, spread + + +def verify_still(path): + """Witness the render itself: the broken panel must be one flat teal, the + repaired panel a high-contrast checker. Probes the saved PNG at each + panel's projected center, so a failed UV contract cannot ship a still.""" + from bpy_extras.object_utils import world_to_camera_view + + scene = bpy.context.scene + bpy.context.view_layer.update() + img = bpy.data.images.load(path) + try: + w, h = img.size + px = [0.0] * (w * h * 4) + img.pixels.foreach_get(px) + finally: + bpy.data.images.remove(img) + + half = max(8, int(w * 0.055)) # ~70 px at 1280: spans >1 checker cell + stats = {} + for name in ("Broken", "Fixed"): + obj = bpy.data.objects[name] + ndc = world_to_camera_view(scene, scene.camera, obj.matrix_world.translation) + cx, cy = int(ndc.x * w), int(ndc.y * h) + stats[name] = patch_stats(px, w, h, cx, cy, half) + + (b_mean, b_spread), (f_mean, f_spread) = stats["Broken"], stats["Fixed"] + print( + f"pixel witness: broken mean rgb=({b_mean[0]:.3f},{b_mean[1]:.3f}," + f"{b_mean[2]:.3f}) spread={b_spread:.4f}; fixed spread={f_spread:.4f}" + ) + if b_spread > 0.02: + return fail( + f"broken panel is not flat (spread {b_spread:.4f} > 0.02) — " + f"the hazard did not render as one color", + 11, + ) + if not (b_mean[2] > b_mean[1] > b_mean[0]): + return fail( + f"broken panel is not the teal of texel (0,0) " + f"(expected b>g>r, got rgb=({b_mean[0]:.3f},{b_mean[1]:.3f},{b_mean[2]:.3f}))", + 12, + ) + if f_spread < 0.25: + return fail( + f"repaired panel is not a checker (spread {f_spread:.4f} < 0.25)", + 13, + ) + if abs(f_mean[0] - b_mean[0]) < 0.1 and f_spread - b_spread < 0.2: + return fail("broken and repaired panels render identically", 14) + return 0 + + def main(): argv = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [] p = argparse.ArgumentParser() @@ -552,9 +625,13 @@

Source

return code if args.output: # check() already emptied the scene; rebuild for the still. - if not render_still(os.path.abspath(args.output), args.engine): + out = os.path.abspath(args.output) + if not render_still(out, args.engine): return fail(f"render produced no file at {args.output}", 10) - print(f"wrote {args.output}") + code = verify_still(out) + if code != 0: + return code + print(f"wrote {args.output} (pixel witness passed)") return 0 diff --git a/examples/gallery.json b/examples/gallery.json index 64f24e1..9465623 100644 --- a/examples/gallery.json +++ b/examples/gallery.json @@ -264,7 +264,7 @@ "name": "uv-layer-grid", "dir": "examples/uv-layer-grid", "teaches": "The UV-layer authoring hazard \u2014 bmesh.ops.create_grid(..., calc_uvs=True) is a silent no-op unless a UV layer already exists; without one an Image Texture samples texel (0,0) everywhere.", - "witnessesFix": "calc_uvs=True alone leaves 0 UV layers; pre-create + calc_uvs fills loops to the closed-form grid UVs ((x/size+1)/2, (y/size+1)/2) within 1e-6; explicit loop assignment is the calc_uvs-free fallback.", + "witnessesFix": "calc_uvs=True alone leaves 0 UV layers; pre-create + calc_uvs fills loops to the closed-form grid UVs ((x/size+1)/2, (y/size+1)/2) within 1e-6; explicit loop assignment is the calc_uvs-free fallback. The still is self-witnessing: the script re-reads its render and exits non-zero unless the hazard panel is one flat teal and the repaired panel a high-contrast checker.", "hero": "docs/gallery/assets/uv-layer-grid-hero.webp", "preview": "examples/uv-layer-grid/preview.webp", "tags": [ diff --git a/examples/uv-layer-grid/README.md b/examples/uv-layer-grid/README.md index 897cecb..1c05d18 100644 --- a/examples/uv-layer-grid/README.md +++ b/examples/uv-layer-grid/README.md @@ -35,6 +35,12 @@ lifted into its own smoke-gated witness so the contract cannot quietly drift. error `0.1`). - *Mesh persistence* — UV layer or loop data lost across `to_mesh`. - *Explicit path* — loop assignment or the closed form itself regressing. +- *Pixel witness* (with `--output`) — the saved PNG is read back and probed + at each panel's projected center: the hazard panel must be one flat teal + (per-channel spread ≤ 0.02, ordering b>g>r), the repaired panel a + high-contrast checker (spread ≥ 0.25). Falsified twice: secretly giving the + hazard panel UVs exited 11 with measured spread `0.7333`; repainting texel + (0,0) magenta exited 12 with measured rgb `(0.927, 0.118, 0.536)`. **Version divergence:** none probed — the silent no-op and closed-form UV fill assert identically on Blender 4.5 LTS and 5.1. The only gate in the file @@ -44,7 +50,10 @@ is the EEVEE engine id for the optional render (`BLENDER_EEVEE_NEXT` on 4.x, **Render:** two easel panels sharing one neon checker image. Left is the hazard (no UV layer) — flat teal of texel (0, 0). Right is the repair (pre-create + `calc_uvs`) — full magenta/cyan checker. If the UV contract -failed, both panels would read the same. +failed, both panels would read the same — and the still is not just an +illustration: the script re-reads its own render and exits non-zero unless +the pixels prove the flat-vs-checker split (measured on 5.1.2: hazard spread +`0.0078`, repair spread `0.7294`). ## Run diff --git a/examples/uv-layer-grid/preview.webp b/examples/uv-layer-grid/preview.webp index 4f6aa26e132511659aa043cbd1b14c590189944b..943731b5fefe23427d79dce93b47f2f35db70842 100644 GIT binary patch literal 14614 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 CnxV@8 literal 16472 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 diff --git a/examples/uv-layer-grid/uv_layer_grid.py b/examples/uv-layer-grid/uv_layer_grid.py index 6d5beb5..019e725 100644 --- a/examples/uv-layer-grid/uv_layer_grid.py +++ b/examples/uv-layer-grid/uv_layer_grid.py @@ -10,7 +10,10 @@ repair path against a closed-form UV grid, and an explicit loop-assignment fallback that does not depend on `calc_uvs` at all. Pass --output to also render a still that stages the broken (flat) panel beside the repaired -(checker) panel so the failure mode is visible at a glance: +(checker) panel — and then *witnesses the render itself*: the saved PNG is +read back and probed at each panel's projected center, asserting the broken +panel is one flat teal (texel (0,0)) while the repaired panel carries both +checker colors. If the UV contract failed, the pixels would say so: blender --background --python uv_layer_grid.py -- blender --background --python uv_layer_grid.py -- --output uv.png @@ -166,7 +169,7 @@ def eevee_engine_id(): def make_uv_testcard(name, w=256, h=256): - """Neon checker + corner marker. Texel (0,0) is a flat teal so a missing UV + """Neon checker whose single texel (0,0) is a flat teal, so a missing UV layer reads as one solid color instead of a bright false-positive checker.""" img = bpy.data.images.new(name, w, h, alpha=False) px = [0.0] * (w * h * 4) @@ -243,15 +246,13 @@ def render_still(path, engine): # Left: the hazard — calc_uvs alone, no UV layer → flat teal of texel (0,0). broken = textured_plane("Broken", card, with_uvs=False) - broken.location = (-1.22, 0.0, 1.18) - broken.rotation_euler = (math.radians(62), 0.0, math.radians(10)) - broken.scale = (1.15, 1.15, 1.15) + broken.location = (-1.18, 0.0, 0.94) + broken.rotation_euler = (math.radians(62), 0.0, math.radians(8)) # Right: the repair — pre-create UV layer, then calc_uvs fills it. fixed = textured_plane("Fixed", card, with_uvs=True) - fixed.location = (1.22, 0.0, 1.18) - fixed.rotation_euler = (math.radians(62), 0.0, math.radians(-10)) - fixed.scale = (1.15, 1.15, 1.15) + fixed.location = (1.18, 0.0, 0.94) + fixed.rotation_euler = (math.radians(62), 0.0, math.radians(-8)) floor_me = bpy.data.meshes.new("Floor") bm = bmesh.new() @@ -290,20 +291,21 @@ def light(name, loc, energy, size, col, rot): ob.rotation_euler = tuple(math.radians(a) for a in rot) scene.collection.objects.link(ob) - light("Key", (-3.8, -4.8, 5.8), 360.0, 4.5, (1.0, 0.96, 0.9), (52, 0, -32)) - light("Fill", (4.8, -2.8, 1.6), 70.0, 9.0, (0.75, 0.85, 1.0), (72, 0, 52)) - light("Rim", (0.2, 4.0, 2.8), 220.0, 3.2, (0.6, 0.78, 1.0), (-62, 0, 178)) - # Between the panels and the wall so it only rakes the backdrop. - light("Wedge", (0.5, 5.2, 2.8), 520.0, 7.0, (1.0, 0.72, 0.42), (-78, 0, 180)) + light("Key", (-3.8, -4.8, 5.8), 300.0, 4.5, (1.0, 0.96, 0.9), (52, 0, -32)) + light("Fill", (4.8, -2.8, 1.6), 55.0, 9.0, (0.75, 0.85, 1.0), (72, 0, 52)) + light("Rim", (0.2, 4.0, 2.8), 90.0, 3.2, (0.6, 0.78, 1.0), (-62, 0, 178)) + # Between the panels and the wall so it only rakes the backdrop: a + # contained warm pool, corners falling off to dark. + light("Wedge", (0.3, 5.4, 1.9), 380.0, 3.6, (1.0, 0.68, 0.38), (-72, 0, 180)) aim = bpy.data.objects.new("Aim", None) - aim.location = (0.0, 0.0, 1.1) + aim.location = (0.0, 0.0, 0.95) scene.collection.objects.link(aim) cam_data = bpy.data.cameras.new("Cam") cam_data.lens = 45.0 cam = bpy.data.objects.new("Cam", cam_data) - cam.location = (0.0, -5.4, 2.2) + cam.location = (0.0, -6.6, 2.1) con = cam.constraints.new("TRACK_TO") con.target = aim con.track_axis = "TRACK_NEGATIVE_Z" @@ -329,6 +331,77 @@ def light(name, loc, energy, size, col, rot): return os.path.exists(path) and os.path.getsize(path) > 0 +def patch_stats(px, w, h, cx, cy, half): + """Mean RGB and per-channel min/max spread of a (2*half)^2 pixel patch.""" + sums = [0.0, 0.0, 0.0] + lo = [1.0, 1.0, 1.0] + hi = [0.0, 0.0, 0.0] + n = 0 + for y in range(max(0, cy - half), min(h, cy + half)): + for x in range(max(0, cx - half), min(w, cx + half)): + i = (y * w + x) * 4 + for c in range(3): + v = px[i + c] + sums[c] += v + lo[c] = min(lo[c], v) + hi[c] = max(hi[c], v) + n += 1 + mean = [s / n for s in sums] + spread = max(hi[c] - lo[c] for c in range(3)) + return mean, spread + + +def verify_still(path): + """Witness the render itself: the broken panel must be one flat teal, the + repaired panel a high-contrast checker. Probes the saved PNG at each + panel's projected center, so a failed UV contract cannot ship a still.""" + from bpy_extras.object_utils import world_to_camera_view + + scene = bpy.context.scene + bpy.context.view_layer.update() + img = bpy.data.images.load(path) + try: + w, h = img.size + px = [0.0] * (w * h * 4) + img.pixels.foreach_get(px) + finally: + bpy.data.images.remove(img) + + half = max(8, int(w * 0.055)) # ~70 px at 1280: spans >1 checker cell + stats = {} + for name in ("Broken", "Fixed"): + obj = bpy.data.objects[name] + ndc = world_to_camera_view(scene, scene.camera, obj.matrix_world.translation) + cx, cy = int(ndc.x * w), int(ndc.y * h) + stats[name] = patch_stats(px, w, h, cx, cy, half) + + (b_mean, b_spread), (f_mean, f_spread) = stats["Broken"], stats["Fixed"] + print( + f"pixel witness: broken mean rgb=({b_mean[0]:.3f},{b_mean[1]:.3f}," + f"{b_mean[2]:.3f}) spread={b_spread:.4f}; fixed spread={f_spread:.4f}" + ) + if b_spread > 0.02: + return fail( + f"broken panel is not flat (spread {b_spread:.4f} > 0.02) — " + f"the hazard did not render as one color", + 11, + ) + if not (b_mean[2] > b_mean[1] > b_mean[0]): + return fail( + f"broken panel is not the teal of texel (0,0) " + f"(expected b>g>r, got rgb=({b_mean[0]:.3f},{b_mean[1]:.3f},{b_mean[2]:.3f}))", + 12, + ) + if f_spread < 0.25: + return fail( + f"repaired panel is not a checker (spread {f_spread:.4f} < 0.25)", + 13, + ) + if abs(f_mean[0] - b_mean[0]) < 0.1 and f_spread - b_spread < 0.2: + return fail("broken and repaired panels render identically", 14) + return 0 + + def main(): argv = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [] p = argparse.ArgumentParser() @@ -344,9 +417,13 @@ def main(): return code if args.output: # check() already emptied the scene; rebuild for the still. - if not render_still(os.path.abspath(args.output), args.engine): + out = os.path.abspath(args.output) + if not render_still(out, args.engine): return fail(f"render produced no file at {args.output}", 10) - print(f"wrote {args.output}") + code = verify_still(out) + if code != 0: + return code + print(f"wrote {args.output} (pixel witness passed)") return 0