From a1e67d542224cf42e2edfd83f58dc3e4aa08cc24 Mon Sep 17 00:00:00 2001 From: fOuttaMyPaint Date: Wed, 9 Sep 2026 19:17:40 -0400 Subject: [PATCH] feat: witness Geometry Nodes zone pairing pair_with_output is load-bearing; assert evaluated cubes against closed forms, not tree structure. Teach USD BEST_MATCH silencing evaluation_mode in the depsgraph skill. Signed-off-by: fOuttaMyPaint Co-authored-by: Cursor --- .cursor-plugin/plugin.json | 1 + AGENTS.md | 4 +- CLAUDE.md | 4 +- README.md | 22 +- ROADMAP.md | 1 + docs/gallery/assets/gn-zone-iterate-hero.webp | Bin 0 -> 10948 bytes .../gn-zone-iterate-contact-sheet.webp | Bin 0 -> 80382 bytes docs/gallery/gn-zone-iterate/index.html | 745 ++++++++++++++++++ docs/gallery/index.html | 13 +- docs/technical-audit.md | 27 + examples/gallery.json | 11 + examples/gn-zone-iterate/README.md | 42 + examples/gn-zone-iterate/gn_zone_iterate.py | 425 ++++++++++ examples/gn-zone-iterate/preview.webp | Bin 0 -> 10236 bytes skills/depsgraph-and-evaluated-data/SKILL.md | 11 +- skills/geometry-nodes-python/SKILL.md | 32 + tests/smoke/catalog.json | 3 +- 17 files changed, 1331 insertions(+), 10 deletions(-) create mode 100644 docs/gallery/assets/gn-zone-iterate-hero.webp create mode 100644 docs/gallery/contact-sheets/gn-zone-iterate-contact-sheet.webp create mode 100644 docs/gallery/gn-zone-iterate/index.html create mode 100644 examples/gn-zone-iterate/README.md create mode 100644 examples/gn-zone-iterate/gn_zone_iterate.py create mode 100644 examples/gn-zone-iterate/preview.webp diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json index fb5ffff..7dc11e7 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -79,6 +79,7 @@ "examples/gn-instance-grid", "examples/gn-modifier-inputs", "examples/gn-sdf-remesh", + "examples/gn-zone-iterate", "examples/gp-lineart-contour", "examples/grease-pencil-rosette", "examples/image-pixels-testcard", diff --git a/AGENTS.md b/AGENTS.md index 613b3ed..7bb2278 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,7 +20,7 @@ a `.cursor-plugin/plugin.json` manifest so the ecosystem drift checker classifies it as a `cursor-plugin`. This is content the AI loads when the user asks Blender questions or works on Blender add-ons in Cursor or Claude Code. -The content base is 13 skills, 6 rules, 2 templates, 17 snippets, and 47 +The content base is 13 skills, 6 rules, 2 templates, 17 snippets, and 48 examples (counts are CI-enforced against README.md and the manifest). The full inventory tables and per-item purposes live in `CLAUDE.md`. Example anatomy and authoring rules: copy `examples/bmesh-gear/`; the render look is specified @@ -35,7 +35,7 @@ Blender-Developer-Tools/ rules/.mdc # 6 rule files templates// # 2 starter templates snippets/.py # 17 standalone Python snippets - examples// # 47 runnable smoke-gated examples (+ gallery.json) + examples// # 48 runnable smoke-gated examples (+ gallery.json) examples/gallery_framing.py # shared Layer 1 framing measurement (render path only) scripts/build_gallery.py # generates docs/gallery/ (stdlib only) scripts/site/ # vendored landing-page build (build_site.py + template) diff --git a/CLAUDE.md b/CLAUDE.md index 07fd3a3..2e84c0a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -21,7 +21,7 @@ skills//SKILL.md - AI workflow definitions, 13 total rules/.mdc - Anti-pattern rules, 6 total templates// - Starter projects, 2 total snippets/.py - Standalone code patterns, 17 total -examples// - Runnable smoke-gated examples, 47 total (+ gallery.json) +examples// - Runnable smoke-gated examples, 48 total (+ gallery.json) scripts/build_gallery.py - Regenerates docs/gallery/ from gallery.json (stdlib only) scripts/site/ - Vendored landing-page build (Jinja2) docs/gallery/ - Committed generated gallery pages + hero renders @@ -83,7 +83,7 @@ v0.1.0: canonical object creation and deletion, depsgraph evaluated mesh, bmesh v0.2.0: Principled BSDF material, driver-with-custom-function via `driver_namespace`, application handler registration, shader node group with cross-version `interface` API, `foreach_get` bulk vertex read, version-branch skeleton, and USD export with `evaluation_mode='RENDER'`. -## Examples (47) +## Examples (48) Runnable scripts at `examples//`, each asserting a real API contract with deterministic checks (exit non-zero on failure) and optionally rendering a still via diff --git a/README.md b/README.md index 191720b..3a8e79e 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@

- 13 skills  •  6 rules  •  2 templates  •  17 snippets  •  47 examples + 13 skills  •  6 rules  •  2 templates  •  17 snippets  •  48 examples

@@ -36,7 +36,7 @@ ## Overview -This repository ships **13 skills, 6 rules, 2 templates, 17 snippets, and 47 runnable examples** for Blender Python development targeting Blender 5.2 LTS (current stable) with Blender 4.5 LTS fallback support. Blender 5.1 is prior stable. +This repository ships **13 skills, 6 rules, 2 templates, 17 snippets, and 48 runnable examples** for Blender Python development targeting Blender 5.2 LTS (current stable) with Blender 4.5 LTS fallback support. Blender 5.1 is prior stable. The content is consumed by AI coding agents (Cursor, Claude Code, any MCP-capable client) when working on Blender add-ons, geometry nodes scripts, batch pipelines, or animation tooling. There is no build step. Edit the markdown and Python files directly. @@ -377,7 +377,7 @@ inside the effect. Per-frame sample renders assert the closed form (mid dips

-Geometry Nodes — 3 examples +Geometry Nodes — 4 examples @@ -420,6 +420,22 @@ One Geometry Nodes tree, three modifier copies. Writes a Float Scale input throu `mod.properties.inputs` on 5.2 and `mod[identifier]` on 4.5/5.1. Asserts readback and evaluated Z-extent equal 1 / 2 / 3. The 5.1 dict form raises TypeError on 5.2. + + + + +
+GN zone iterate: four brass cubes in a row (Repeat Zone) beside a tower of six teal cubes (For Each Element) on a dark studio floor, proving pair_with_output actually iterates + + +### [gn-zone-iterate](examples/gn-zone-iterate/) + +Repeat Zone and For Each Element only iterate after `pair_with_output`. Asserts +evaluated cubes against closed forms — Repeat `8×(1+N)` with X-centers at +`k×1.2`, For Each `8×P` with Z-centers at `i×0.6+0.21` — not that the zone +nodes exist. Unpaired evaluates empty; For Each's main Geometry socket is a +passthrough. +
diff --git a/ROADMAP.md b/ROADMAP.md index d5556bb..56d8850 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -93,6 +93,7 @@ Not committed; target list for the next content version. (v0.3.0 shipped the smo - ~~Custom ID-property delete witness~~ **SHIPPED** as `examples/cross-version-property-delete/` — IDs built via `bpy.data.objects.new` (not `active_object`); `property_unset` is TypeError and leaves the key; `del` removes it on 4.5 LTS and 5.x - ~~USD export evaluation_mode witness~~ **SHIPPED** as `examples/usd-export-evaluation-mode/` — probed `wm.usd_export` on CI Linux portables 5.2.1 (`9e2066aef7ef`) and 4.5.13 (`daeeeca98fb0`); TESSELLATE+VIEWPORT 26/24, TESSELLATE+RENDER 98/96; BEST_MATCH writes the 8-vert catmullClark cage so the mode is silent +- ~~Repeat Zone / For Each Element pairing witness~~ **SHIPPED** as `examples/gn-zone-iterate/` — `pair_with_output` is load-bearing (unpaired evaluates 0 verts); Repeat `8×(1+N)` with X-centers at `k×STEP`; For Each `8×P` with Z-centers at `i×STEP`; For Each main Geometry is a passthrough (6 verts); count-only is insufficient (`--no-offset` still 32 verts, one X-center) - Tighten inverted smoke canaries: assert the expected `[FAIL]` marker text (`skipped on ... should run` / `missing post-exit sidecar`) alongside wrapper exit 1, so a canary that dies for the wrong reason does not satisfy the gate - ~~Fleet Pages facelift + examples support~~ **RESOLVED differently (2026-07-03)**: the meta-repo migration was dropped — the fleet template only scaffolds new tools, and each tool's site evolves independently after that. This repo vendored the site build into `scripts/site/`, redesigned landing + gallery as the Blender-viewport system (see `docs/gallery/DESIGN_NOTES.md`), added the examples grid, nav link, and full hero stats locally. `scripts/build_gallery.py` and `examples/gallery.json` are now permanent, not a prototype awaiting lift-and-shift. - `modal-operators` skill -- `invoke` returning `RUNNING_MODAL`, the `modal()` event handler, modal cancellation patterns diff --git a/docs/gallery/assets/gn-zone-iterate-hero.webp b/docs/gallery/assets/gn-zone-iterate-hero.webp new file mode 100644 index 0000000000000000000000000000000000000000..7a8806e14cc736b15d88ee250933d0491d5e877f GIT binary patch literal 10948 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

; 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

T>cwSvVNy_@ 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 literal 0 HcmV?d00001 diff --git a/docs/gallery/gn-zone-iterate/index.html b/docs/gallery/gn-zone-iterate/index.html new file mode 100644 index 0000000..07a80c9 --- /dev/null +++ b/docs/gallery/gn-zone-iterate/index.html @@ -0,0 +1,745 @@ + + + + + + gn-zone-iterate — Examples — Blender Developer Tools + + + + + + + + + + + + + + + + + +

+
+

gn-zone-iterate

+

Repeat Zone and For Each Element only iterate after pair_with_output. Evaluated cube counts follow 8 times (1+N) and 8 times P, not tree structure.

+
+
+ +

Rendered headless by the example itself — click to zoom.

+
witnesses Repeat 32/24 verts/faces with X-centers at k*1.2; For Each 48/36 with Z-centers at i*0.6+0.21. Unpaired evaluates empty; For Each main Geometry passthrough is 6 verts.
+
+
blender --background --python examples/gn-zone-iterate/gn_zone_iterate.py --
+ +
+
+

A Repeat Zone row and a For Each Element tower that witness geometry-nodes-python zone pairing — not tree structure.

+

pair_with_output is load-bearing. Unpaired Repeat Input has no Geometry sockets; unpaired For Each evaluates empty (Cannot evaluate node group on 4.5). For Each's main Geometry output is the input mesh passthrough; generated cubes live on Generation_0.

+

Closed forms (cube = 8 verts / 6 faces):

+
  • Repeat: join one translated cube per iteration. verts = 8 × (1 + N) with N=3 → 32. X-centers at k × 1.2 for k = 0..3.
  • For Each: one cube per POINT, Z-offset by Index × 0.6. verts = 8 × P with P=6 → 48. Z-centers at i × 0.6 + 0.21.
+

Count alone is not enough. Joining N+1 cubes at the origin hits 32 verts with a single X-center (--no-offset). The center axis is the second witness.

+

Same on 4.5 LTS and 5.x (zones are 4.3+). No skip.

+

What failure each check would catch:

+
  • exit 3 — Repeat pairing broken or iterations wrong (--unpair-repeat → 0/0; --repeat-iterations 1 → 16/12)
  • exit 4 — Repeat count matches but cubes collapsed (--no-offset)
  • exit 5 — For Each pairing broken, element count wrong, or main-socket passthrough (--unpair-foreach → 0/0; --foreach-count 3 → 24/18; --foreach-main → 6/0)
  • exit 6 — For Each count matches but Z-centers do not
+

Run

+
blender --background --python gn_zone_iterate.py --
+blender --background --python gn_zone_iterate.py -- --output zones.png
+

The --output render path measures framing via examples/gallery_framing.py (exit 10 on violation).

+
+
+

Source

+
+ examples/gn-zone-iterate/gn_zone_iterate.py + View on GitHub → +
+
"""Geometry Nodes zone pairing — a runnable example.
+
+Witnesses Repeat Zone and For Each Element from
+``skills/geometry-nodes-python``: ``pair_with_output`` is load-bearing, and
+the evaluated mesh must match a closed form. Tree-structure checks are
+vacuous — a For Each whose Group Output reads the *main* Geometry socket
+passes "nodes exist and are linked" while shipping the unevaluated grid.
+
+Closed forms (cube = 8 verts / 6 faces):
+
+* Repeat: start with one cube, each iteration Joins another translated by
+  ``(Iteration + 1) * STEP``. verts = 8 * (1 + N), unique X-centers at
+  ``k * STEP`` for k = 0..N.
+* For Each Element: one cube per POINT, offset in Z by ``Index * STEP``.
+  verts = 8 * P, unique Z-centers at ``i * STEP`` for i = 0..P-1.
+
+Count alone is not enough: Joining N+1 cubes at the origin hits the vert
+count with one X-center. The center axis is the second witness.
+
+By default it runs only the correctness check (no render) — the CI smoke
+check. Pass --output to also render a still:
+
+    blender --background --python gn_zone_iterate.py --
+    blender --background --python gn_zone_iterate.py -- --output z.png
+"""
+import bpy, bmesh, sys, os, math, argparse
+
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir))
+sys.dont_write_bytecode = True
+import gallery_framing
+
+CUBE_VERTS = 8
+CUBE_FACES = 6
+
+REPEAT_N = 3
+REPEAT_STEP = 1.2
+REPEAT_SIZE = 0.55
+REPEAT_VERTS = CUBE_VERTS * (1 + REPEAT_N)
+REPEAT_FACES = CUBE_FACES * (1 + REPEAT_N)
+REPEAT_CENTERS_X = [k * REPEAT_STEP for k in range(REPEAT_N + 1)]
+
+FOREACH_P = 6
+FOREACH_STEP = 0.60
+FOREACH_SIZE = 0.42
+FOREACH_VERTS = CUBE_VERTS * FOREACH_P
+FOREACH_FACES = CUBE_FACES * FOREACH_P
+FOREACH_CENTERS_Z = [i * FOREACH_STEP + FOREACH_SIZE / 2 for i in range(FOREACH_P)]
+
+
+def sock(node, collection, identifier):
+    for s in getattr(node, collection):
+        if s.identifier == identifier:
+            return s
+    raise RuntimeError(f"{node.bl_idname} has no {collection} {identifier!r}")
+
+
+def eval_mesh(obj):
+    dg = bpy.context.evaluated_depsgraph_get()
+    ev = obj.evaluated_get(dg)
+    me = ev.to_mesh()
+    try:
+        coords = [(v.co.x, v.co.y, v.co.z) for v in me.vertices]
+        faces = len(me.polygons)
+    finally:
+        ev.to_mesh_clear()
+    return coords, faces
+
+
+def centers_ok(coords, centers, half, axis):
+    """Every vert on `axis` sits in exactly one center ± half; each center has 8 verts."""
+    counts = [0] * len(centers)
+    worst = 0.0
+    for co in coords:
+        val = co[axis]
+        dists = [abs(val - c) for c in centers]
+        i = min(range(len(centers)), key=lambda k: dists[k])
+        worst = max(worst, dists[i])
+        if dists[i] > half + 1e-3:
+            return False, counts, dists[i]
+        counts[i] += 1
+    return all(c == CUBE_VERTS for c in counts), counts, worst
+
+
+def build_repeat_tree(n, pair=True, offset=True, material=None):
+    tree = bpy.data.node_groups.new("RepeatZone", "GeometryNodeTree")
+    tree.interface.new_socket(name="Geometry", in_out="OUTPUT", socket_type="NodeSocketGeometry")
+    go = tree.nodes.new("NodeGroupOutput")
+    cube0 = tree.nodes.new("GeometryNodeMeshCube")
+    cube0.inputs["Size"].default_value = (REPEAT_SIZE, REPEAT_SIZE, REPEAT_SIZE)
+    rin = tree.nodes.new("GeometryNodeRepeatInput")
+    rout = tree.nodes.new("GeometryNodeRepeatOutput")
+    if pair:
+        if not rin.pair_with_output(rout):
+            raise RuntimeError("RepeatInput.pair_with_output failed")
+    rin.inputs["Iterations"].default_value = n
+
+    cube1 = tree.nodes.new("GeometryNodeMeshCube")
+    cube1.inputs["Size"].default_value = (REPEAT_SIZE, REPEAT_SIZE, REPEAT_SIZE)
+    join = tree.nodes.new("GeometryNodeJoinGeometry")
+    shade = tree.nodes.new("GeometryNodeSetShadeSmooth")
+    shade.inputs["Shade Smooth"].default_value = False
+
+    added = cube1.outputs["Mesh"]
+    if offset and pair:
+        add = tree.nodes.new("ShaderNodeMath")
+        add.operation = "ADD"
+        add.inputs[1].default_value = 1.0
+        mul = tree.nodes.new("ShaderNodeMath")
+        mul.operation = "MULTIPLY"
+        mul.inputs[1].default_value = REPEAT_STEP
+        comb = tree.nodes.new("ShaderNodeCombineXYZ")
+        xf = tree.nodes.new("GeometryNodeTransform")
+        tree.links.new(rin.outputs["Iteration"], add.inputs[0])
+        tree.links.new(add.outputs["Value"], mul.inputs[0])
+        tree.links.new(mul.outputs["Value"], comb.inputs["X"])
+        tree.links.new(cube1.outputs["Mesh"], xf.inputs["Geometry"])
+        tree.links.new(comb.outputs["Vector"], xf.inputs["Translation"])
+        added = xf.outputs["Geometry"]
+
+    lift = tree.nodes.new("GeometryNodeTransform")
+    lift.inputs["Translation"].default_value = (0.0, 0.0, REPEAT_SIZE / 2)
+
+    if pair:
+        tree.links.new(cube0.outputs["Mesh"], rin.inputs["Geometry"])
+        tree.links.new(rin.outputs["Geometry"], join.inputs[0])
+        tree.links.new(added, join.inputs[0])
+        tree.links.new(join.outputs["Geometry"], rout.inputs["Geometry"])
+        tree.links.new(rout.outputs["Geometry"], lift.inputs["Geometry"])
+    else:
+        # Unpaired Repeat Input has no Geometry sockets. Leave the output empty
+        # so evaluation cannot silently pass the start cube through.
+        pass
+
+    tree.links.new(lift.outputs["Geometry"], shade.inputs["Geometry"])
+    out = shade.outputs["Geometry"]
+    if material is not None:
+        sm = tree.nodes.new("GeometryNodeSetMaterial")
+        sm.inputs["Material"].default_value = material
+        tree.links.new(out, sm.inputs["Geometry"])
+        out = sm.outputs["Geometry"]
+    tree.links.new(out, go.inputs["Geometry"])
+    return tree
+
+
+def build_foreach_tree(count, pair=True, use_generation=True, material=None):
+    tree = bpy.data.node_groups.new("ForEachZone", "GeometryNodeTree")
+    tree.interface.new_socket(name="Geometry", in_out="OUTPUT", socket_type="NodeSocketGeometry")
+    go = tree.nodes.new("NodeGroupOutput")
+    line = tree.nodes.new("GeometryNodeMeshLine")
+    line.inputs["Count"].default_value = count
+    # degenerate line — elements exist; Index, not position, places the cubes
+    line.inputs["Offset"].default_value = (0.0, 0.0, 0.0)
+
+    fin = tree.nodes.new("GeometryNodeForeachGeometryElementInput")
+    fout = tree.nodes.new("GeometryNodeForeachGeometryElementOutput")
+    if pair:
+        if not fin.pair_with_output(fout):
+            raise RuntimeError("ForeachInput.pair_with_output failed")
+    fout.domain = "POINT"
+
+    cube = tree.nodes.new("GeometryNodeMeshCube")
+    cube.inputs["Size"].default_value = (FOREACH_SIZE, FOREACH_SIZE, FOREACH_SIZE)
+    mul = tree.nodes.new("ShaderNodeMath")
+    mul.operation = "MULTIPLY"
+    mul.inputs[1].default_value = FOREACH_STEP
+    comb = tree.nodes.new("ShaderNodeCombineXYZ")
+    sp = tree.nodes.new("GeometryNodeSetPosition")
+    shade = tree.nodes.new("GeometryNodeSetShadeSmooth")
+    shade.inputs["Shade Smooth"].default_value = False
+    lift = tree.nodes.new("GeometryNodeTransform")
+    lift.inputs["Translation"].default_value = (0.0, 0.0, FOREACH_SIZE / 2)
+
+    tree.links.new(line.outputs["Mesh"], fin.inputs["Geometry"])
+    tree.links.new(fin.outputs["Index"], mul.inputs[0])
+    tree.links.new(mul.outputs["Value"], comb.inputs["Z"])
+    tree.links.new(cube.outputs["Mesh"], sp.inputs["Geometry"])
+    tree.links.new(comb.outputs["Vector"], sp.inputs["Offset"])
+
+    if pair:
+        gen_in = sock(fout, "inputs", "Generation_0")
+        tree.links.new(sp.outputs["Geometry"], gen_in)
+        if use_generation:
+            body = sock(fout, "outputs", "Generation_0")
+        else:
+            body = fout.outputs["Geometry"]
+        tree.links.new(body, lift.inputs["Geometry"])
+    tree.links.new(lift.outputs["Geometry"], shade.inputs["Geometry"])
+    out = shade.outputs["Geometry"]
+    if material is not None:
+        sm = tree.nodes.new("GeometryNodeSetMaterial")
+        sm.inputs["Material"].default_value = material
+        tree.links.new(out, sm.inputs["Geometry"])
+        out = sm.outputs["Geometry"]
+    tree.links.new(out, go.inputs["Geometry"])
+    return tree
+
+
+def principled(name, color, metallic, roughness):
+    mat = bpy.data.materials.new(name)
+    mat.use_nodes = True
+    bsdf = mat.node_tree.nodes["Principled BSDF"]
+    bsdf.inputs["Base Color"].default_value = color
+    bsdf.inputs["Metallic"].default_value = metallic
+    bsdf.inputs["Roughness"].default_value = roughness
+    return mat
+
+
+def carrier(name):
+    me = bpy.data.meshes.new(name)
+    me.vertices.add(1)
+    ob = bpy.data.objects.new(name, me)
+    bpy.context.collection.objects.link(ob)
+    return ob
+
+
+def attach(obj, tree):
+    mod = obj.modifiers.new("GN", "NODES")
+    mod.node_group = tree
+    return mod
+
+
+def build(repeat_n, foreach_p, pair_repeat, pair_foreach, offset_repeat, foreach_generation):
+    bpy.ops.wm.read_factory_settings(use_empty=True)
+    brass = principled("Brass", (0.86, 0.55, 0.16, 1.0), 0.85, 0.34)
+    teal = principled("Teal", (0.08, 0.55, 0.58, 1.0), 0.15, 0.32)
+    rpt = carrier("RepeatRow")
+    fee = carrier("ForEachTower")
+    rpt.location = (-2.80, 0.0, 0.0)
+    fee.location = (2.20, 0.0, 0.0)
+    attach(rpt, build_repeat_tree(repeat_n, pair=pair_repeat, offset=offset_repeat, material=brass))
+    attach(fee, build_foreach_tree(
+        foreach_p, pair=pair_foreach, use_generation=foreach_generation, material=teal,
+    ))
+    bpy.context.view_layer.update()
+    return rpt, fee
+
+
+def check(rpt, fee, expect_n, expect_p):
+    if len(rpt.data.vertices) != 1 or len(fee.data.vertices) != 1:
+        print("ERROR: carrier mesh was rewritten; zones must not apply in-place", file=sys.stderr)
+        return 2
+
+    r_coords, r_faces = eval_mesh(rpt)
+    f_coords, f_faces = eval_mesh(fee)
+    r_exp_v = CUBE_VERTS * (1 + expect_n)
+    r_exp_f = CUBE_FACES * (1 + expect_n)
+    f_exp_v = CUBE_VERTS * expect_p
+    f_exp_f = CUBE_FACES * expect_p
+    r_centers = [k * REPEAT_STEP for k in range(expect_n + 1)]
+    f_centers = [i * FOREACH_STEP + FOREACH_SIZE / 2 for i in range(expect_p)]
+
+    print(
+        f"repeat verts={len(r_coords)} faces={r_faces} "
+        f"foreach verts={len(f_coords)} faces={f_faces} "
+        f"expect repeat={r_exp_v}/{r_exp_f} foreach={f_exp_v}/{f_exp_f}"
+    )
+
+    if len(r_coords) != r_exp_v or r_faces != r_exp_f:
+        print(
+            f"ERROR: Repeat evaluated {len(r_coords)}/{r_faces}, "
+            f"closed form 8*(1+N)={r_exp_v}/{r_exp_f} with N={expect_n}",
+            file=sys.stderr,
+        )
+        return 3
+    ok, counts, worst = centers_ok(r_coords, r_centers, REPEAT_SIZE / 2, 0)
+    if not ok:
+        print(
+            f"ERROR: Repeat X-centers {counts} worst={worst:.4f} "
+            f"expected {CUBE_VERTS} verts at {r_centers}",
+            file=sys.stderr,
+        )
+        return 4
+
+    if len(f_coords) != f_exp_v or f_faces != f_exp_f:
+        print(
+            f"ERROR: For Each evaluated {len(f_coords)}/{f_faces}, "
+            f"closed form 8*P={f_exp_v}/{f_exp_f} with P={expect_p}",
+            file=sys.stderr,
+        )
+        return 5
+    ok, counts, worst = centers_ok(f_coords, f_centers, FOREACH_SIZE / 2, 2)
+    if not ok:
+        print(
+            f"ERROR: For Each Z-centers {counts} worst={worst:.4f} "
+            f"expected {CUBE_VERTS} verts at {f_centers}",
+            file=sys.stderr,
+        )
+        return 6
+
+    print(
+        f"repeat_N={expect_n} foreach_P={expect_p} "
+        f"x_centers={r_centers} z_centers={f_centers} pairing=ok"
+    )
+    return 0
+
+
+def eevee_engine_id():
+    return "BLENDER_EEVEE" if bpy.app.version >= (5, 0, 0) else "BLENDER_EEVEE_NEXT"
+
+
+def render_still(rpt, fee, path, engine):
+    scene = bpy.context.scene
+
+    floor_me = bpy.data.meshes.new("Floor")
+    bm = bmesh.new()
+    try:
+        bmesh.ops.create_grid(bm, x_segments=1, y_segments=1, size=30.0)
+        bm.to_mesh(floor_me)
+    finally:
+        bm.free()
+    studio = principled("Studio", (0.03, 0.032, 0.037, 1.0), 0.0, 0.7)
+    floor_me.materials.append(studio)
+    floor = bpy.data.objects.new("Floor", floor_me)
+    scene.collection.objects.link(floor)
+    wall = bpy.data.objects.new("Wall", floor_me.copy())
+    wall.data.materials.clear()
+    wall.data.materials.append(principled("Wall", (0.03, 0.032, 0.037, 1.0), 0.0, 0.7))
+    wall.location = (0.0, 9.0, 0.0)
+    wall.rotation_euler = (math.pi / 2, 0.0, 0.0)
+    scene.collection.objects.link(wall)
+
+    world = bpy.data.worlds.new("World")
+    world.use_nodes = True
+    world.node_tree.nodes["Background"].inputs["Color"].default_value = (0.02, 0.021, 0.025, 1.0)
+    scene.world = world
+
+    def light(name, loc, energy, size, col, rot):
+        ld = bpy.data.lights.new(name, "AREA")
+        ld.energy = energy
+        ld.size = size
+        ld.color = col
+        ob = bpy.data.objects.new(name, ld)
+        ob.location = loc
+        ob.rotation_euler = tuple(math.radians(a) for a in rot)
+        scene.collection.objects.link(ob)
+
+    light("Key", (-4.0, -5.0, 6.0), 520.0, 5.0, (1.0, 0.96, 0.9), (46, 0, -35))
+    light("Fill", (5.0, -3.5, 3.0), 160.0, 9.0, (0.75, 0.85, 1.0), (62, 0, 50))
+    light("Wedge", (2.5, 5.5, 4.0), 360.0, 6.0, (1.0, 0.76, 0.5), (-68, 0, 190))
+    light("Glint", (0.4, -5.2, 5.5), 700.0, 0.9, (1.0, 0.92, 0.75), (42, 0, 8))
+
+    aim = bpy.data.objects.new("Aim", None)
+    aim.location = (0.0, 0.0, 1.50)
+    aim.hide_render = True
+    scene.collection.objects.link(aim)
+    cam_data = bpy.data.cameras.new("Cam")
+    cam_data.lens = 50.0
+    cam = bpy.data.objects.new("Cam", cam_data)
+    cam.location = (6.6, -9.3, 3.55)
+    scene.collection.objects.link(cam)
+    scene.camera = cam
+    track = cam.constraints.new("TRACK_TO")
+    track.target = aim
+    track.track_axis = "TRACK_NEGATIVE_Z"
+    track.up_axis = "UP_Y"
+
+    scene.render.engine = "CYCLES" if engine == "cycles" else eevee_engine_id()
+    if engine == "cycles":
+        scene.cycles.samples = 32
+    else:
+        try:
+            scene.eevee.taa_render_samples = 64
+        except AttributeError:
+            pass
+    scene.render.resolution_x = 1280
+    scene.render.resolution_y = 720
+    scene.render.image_settings.file_format = "PNG"
+    scene.render.filepath = path
+    scene.view_settings.view_transform = "Standard"
+
+    hero = [rpt, fee]
+    fcode = gallery_framing.check_framing(
+        scene, cam, hero=hero, elements=hero, stage=[floor, wall],
+    )
+    if fcode:
+        return fcode
+    bpy.ops.render.render(write_still=True)
+    if not (os.path.exists(path) and os.path.getsize(path) > 0):
+        print("ERROR: render produced no file", file=sys.stderr)
+        return 12
+    return 0
+
+
+def main():
+    argv = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
+    p = argparse.ArgumentParser()
+    p.add_argument("--output", default=None)
+    p.add_argument("--engine", default="eevee", choices=("eevee", "cycles"))
+    p.add_argument("--unpair-repeat", action="store_true")
+    p.add_argument("--unpair-foreach", action="store_true")
+    p.add_argument("--repeat-iterations", type=int, default=REPEAT_N)
+    p.add_argument("--foreach-count", type=int, default=FOREACH_P)
+    p.add_argument("--foreach-main", action="store_true",
+                   help="falsification: Group Output reads For Each main Geometry")
+    p.add_argument("--no-offset", action="store_true",
+                   help="falsification: Repeat Join without Iteration translation")
+    args = p.parse_args(argv)
+
+    rpt, fee = build(
+        args.repeat_iterations, args.foreach_count,
+        pair_repeat=not args.unpair_repeat,
+        pair_foreach=not args.unpair_foreach,
+        offset_repeat=not args.no_offset,
+        foreach_generation=not args.foreach_main,
+    )
+    code = check(rpt, fee, REPEAT_N, FOREACH_P)
+    if code:
+        return code
+
+    if args.output:
+        rcode = render_still(rpt, fee, os.path.abspath(args.output), args.engine)
+        if rcode:
+            return rcode
+        print(f"rendered still {args.output}")
+
+    print("gn-zone-iterate OK")
+    return 0
+
+
+if __name__ == "__main__":
+    try:
+        sys.exit(main())
+    except Exception as exc:
+        print(f"ERROR: {type(exc).__name__}: {exc}", file=sys.stderr)
+        sys.exit(1)
+
+
+
+ +
+
+ generated from examples/gallery.json + CC-BY-NC-ND-4.0 + exit 0 +
+
+ + + diff --git a/docs/gallery/index.html b/docs/gallery/index.html index 19fae33..4ddcc55 100644 --- a/docs/gallery/index.html +++ b/docs/gallery/index.html @@ -272,7 +272,7 @@

Examples Gallery

autocomplete="off" spellcheck="false" aria-label="Search examples" /> - 47 examples + 48 examples
@@ -840,6 +840,17 @@

usd-export-evaluation-mode

View example
+
+ + gn-zone-iterate — Repeat Zone and For Each Element only iterate after pair_with_output. + +
+

gn-zone-iterate

+

Repeat Zone and For Each Element only iterate after pair_with_output. Evaluated cube counts follow 8 times (1+N) and 8 times P, not tree structure.

+

witnesses Repeat 32/24 verts/faces with X-centers at k*1.2; For Each 48/36 with Z-centers at i*0.6+0.21. Unpaired evaluates empty; For Each main Geometry passthrough is 6 verts.

+ View example +
+
diff --git a/docs/technical-audit.md b/docs/technical-audit.md index d181e27..eab1a00 100644 --- a/docs/technical-audit.md +++ b/docs/technical-audit.md @@ -33,6 +33,33 @@ Set scene resolution **before** building strips. `A.width, A.height == (96, 54)`). No separate example — that script already fails if the bake drifts. +### 2026-09-09 — USD `export_subdivision='BEST_MATCH'` silences `evaluation_mode` + +Default `wm.usd_export` `export_subdivision='BEST_MATCH'` writes the cage +plus `subdivisionScheme = catmullClark`. VIEWPORT and RENDER USDA files +are then identical, so `evaluation_mode` looks like a no-op. TESSELLATE +makes the mode observable. Catmull-Clark on a cube: verts = +`2 + 6 × 4^n` (n=1 → 26, n=2 → 98). Same on 4.5 LTS and 5.2 LTS; not a +version split, an exporter-default trap. Not listed in the python_api notes +as a behavior change because the RNA names did not move. + +- Taught: `skills/depsgraph-and-evaluated-data/SKILL.md` +- Witness: `examples/usd-export-evaluation-mode/` + +### 2026-09-09 — Geometry Nodes zone pairing is load-bearing + +Creating Repeat / For Each Element input and output nodes and linking +sockets is not enough. `pair_with_output` creates the Geometry items; +unpaired Repeat Input has only Iterations, unpaired For Each evaluates +empty. For Each's main `Geometry` output is the input-mesh passthrough; +generated meshes live on `Generation_0`. Tree-structure checks are +vacuous. Count-only is also insufficient: joining N+1 cubes at the origin +hits `8×(1+N)` verts with one X-center. Same on 4.5 LTS and 5.x (zones +are 4.3+). Not a version split. + +- Taught: `skills/geometry-nodes-python/SKILL.md` +- Witness: `examples/gn-zone-iterate/` + ### Contrast — NodesModifier dict assignment (5.2, was in the notes) `mod[identifier] = value` raises `TypeError` on 5.2 (`id properties not diff --git a/examples/gallery.json b/examples/gallery.json index 0ccaf0a..a567299 100644 --- a/examples/gallery.json +++ b/examples/gallery.json @@ -594,6 +594,17 @@ "depsgraph", "export" ] + }, + { + "name": "gn-zone-iterate", + "dir": "examples/gn-zone-iterate", + "teaches": "Repeat Zone and For Each Element only iterate after pair_with_output. Evaluated cube counts follow 8 times (1+N) and 8 times P, not tree structure.", + "witnessesFix": "Repeat 32/24 verts/faces with X-centers at k*1.2; For Each 48/36 with Z-centers at i*0.6+0.21. Unpaired evaluates empty; For Each main Geometry passthrough is 6 verts.", + "hero": "docs/gallery/assets/gn-zone-iterate-hero.webp", + "preview": "examples/gn-zone-iterate/preview.webp", + "tags": [ + "geometry-nodes" + ] } ] } diff --git a/examples/gn-zone-iterate/README.md b/examples/gn-zone-iterate/README.md new file mode 100644 index 0000000..14e329d --- /dev/null +++ b/examples/gn-zone-iterate/README.md @@ -0,0 +1,42 @@ +# Geometry Nodes zone iterate + +A Repeat Zone row and a For Each Element tower that witness +[`geometry-nodes-python`](../../skills/geometry-nodes-python/SKILL.md) +zone pairing — not tree structure. + +`pair_with_output` is load-bearing. Unpaired Repeat Input has no Geometry +sockets; unpaired For Each evaluates empty (`Cannot evaluate node group` on +4.5). For Each's main `Geometry` output is the input mesh passthrough; +generated cubes live on `Generation_0`. + +Closed forms (cube = 8 verts / 6 faces): + +- Repeat: join one translated cube per iteration. verts = `8 × (1 + N)` with + N=3 → 32. X-centers at `k × 1.2` for k = 0..3. +- For Each: one cube per POINT, Z-offset by `Index × 0.6`. verts = `8 × P` + with P=6 → 48. Z-centers at `i × 0.6 + 0.21`. + +**Count alone is not enough.** Joining N+1 cubes at the origin hits 32 verts +with a single X-center (`--no-offset`). The center axis is the second witness. + +Same on 4.5 LTS and 5.x (zones are 4.3+). No skip. + +**What failure each check would catch:** + +- exit 3 — Repeat pairing broken or iterations wrong (`--unpair-repeat` → 0/0; + `--repeat-iterations 1` → 16/12) +- exit 4 — Repeat count matches but cubes collapsed (`--no-offset`) +- exit 5 — For Each pairing broken, element count wrong, or main-socket + passthrough (`--unpair-foreach` → 0/0; `--foreach-count 3` → 24/18; + `--foreach-main` → 6/0) +- exit 6 — For Each count matches but Z-centers do not + +## Run + +```bash +blender --background --python gn_zone_iterate.py -- +blender --background --python gn_zone_iterate.py -- --output zones.png +``` + +The `--output` render path measures framing via `examples/gallery_framing.py` +(exit 10 on violation). diff --git a/examples/gn-zone-iterate/gn_zone_iterate.py b/examples/gn-zone-iterate/gn_zone_iterate.py new file mode 100644 index 0000000..fd7cea4 --- /dev/null +++ b/examples/gn-zone-iterate/gn_zone_iterate.py @@ -0,0 +1,425 @@ +"""Geometry Nodes zone pairing — a runnable example. + +Witnesses Repeat Zone and For Each Element from +``skills/geometry-nodes-python``: ``pair_with_output`` is load-bearing, and +the evaluated mesh must match a closed form. Tree-structure checks are +vacuous — a For Each whose Group Output reads the *main* Geometry socket +passes "nodes exist and are linked" while shipping the unevaluated grid. + +Closed forms (cube = 8 verts / 6 faces): + +* Repeat: start with one cube, each iteration Joins another translated by + ``(Iteration + 1) * STEP``. verts = 8 * (1 + N), unique X-centers at + ``k * STEP`` for k = 0..N. +* For Each Element: one cube per POINT, offset in Z by ``Index * STEP``. + verts = 8 * P, unique Z-centers at ``i * STEP`` for i = 0..P-1. + +Count alone is not enough: Joining N+1 cubes at the origin hits the vert +count with one X-center. The center axis is the second witness. + +By default it runs only the correctness check (no render) — the CI smoke +check. Pass --output to also render a still: + + blender --background --python gn_zone_iterate.py -- + blender --background --python gn_zone_iterate.py -- --output z.png +""" +import bpy, bmesh, sys, os, math, argparse + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir)) +sys.dont_write_bytecode = True +import gallery_framing + +CUBE_VERTS = 8 +CUBE_FACES = 6 + +REPEAT_N = 3 +REPEAT_STEP = 1.2 +REPEAT_SIZE = 0.55 +REPEAT_VERTS = CUBE_VERTS * (1 + REPEAT_N) +REPEAT_FACES = CUBE_FACES * (1 + REPEAT_N) +REPEAT_CENTERS_X = [k * REPEAT_STEP for k in range(REPEAT_N + 1)] + +FOREACH_P = 6 +FOREACH_STEP = 0.60 +FOREACH_SIZE = 0.42 +FOREACH_VERTS = CUBE_VERTS * FOREACH_P +FOREACH_FACES = CUBE_FACES * FOREACH_P +FOREACH_CENTERS_Z = [i * FOREACH_STEP + FOREACH_SIZE / 2 for i in range(FOREACH_P)] + + +def sock(node, collection, identifier): + for s in getattr(node, collection): + if s.identifier == identifier: + return s + raise RuntimeError(f"{node.bl_idname} has no {collection} {identifier!r}") + + +def eval_mesh(obj): + dg = bpy.context.evaluated_depsgraph_get() + ev = obj.evaluated_get(dg) + me = ev.to_mesh() + try: + coords = [(v.co.x, v.co.y, v.co.z) for v in me.vertices] + faces = len(me.polygons) + finally: + ev.to_mesh_clear() + return coords, faces + + +def centers_ok(coords, centers, half, axis): + """Every vert on `axis` sits in exactly one center ± half; each center has 8 verts.""" + counts = [0] * len(centers) + worst = 0.0 + for co in coords: + val = co[axis] + dists = [abs(val - c) for c in centers] + i = min(range(len(centers)), key=lambda k: dists[k]) + worst = max(worst, dists[i]) + if dists[i] > half + 1e-3: + return False, counts, dists[i] + counts[i] += 1 + return all(c == CUBE_VERTS for c in counts), counts, worst + + +def build_repeat_tree(n, pair=True, offset=True, material=None): + tree = bpy.data.node_groups.new("RepeatZone", "GeometryNodeTree") + tree.interface.new_socket(name="Geometry", in_out="OUTPUT", socket_type="NodeSocketGeometry") + go = tree.nodes.new("NodeGroupOutput") + cube0 = tree.nodes.new("GeometryNodeMeshCube") + cube0.inputs["Size"].default_value = (REPEAT_SIZE, REPEAT_SIZE, REPEAT_SIZE) + rin = tree.nodes.new("GeometryNodeRepeatInput") + rout = tree.nodes.new("GeometryNodeRepeatOutput") + if pair: + if not rin.pair_with_output(rout): + raise RuntimeError("RepeatInput.pair_with_output failed") + rin.inputs["Iterations"].default_value = n + + cube1 = tree.nodes.new("GeometryNodeMeshCube") + cube1.inputs["Size"].default_value = (REPEAT_SIZE, REPEAT_SIZE, REPEAT_SIZE) + join = tree.nodes.new("GeometryNodeJoinGeometry") + shade = tree.nodes.new("GeometryNodeSetShadeSmooth") + shade.inputs["Shade Smooth"].default_value = False + + added = cube1.outputs["Mesh"] + if offset and pair: + add = tree.nodes.new("ShaderNodeMath") + add.operation = "ADD" + add.inputs[1].default_value = 1.0 + mul = tree.nodes.new("ShaderNodeMath") + mul.operation = "MULTIPLY" + mul.inputs[1].default_value = REPEAT_STEP + comb = tree.nodes.new("ShaderNodeCombineXYZ") + xf = tree.nodes.new("GeometryNodeTransform") + tree.links.new(rin.outputs["Iteration"], add.inputs[0]) + tree.links.new(add.outputs["Value"], mul.inputs[0]) + tree.links.new(mul.outputs["Value"], comb.inputs["X"]) + tree.links.new(cube1.outputs["Mesh"], xf.inputs["Geometry"]) + tree.links.new(comb.outputs["Vector"], xf.inputs["Translation"]) + added = xf.outputs["Geometry"] + + lift = tree.nodes.new("GeometryNodeTransform") + lift.inputs["Translation"].default_value = (0.0, 0.0, REPEAT_SIZE / 2) + + if pair: + tree.links.new(cube0.outputs["Mesh"], rin.inputs["Geometry"]) + tree.links.new(rin.outputs["Geometry"], join.inputs[0]) + tree.links.new(added, join.inputs[0]) + tree.links.new(join.outputs["Geometry"], rout.inputs["Geometry"]) + tree.links.new(rout.outputs["Geometry"], lift.inputs["Geometry"]) + else: + # Unpaired Repeat Input has no Geometry sockets. Leave the output empty + # so evaluation cannot silently pass the start cube through. + pass + + tree.links.new(lift.outputs["Geometry"], shade.inputs["Geometry"]) + out = shade.outputs["Geometry"] + if material is not None: + sm = tree.nodes.new("GeometryNodeSetMaterial") + sm.inputs["Material"].default_value = material + tree.links.new(out, sm.inputs["Geometry"]) + out = sm.outputs["Geometry"] + tree.links.new(out, go.inputs["Geometry"]) + return tree + + +def build_foreach_tree(count, pair=True, use_generation=True, material=None): + tree = bpy.data.node_groups.new("ForEachZone", "GeometryNodeTree") + tree.interface.new_socket(name="Geometry", in_out="OUTPUT", socket_type="NodeSocketGeometry") + go = tree.nodes.new("NodeGroupOutput") + line = tree.nodes.new("GeometryNodeMeshLine") + line.inputs["Count"].default_value = count + # degenerate line — elements exist; Index, not position, places the cubes + line.inputs["Offset"].default_value = (0.0, 0.0, 0.0) + + fin = tree.nodes.new("GeometryNodeForeachGeometryElementInput") + fout = tree.nodes.new("GeometryNodeForeachGeometryElementOutput") + if pair: + if not fin.pair_with_output(fout): + raise RuntimeError("ForeachInput.pair_with_output failed") + fout.domain = "POINT" + + cube = tree.nodes.new("GeometryNodeMeshCube") + cube.inputs["Size"].default_value = (FOREACH_SIZE, FOREACH_SIZE, FOREACH_SIZE) + mul = tree.nodes.new("ShaderNodeMath") + mul.operation = "MULTIPLY" + mul.inputs[1].default_value = FOREACH_STEP + comb = tree.nodes.new("ShaderNodeCombineXYZ") + sp = tree.nodes.new("GeometryNodeSetPosition") + shade = tree.nodes.new("GeometryNodeSetShadeSmooth") + shade.inputs["Shade Smooth"].default_value = False + lift = tree.nodes.new("GeometryNodeTransform") + lift.inputs["Translation"].default_value = (0.0, 0.0, FOREACH_SIZE / 2) + + tree.links.new(line.outputs["Mesh"], fin.inputs["Geometry"]) + tree.links.new(fin.outputs["Index"], mul.inputs[0]) + tree.links.new(mul.outputs["Value"], comb.inputs["Z"]) + tree.links.new(cube.outputs["Mesh"], sp.inputs["Geometry"]) + tree.links.new(comb.outputs["Vector"], sp.inputs["Offset"]) + + if pair: + gen_in = sock(fout, "inputs", "Generation_0") + tree.links.new(sp.outputs["Geometry"], gen_in) + if use_generation: + body = sock(fout, "outputs", "Generation_0") + else: + body = fout.outputs["Geometry"] + tree.links.new(body, lift.inputs["Geometry"]) + tree.links.new(lift.outputs["Geometry"], shade.inputs["Geometry"]) + out = shade.outputs["Geometry"] + if material is not None: + sm = tree.nodes.new("GeometryNodeSetMaterial") + sm.inputs["Material"].default_value = material + tree.links.new(out, sm.inputs["Geometry"]) + out = sm.outputs["Geometry"] + tree.links.new(out, go.inputs["Geometry"]) + return tree + + +def principled(name, color, metallic, roughness): + mat = bpy.data.materials.new(name) + mat.use_nodes = True + bsdf = mat.node_tree.nodes["Principled BSDF"] + bsdf.inputs["Base Color"].default_value = color + bsdf.inputs["Metallic"].default_value = metallic + bsdf.inputs["Roughness"].default_value = roughness + return mat + + +def carrier(name): + me = bpy.data.meshes.new(name) + me.vertices.add(1) + ob = bpy.data.objects.new(name, me) + bpy.context.collection.objects.link(ob) + return ob + + +def attach(obj, tree): + mod = obj.modifiers.new("GN", "NODES") + mod.node_group = tree + return mod + + +def build(repeat_n, foreach_p, pair_repeat, pair_foreach, offset_repeat, foreach_generation): + bpy.ops.wm.read_factory_settings(use_empty=True) + brass = principled("Brass", (0.86, 0.55, 0.16, 1.0), 0.85, 0.34) + teal = principled("Teal", (0.08, 0.55, 0.58, 1.0), 0.15, 0.32) + rpt = carrier("RepeatRow") + fee = carrier("ForEachTower") + rpt.location = (-2.80, 0.0, 0.0) + fee.location = (2.20, 0.0, 0.0) + attach(rpt, build_repeat_tree(repeat_n, pair=pair_repeat, offset=offset_repeat, material=brass)) + attach(fee, build_foreach_tree( + foreach_p, pair=pair_foreach, use_generation=foreach_generation, material=teal, + )) + bpy.context.view_layer.update() + return rpt, fee + + +def check(rpt, fee, expect_n, expect_p): + if len(rpt.data.vertices) != 1 or len(fee.data.vertices) != 1: + print("ERROR: carrier mesh was rewritten; zones must not apply in-place", file=sys.stderr) + return 2 + + r_coords, r_faces = eval_mesh(rpt) + f_coords, f_faces = eval_mesh(fee) + r_exp_v = CUBE_VERTS * (1 + expect_n) + r_exp_f = CUBE_FACES * (1 + expect_n) + f_exp_v = CUBE_VERTS * expect_p + f_exp_f = CUBE_FACES * expect_p + r_centers = [k * REPEAT_STEP for k in range(expect_n + 1)] + f_centers = [i * FOREACH_STEP + FOREACH_SIZE / 2 for i in range(expect_p)] + + print( + f"repeat verts={len(r_coords)} faces={r_faces} " + f"foreach verts={len(f_coords)} faces={f_faces} " + f"expect repeat={r_exp_v}/{r_exp_f} foreach={f_exp_v}/{f_exp_f}" + ) + + if len(r_coords) != r_exp_v or r_faces != r_exp_f: + print( + f"ERROR: Repeat evaluated {len(r_coords)}/{r_faces}, " + f"closed form 8*(1+N)={r_exp_v}/{r_exp_f} with N={expect_n}", + file=sys.stderr, + ) + return 3 + ok, counts, worst = centers_ok(r_coords, r_centers, REPEAT_SIZE / 2, 0) + if not ok: + print( + f"ERROR: Repeat X-centers {counts} worst={worst:.4f} " + f"expected {CUBE_VERTS} verts at {r_centers}", + file=sys.stderr, + ) + return 4 + + if len(f_coords) != f_exp_v or f_faces != f_exp_f: + print( + f"ERROR: For Each evaluated {len(f_coords)}/{f_faces}, " + f"closed form 8*P={f_exp_v}/{f_exp_f} with P={expect_p}", + file=sys.stderr, + ) + return 5 + ok, counts, worst = centers_ok(f_coords, f_centers, FOREACH_SIZE / 2, 2) + if not ok: + print( + f"ERROR: For Each Z-centers {counts} worst={worst:.4f} " + f"expected {CUBE_VERTS} verts at {f_centers}", + file=sys.stderr, + ) + return 6 + + print( + f"repeat_N={expect_n} foreach_P={expect_p} " + f"x_centers={r_centers} z_centers={f_centers} pairing=ok" + ) + return 0 + + +def eevee_engine_id(): + return "BLENDER_EEVEE" if bpy.app.version >= (5, 0, 0) else "BLENDER_EEVEE_NEXT" + + +def render_still(rpt, fee, path, engine): + scene = bpy.context.scene + + floor_me = bpy.data.meshes.new("Floor") + bm = bmesh.new() + try: + bmesh.ops.create_grid(bm, x_segments=1, y_segments=1, size=30.0) + bm.to_mesh(floor_me) + finally: + bm.free() + studio = principled("Studio", (0.03, 0.032, 0.037, 1.0), 0.0, 0.7) + floor_me.materials.append(studio) + floor = bpy.data.objects.new("Floor", floor_me) + scene.collection.objects.link(floor) + wall = bpy.data.objects.new("Wall", floor_me.copy()) + wall.data.materials.clear() + wall.data.materials.append(principled("Wall", (0.03, 0.032, 0.037, 1.0), 0.0, 0.7)) + wall.location = (0.0, 9.0, 0.0) + wall.rotation_euler = (math.pi / 2, 0.0, 0.0) + scene.collection.objects.link(wall) + + world = bpy.data.worlds.new("World") + world.use_nodes = True + world.node_tree.nodes["Background"].inputs["Color"].default_value = (0.02, 0.021, 0.025, 1.0) + scene.world = world + + def light(name, loc, energy, size, col, rot): + ld = bpy.data.lights.new(name, "AREA") + ld.energy = energy + ld.size = size + ld.color = col + ob = bpy.data.objects.new(name, ld) + ob.location = loc + ob.rotation_euler = tuple(math.radians(a) for a in rot) + scene.collection.objects.link(ob) + + light("Key", (-4.0, -5.0, 6.0), 520.0, 5.0, (1.0, 0.96, 0.9), (46, 0, -35)) + light("Fill", (5.0, -3.5, 3.0), 160.0, 9.0, (0.75, 0.85, 1.0), (62, 0, 50)) + light("Wedge", (2.5, 5.5, 4.0), 360.0, 6.0, (1.0, 0.76, 0.5), (-68, 0, 190)) + light("Glint", (0.4, -5.2, 5.5), 700.0, 0.9, (1.0, 0.92, 0.75), (42, 0, 8)) + + aim = bpy.data.objects.new("Aim", None) + aim.location = (0.0, 0.0, 1.50) + aim.hide_render = True + scene.collection.objects.link(aim) + cam_data = bpy.data.cameras.new("Cam") + cam_data.lens = 50.0 + cam = bpy.data.objects.new("Cam", cam_data) + cam.location = (6.6, -9.3, 3.55) + scene.collection.objects.link(cam) + scene.camera = cam + track = cam.constraints.new("TRACK_TO") + track.target = aim + track.track_axis = "TRACK_NEGATIVE_Z" + track.up_axis = "UP_Y" + + scene.render.engine = "CYCLES" if engine == "cycles" else eevee_engine_id() + if engine == "cycles": + scene.cycles.samples = 32 + else: + try: + scene.eevee.taa_render_samples = 64 + except AttributeError: + pass + scene.render.resolution_x = 1280 + scene.render.resolution_y = 720 + scene.render.image_settings.file_format = "PNG" + scene.render.filepath = path + scene.view_settings.view_transform = "Standard" + + hero = [rpt, fee] + fcode = gallery_framing.check_framing( + scene, cam, hero=hero, elements=hero, stage=[floor, wall], + ) + if fcode: + return fcode + bpy.ops.render.render(write_still=True) + if not (os.path.exists(path) and os.path.getsize(path) > 0): + print("ERROR: render produced no file", file=sys.stderr) + return 12 + return 0 + + +def main(): + argv = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [] + p = argparse.ArgumentParser() + p.add_argument("--output", default=None) + p.add_argument("--engine", default="eevee", choices=("eevee", "cycles")) + p.add_argument("--unpair-repeat", action="store_true") + p.add_argument("--unpair-foreach", action="store_true") + p.add_argument("--repeat-iterations", type=int, default=REPEAT_N) + p.add_argument("--foreach-count", type=int, default=FOREACH_P) + p.add_argument("--foreach-main", action="store_true", + help="falsification: Group Output reads For Each main Geometry") + p.add_argument("--no-offset", action="store_true", + help="falsification: Repeat Join without Iteration translation") + args = p.parse_args(argv) + + rpt, fee = build( + args.repeat_iterations, args.foreach_count, + pair_repeat=not args.unpair_repeat, + pair_foreach=not args.unpair_foreach, + offset_repeat=not args.no_offset, + foreach_generation=not args.foreach_main, + ) + code = check(rpt, fee, REPEAT_N, FOREACH_P) + if code: + return code + + if args.output: + rcode = render_still(rpt, fee, os.path.abspath(args.output), args.engine) + if rcode: + return rcode + print(f"rendered still {args.output}") + + print("gn-zone-iterate OK") + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Exception as exc: + print(f"ERROR: {type(exc).__name__}: {exc}", file=sys.stderr) + sys.exit(1) diff --git a/examples/gn-zone-iterate/preview.webp b/examples/gn-zone-iterate/preview.webp new file mode 100644 index 0000000000000000000000000000000000000000..459b37b26a77b2dadafe1931fa7fd52d289f1f4e GIT binary patch literal 10236 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