Audit prop budgets and add a prop-gallery art check

- audit_glb decodes geometry: 400 tris / 600 verts budget, degenerate
  triangles, UV range, ground contact, one material; newspaper box parts moved
  to sit on y=0
- capture_prop_gallery.gd renders the six props on a studio backdrop; new
  prop_gallery catalogue entry + AI mockup (compare 10 good, judge match 0.90)
- headless test that instances share the imported atlas material
- README documents the gallery capture and budget; TODO props pipeline section
  moved to DONE
This commit is contained in:
zwitschi committed 2026-11-01 10:27:27 +01:00
1 parent bb40a98537
commit 2a4e0d1998
12 files changed
+310 -22

No files matched your search

+37
View File
@@ -195,6 +195,43 @@ class AuditTests(unittest.TestCase):
self.assertFalse(result["ok"])
self.assertTrue(result["issues"])
def test_audit_enforces_the_triangle_budget(self):
old = model_pipeline.MAX_TRIANGLES
model_pipeline.MAX_TRIANGLES = 10
try:
path = self.root / "bench.glb"
path.write_bytes(model_pipeline.build_glb(prop("bench")))
result = model_pipeline.audit_glb(path)
finally:
model_pipeline.MAX_TRIANGLES = old
self.assertFalse(result["ok"])
self.assertTrue(any("triangle budget" in issue for issue in result["issues"]),
result["issues"])
def test_degenerate_triangle_helper(self):
self.assertEqual(
model_pipeline._triangle_area2((0, 0, 0), (1, 0, 0), (2, 0, 0)), 0.0)
self.assertGreater(
model_pipeline._triangle_area2((0, 0, 0), (1, 0, 0), (0, 1, 0)), 0.0)
def test_audit_reads_positions_and_uvs_from_the_binary(self):
parsed = parse_glb(model_pipeline.build_glb(prop("bollard")))
gltf, binary = parsed["gltf"], parsed["binary"]
primitive = gltf["meshes"][0]["primitives"][0]
positions = model_pipeline._read_float_accessor(
gltf, binary, primitive["attributes"]["POSITION"])
uvs = model_pipeline._read_float_accessor(
gltf, binary, primitive["attributes"]["TEXCOORD_0"])
indices = model_pipeline._read_index_accessor(
gltf, binary, primitive["indices"])
self.assertEqual(len(positions), gltf["accessors"][
primitive["attributes"]["POSITION"]]["count"])
self.assertEqual(len(uvs), len(positions))
self.assertEqual(len(indices) % 3, 0)
self.assertLess(min(p[1] for p in positions), 0.01)
for u, v in uvs:
self.assertTrue(0.0 <= u <= 1.0 and 0.0 <= v <= 1.0)
def test_build_writes_into_the_models_directory(self):
old = model_pipeline.MODELS_DIR
model_pipeline.MODELS_DIR = self.root