wip(L17, side branch): FloatingIslands seal-cap fix + owner/Core chunk-scale change (breaks SurfaceWorld)
Not for assembler/world: the 8 m -> 4 m strate chunk change moves every stratum, so the SurfaceWorld spawn camera floats in a void and the L1 mesh export shrank 58.7 -> 31.7 MB. Kept for its diagnostics, the boundarySeal finding and the readable capture shading. See Linux17/REPORT.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX
This commit is contained in:
1 parent
9a7c87e47b
commit
34ae1d7187
30 files changed
+1353
-70
No files matched your search
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Measure upward mesh faces around the FI/SW stratum interface."""
|
||||
import array
|
||||
import collections
|
||||
import math
|
||||
import struct
|
||||
import sys
|
||||
|
||||
|
||||
def read_exact(stream, size):
|
||||
data = stream.read(size)
|
||||
if len(data) != size:
|
||||
raise EOFError(f"wanted {size} bytes, got {len(data)}")
|
||||
return data
|
||||
|
||||
|
||||
path = sys.argv[1]
|
||||
low_z = float(sys.argv[2]) if len(sys.argv) > 2 else -80.0
|
||||
high_z = float(sys.argv[3]) if len(sys.argv) > 3 else -45.0
|
||||
with open(path, "rb") as stream:
|
||||
if read_exact(stream, 8) != b"VFMSH001":
|
||||
raise SystemExit("bad VFMSH001 header")
|
||||
version, voxel_um, tile_count = struct.unpack("<3I", read_exact(stream, 12))
|
||||
camera = struct.unpack("<3d", read_exact(stream, 24))
|
||||
yaw, pitch = struct.unpack("<2d", read_exact(stream, 16))
|
||||
per_lod = collections.defaultdict(lambda: {"tiles": 0, "faces": [], "spans": []})
|
||||
near_tiles = collections.defaultdict(list)
|
||||
for _ in range(tile_count):
|
||||
key = struct.unpack("<4i", read_exact(stream, 16))
|
||||
surf_vertices, skirt_count, vertex_count, index_count, mask_count = struct.unpack(
|
||||
"<5I", read_exact(stream, 20))
|
||||
p = array.array("f")
|
||||
p.frombytes(read_exact(stream, vertex_count * 12))
|
||||
n = array.array("f")
|
||||
n.frombytes(read_exact(stream, vertex_count * 12))
|
||||
if sys.byteorder != "little":
|
||||
p.byteswap(); n.byteswap()
|
||||
indices = array.array("I")
|
||||
indices.frombytes(read_exact(stream, index_count * 4))
|
||||
masks = read_exact(stream, mask_count)
|
||||
if sys.byteorder != "little":
|
||||
indices.byteswap()
|
||||
lod = key[3]
|
||||
z_values = []
|
||||
for tri in range(index_count // 3):
|
||||
if masks and masks[tri] != 0:
|
||||
continue
|
||||
a, b, c = indices[tri * 3:tri * 3 + 3]
|
||||
if max(a, b, c) >= surf_vertices:
|
||||
continue
|
||||
normal_z = (n[a * 3 + 2] + n[b * 3 + 2] + n[c * 3 + 2]) / 3.0
|
||||
if normal_z < 0.65:
|
||||
continue
|
||||
z = (p[a * 3 + 2] + p[b * 3 + 2] + p[c * 3 + 2]) / 3.0
|
||||
if low_z <= z <= high_z:
|
||||
z_values.append(z)
|
||||
if not z_values:
|
||||
continue
|
||||
z_values.sort()
|
||||
row = per_lod[lod]
|
||||
row["tiles"] += 1
|
||||
row["faces"].extend(z_values)
|
||||
span = z_values[math.floor(.95 * (len(z_values) - 1))] - z_values[math.floor(.05 * (len(z_values) - 1))]
|
||||
row["spans"].append(span)
|
||||
extent = 32 * (1 << lod) * voxel_um / 1_000_000.0
|
||||
cx = (key[0] + 0.5) * extent
|
||||
cy = (key[1] + 0.5) * extent
|
||||
near_tiles[lod].append((math.hypot(cx - camera[0], cy - camera[1]), key,
|
||||
z_values[len(z_values) // 2], span, len(z_values)))
|
||||
|
||||
|
||||
def q(values, fraction):
|
||||
return values[math.floor(fraction * (len(values) - 1))] if values else math.nan
|
||||
|
||||
|
||||
print(f"camera_m={camera} yaw={yaw} pitch={pitch} boundary_band_m={low_z}..{high_z}")
|
||||
print("lod tiles_with_boundary_faces faces z_m_p05/median/p95 tile_span_m_p50/p95/max")
|
||||
for lod in sorted(per_lod):
|
||||
row = per_lod[lod]
|
||||
spans = sorted(row["spans"])
|
||||
print(f"{lod} {row['tiles']} {len(row['faces'])} "
|
||||
f"{q(sorted(row['faces']), .05):.4f}/{q(sorted(row['faces']), .5):.4f}/"
|
||||
f"{q(sorted(row['faces']), .95):.4f} "
|
||||
f"{q(spans, .5):.4f}/{q(spans, .95):.4f}/{max(spans):.4f}")
|
||||
print("nearest_xy_boundary_tiles_by_lod:")
|
||||
for lod in sorted(near_tiles):
|
||||
for distance, key, median, span, faces in sorted(near_tiles[lod])[:3]:
|
||||
print(f"lod={lod} key={key} xy_distance_m={distance:.2f} "
|
||||
f"boundary_median_z={median:.4f} within_tile_p05_p95_m={span:.4f} faces={faces}")
|
||||
Reference in new issue
Block a user