Exact-pixel and production-perf comparison of6c79d35c(+ only the A2 normal files, so no terrain mask is needed) againstc51b07efwith no pack: connected as +Acdream, visible window, one isolated config clone per variant, pinned clocks. Open field: the only differences are idle pose, mana digits and a passing flyer. Holtburg: same-binary-twice defines the dynamic mask (9.8%); in the static 90% both self-diffs have ZERO pixels with |d|>=8 while base+normals vs HEAD-off has 841/729 - all streaks inside the animated lifestone. Buildings, ground, trees, sky and UI are clean. Perf (uncapped Release, no automation observer, ACDREAM_FRAME_PROF=1): Holtburg CPU p50 4.7 -> 4.1 ms, Arwic 6.0 -> 5.2 ms, GPU unchanged, alloc/frame 574 KB -> 21 KB. No regression; F5b's '27.8 ms retail CPU' was the observer. Three false alarms recorded so nobody repeats them: the isolated gate settings lack fieldOfView (90 vs the real 86.33 -> a 0.952 zoom); the real %APPDATA% settings still selected acdream.atmospheric/low (pack ON); a minimized GLFW window is throttled and never settles. Tools: tools/vm0/capture-visible.ps1 (pre-campaign gate + -Exe/-Live/ -ConfigDir/-CharacterName/-PreCaptureCommand), tools/vm0/perf-run.sh, and -BuildingDetailTextures on run-offline-pixel-gate.ps1. Baseline patches under docs/research/evidence/vm0/. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
31 lines
1.6 KiB
Python
31 lines
1.6 KiB
Python
import sys, numpy as np
|
|
from PIL import Image
|
|
root = r"artifacts/vm0"
|
|
def load(n): return np.asarray(Image.open(f"{root}/{n}/screenshots/world-offline.png").convert("RGB")).astype(np.int16)
|
|
def cmp(a, b, name, maskTop=0):
|
|
A, B = load(a), load(b)
|
|
assert A.shape == B.shape, (A.shape, B.shape)
|
|
d = np.abs(A - B).max(axis=2)
|
|
H, W = d.shape
|
|
region = d[maskTop:, :]
|
|
diff = region > 0
|
|
n = int(diff.sum()); tot = region.size
|
|
rows = np.where(diff.any(axis=1))[0]
|
|
print(f"{name}: {n} / {tot} px differ ({100.0*n/tot:.5f}%)"
|
|
+ (f" rows {rows.min()+maskTop}-{rows.max()+maskTop}, max|d|={int(region.max())}, mean|d| over differing={region[diff].mean():.2f}" if n else " IDENTICAL"))
|
|
if n:
|
|
hist = np.bincount(region[diff].astype(np.int64), minlength=8)
|
|
print(f" |d| histogram 1..7+: {hist[1:8].tolist()} ...>=8: {int((region[diff]>=8).sum())}")
|
|
vis = np.zeros((H, W, 3), np.uint8)
|
|
vis[..., 0] = np.clip(d * 16, 0, 255).astype(np.uint8) # red = difference amplified x16
|
|
base = (A.astype(np.float32) * 0.25).astype(np.uint8)
|
|
vis = np.maximum(vis, base)
|
|
Image.fromarray(vis).save(f"{root}/diff-{name}.png")
|
|
return n
|
|
print("== whole frame, exact ==")
|
|
cmp("base", "base-normals", "A2-normals-only")
|
|
cmp("base-normals", "head-off", "HEAD-off_vs_base+normals")
|
|
cmp("head-off", "head-on", "detail-on_vs_off")
|
|
cmp("base", "head-off", "HEAD-off_vs_base")
|
|
print("== top-280 sky band masked (the tool's documented self-noise band) ==")
|
|
cmp("base-normals", "head-off", "HEAD-off_vs_base+normals_masked", 280)
|