Files
VoxelForge/Standalone/Research/WorldAssemblerM3/Linux60/CaptureFarLODsL60.py
T
Fr0zkaandClaude Opus 5.5 c0c204ba50 fix: signed-overflow UB in VoxelHash made cave placement compiler-dependent; all generators LOD0-8; speed matrix (L60)
VoxelHash::Cell/Pair, legacy Cellular3D and the shared Core cellular hash added 0x7FFFFFFF to a signed
int32 before casting to uint32; overflow is undefined, so Clang and GCC placed cave passage 1 differently
(first differing sample at LOD1 tile (0,64,-512)). The bias is now done in unsigned arithmetic, in both the
standalone copy and the Unreal plugin header (Source/VoxelForge/Public/VoxelCaveMorphology.h). Native
caves, motifs and lattice now stream LOD0-8 with skirts and cross-level transitions. New verify.py
--speed-matrix runs every generator on one asserted-identical view (5 interleaved runs): motifs 1.33,
profiles 1.30-1.32, caves 1.41, natural SW 1.67, lattice 1.70, FI 4.93 s whole view. fast/medium/full PASS,
Clang/GCC peer hashes equal. Research R29 (open-edge ledge) and R30 (compiler-divergence suspects).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
2026-10-26 01:50:15 +01:00

220 lines
11 KiB
Python

#!/usr/bin/env python3
"""Render cave, motif, and lattice features from meshes streamed at LOD4-8."""
from __future__ import annotations
import argparse
import hashlib
import importlib.util
import json
import math
import os
from pathlib import Path
import re
import struct
import sys
ROOT = Path(__file__).resolve().parents[4]
CAPTURE54 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux54/CaptureNativeCavesL54.py"
spec = importlib.util.spec_from_file_location("capture_native_caves_l54", CAPTURE54)
capture54 = importlib.util.module_from_spec(spec)
assert spec and spec.loader
spec.loader.exec_module(capture54)
run_step = capture54.run_step
camera_angles = capture54.camera_angles
fmt = capture54.fmt
QUALITY = ROOT / "Standalone/Tools/verify/capture_quality.py"
Q = 1_000_000.0
def sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
digest.update(block)
return digest.hexdigest()
def midpoint(points: list[tuple[float, float, float]]) -> tuple[float, float, float]:
return tuple(sum(point[axis] for point in points) / len(points) for axis in range(3))
def read_feature(name: str, layout_path: Path):
layout = json.loads(layout_path.read_text(encoding="utf-8"))
if name == "caves":
edges = sorted(layout.get("cavern_edges", []), key=lambda row: row["stable_id"])
if len(edges) != 2:
raise ValueError("cave layout must have two resolved spine edges")
points = [[value / Q for value in point]
for point in edges[0]["control_points_um"]]
target = tuple(points[-1][axis] for axis in range(3))
return target, target[2] + 2.0, 28.0, "cave mouth"
if name == "motifs":
monolith = next(row for row in layout.get("stamps", []) if row.get("kind") == 5)
target = tuple(value / Q for value in monolith["position_um"])
floor = monolith["floor_um"] / Q
return (target[0], target[1], floor + 12.0), floor + 12.0, 32.0, "monolith"
edges = layout.get("cavern_edges", [])
helix = next((edge for edge in edges
if edge.get("stable_id") == "lattice/spine/01-helix-ramp-v1"), None)
if helix is None:
raise ValueError("lattice layout has no resolved helix")
points = [tuple(value / Q for value in point) for point in helix["polyline_um"]]
target = midpoint(points)
return target, target[2] + 4.0, 36.0, "helix"
def audit_roi_lods(mesh: Path, center: tuple[float, float, float], radius: float):
roi_counts: dict[int, int] = {}
roi_skirts: dict[int, int] = {}
with mesh.open("rb") as stream:
prefix = stream.read(60)
if len(prefix) != 60 or prefix[:8] != b"VFMSH001":
raise ValueError("far-LOD audit requires a VFMSH001 Core mesh")
version, voxel_um, tile_count = struct.unpack_from("<3I", prefix, 8)
if version != 1 or voxel_um <= 0:
raise ValueError("mesh version or voxel size is invalid")
for _ in range(tile_count):
header = stream.read(36)
if len(header) != 36:
raise ValueError("truncated far-LOD tile header")
key = struct.unpack_from("<4i", header, 0)
surface_count, skirt_count, vertex_count, index_count, mask_count = \
struct.unpack_from("<5I", header, 16)
positions = stream.read(vertex_count * 12)
normals = stream.read(vertex_count * 12)
index_bytes = stream.read(index_count * 4)
masks = stream.read(mask_count)
if (len(positions) != vertex_count * 12
or len(normals) != vertex_count * 12
or len(index_bytes) != index_count * 4
or len(masks) != mask_count):
raise ValueError("truncated far-LOD tile payload")
lod = key[3]
coords = list(struct.iter_unpack("<3f", positions))
indices = struct.unpack(f"<{index_count}I", index_bytes) if index_count else ()
for triangle in range(index_count // 3):
ids = indices[triangle * 3:triangle * 3 + 3]
if max(ids) >= vertex_count:
raise ValueError("far-LOD triangle references an invalid vertex")
is_skirt = bool(masks and triangle < len(masks) and masks[triangle])
if is_skirt:
continue
centroid = tuple(sum(coords[index][axis] for index in ids) / 3.0
for axis in range(3))
distance_squared = sum((centroid[axis] - center[axis]) ** 2
for axis in range(3))
if distance_squared <= radius * radius:
roi_counts[lod] = roi_counts.get(lod, 0) + 1
if skirt_count:
roi_skirts[lod] = roi_skirts.get(lod, 0) + skirt_count
if stream.read(1):
raise ValueError("far-LOD mesh has trailing bytes")
return roi_counts, roi_skirts
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--out", type=Path, required=True)
parser.add_argument("--fixture-dir", type=Path, required=True)
parser.add_argument("--layout-dir", type=Path, required=True)
parser.add_argument("--headless", type=Path, required=True)
parser.add_argument("--renderer", type=Path, required=True)
parser.add_argument("--artifact-dir", type=Path, required=True)
args = parser.parse_args()
out = args.out.resolve()
fixture_dir, layout_dir = args.fixture_dir.resolve(), args.layout_dir.resolve()
artifact_dir = args.artifact_dir.resolve()
mesh_dir, png_dir = out / "far-lod-meshes", out / "far-lod-png"
for directory in (mesh_dir, png_dir, artifact_dir):
directory.mkdir(parents=True, exist_ok=True)
env = os.environ.copy()
env["LP_NUM_THREADS"] = "12"
env["XDG_CACHE_HOME"] = str(out / "xdg-cache")
cases = (
("caves", fixture_dir / "caves.json",
layout_dir / "native-caves-field-clang.json", "caves", []),
("motifs", fixture_dir / "style-override-motifs-slice1.json",
layout_dir / "motif-slice1-capsule-reachability-clang.json", "surface-world", []),
("lattice", fixture_dir / "lattice-l58.json",
layout_dir / "native-lattice-field-clang.json", "lattice", ["--lattice-strate=1"]),
)
quality_rows = []
for name, fixture, layout, recipe, extra_flags in cases:
if not fixture.is_file() or not layout.is_file():
raise RuntimeError(f"missing {name} fixture or layout")
target, target_height, radius, label = read_feature(name, layout)
stream_camera = (target[0] + 1024.0, target[1], target[2], 0.0, 0.0)
stream_yaw, stream_pitch = camera_angles(stream_camera[:3], target)
stream_camera = (*stream_camera[:3], stream_yaw, stream_pitch)
mesh = mesh_dir / f"{name}-lod4-8.vfmesh"
mesh_layout = layout_dir / f"{name}-far-lod-layout.json"
command = [args.headless, fixture, "--workers=12", "--world-assembler-prototype",
"--stream-benchmark", "--stream-pipeline", "--force-generate",
"--clip-radius=3", "--max-clip-level=8", "--max-level=-1",
"--render-distance-chunks=0", f"--recipe={recipe}",
f"--camera={fmt(stream_camera)}", *extra_flags,
f"--resolved-layout-output={mesh_layout}", f"--mesh-export={mesh}"]
output = run_step(f"{name}-far-lod-export", command,
out / f"capture-{name}-far-lod-export.log", env=env, stamped=True)
worker_rows = {int(match.group(1)): (int(match.group(2)), int(match.group(3)))
for match in re.finditer(
r"^\[WorldAssemblerLODWorker\] lod=(\d+) tiles=(\d+) .*?skirt_triangles=(\d+)",
output, re.M)}
if (set(worker_rows) != set(range(9))
or any(worker_rows[level][0] <= 0 for level in range(9))
or sum(worker_rows[level][1] for level in range(4, 9)) <= 0):
raise RuntimeError(f"{name} far view lacks LOD0-8 tile/skirt work: {worker_rows}")
if not mesh.is_file() or mesh.stat().st_size == 0:
raise RuntimeError(f"{name} far LOD export produced no mesh")
roi, roi_skirts = audit_roi_lods(mesh, target, radius)
feature_lods = sorted(level for level, count in roi.items() if count > 0)
far_feature_lods = [level for level in feature_lods if level >= 4]
if not far_feature_lods:
raise RuntimeError(f"{name} {label} has no non-skirt surface triangles in LOD4-8 ROI: {roi}")
camera = (target[0] + 18.0, target[1] - 28.0, target_height + 10.0)
yaw, pitch = camera_angles(camera, target)
png = png_dir / f"{name}-far-lod.png"
image = artifact_dir / f"{name}-far-lod.jpg"
render = [args.renderer, mesh, png, "--size=1280x720", "--fov-deg=76",
f"--camera-m={fmt(camera)}", f"--yaw-deg={yaw:.6f}",
f"--pitch-deg={pitch:.6f}", "--tile-skirts=on", "--shade=readable",
"--headlamp=on", "--height-tint=on", f"--height-center-m={target_height:.6f}",
"--height-range-m=42", "--tile-edges=off",
f"--focus-region={fmt((*target, radius))}"]
run_step(f"{name}-far-lod-render", render,
out / f"capture-{name}-far-lod-render.log", env=env, stamped=True)
run_step(f"{name}-far-lod-jpeg", ["ffmpeg", "-nostdin", "-hide_banner",
"-loglevel", "error", "-y", "-i", png, "-frames:v", "1", "-q:v", "5", image],
out / f"capture-{name}-far-lod-jpeg.log", env=env)
quality_output = run_step(f"{name}-far-lod-quality", [sys.executable, QUALITY, image],
out / f"capture-{name}-far-lod-quality.log", env=env)
quality = [line for line in quality_output.splitlines()
if line.startswith("[CaptureQuality]")]
if not quality or not quality[-1].endswith("status=PASS"):
raise RuntimeError(f"{name} far LOD capture failed its image quality gate")
size = image.stat().st_size
if not 0 < size <= 300_000:
raise RuntimeError(f"{name} far LOD capture exceeds 300 KB: {size}")
print(f"[L60FarLODCapture] generator={name} feature={label} file={image} "
f"bytes={size} sha256={sha256(image)} feature_lods={feature_lods} "
f"feature_triangles={sum(roi.values())} far_skirt_triangles="
f"{sum(value for lod, value in roi_skirts.items() if lod >= 4)} status=PASS",
flush=True)
quality_rows.append({"generator": name, "feature": label, "file": str(image),
"bytes": size, "sha256": sha256(image), "feature_triangles_by_lod": roi,
"feature_skirts_by_lod": roi_skirts})
(out / "far-lod-captures.json").write_text(json.dumps(quality_rows, indent=2) + "\n",
encoding="utf-8")
return 0
if __name__ == "__main__":
try:
raise SystemExit(main())
except Exception as error:
print(f"[L60FarLODCapture] status=FAIL error={error}", file=sys.stderr, flush=True)
raise SystemExit(1)