Files
healer-man/scripts/runewaker-pipeline/audit-environment-quality.test.mjs
2026-10-06 22:25:34 -04:00

117 lines
6.5 KiB
JavaScript

import assert from "node:assert/strict";
import { mkdtemp, rm } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import test from "node:test";
import { Accessor, Document, NodeIO } from "@gltf-transform/core";
import { EXTMeshGPUInstancing } from "@gltf-transform/extensions";
import {
mappingMetrics,
nodeInstanceTransforms,
sourceImageAliasKey,
transformInstancedPoint,
triangleArea,
} from "./audit-environment-quality.mjs";
test("source image aliases preserve unresolved or used alpha and normalize only known-unused alpha", () => {
const source = new Uint8Array([
255, 64, 32, 0,
10, 20, 30, 255,
]);
const aliasWithDifferentAlpha = new Uint8Array([
255, 64, 32, 200,
10, 20, 30, 1,
]);
const opaqueA = sourceImageAliasKey({ width: 2, height: 1, rgba: source, alphaMode: "OPAQUE", alphaUsed: false });
const opaqueB = sourceImageAliasKey({ width: 2, height: 1, rgba: aliasWithDifferentAlpha, alphaMode: "OPAQUE", alphaUsed: false });
assert.equal(opaqueA, opaqueB, "opaque texture aliases are compared using RGB and dimensions");
assert.notEqual(sourceImageAliasKey({ width: 2, height: 1, rgba: source, alphaMode: "OPAQUE" }),
sourceImageAliasKey({ width: 2, height: 1, rgba: aliasWithDifferentAlpha, alphaMode: "OPAQUE" }),
"varying source alpha stays part of identity when native use is unresolved");
const uniformTranslucent = new Uint8Array([255, 64, 32, 128, 10, 20, 30, 128]);
const uniformOpaque = new Uint8Array([255, 64, 32, 255, 10, 20, 30, 255]);
assert.notEqual(sourceImageAliasKey({ width: 2, height: 1, rgba: uniformTranslucent, alphaMode: "OPAQUE" }),
sourceImageAliasKey({ width: 2, height: 1, rgba: uniformOpaque, alphaMode: "OPAQUE" }),
"uniform non-opaque alpha also remains part of identity when native use is unresolved");
const nativeAlphaA = sourceImageAliasKey({ width: 2, height: 1, rgba: source, alphaMode: "OPAQUE", alphaUsed: true });
const nativeAlphaB = sourceImageAliasKey({ width: 2, height: 1, rgba: aliasWithDifferentAlpha, alphaMode: "OPAQUE", alphaUsed: true });
assert.notEqual(nativeAlphaA, nativeAlphaB, "native translucency preserves RGBA even if the converted material says OPAQUE");
const blendedA = sourceImageAliasKey({ width: 2, height: 1, rgba: source, alphaMode: "BLEND" });
const blendedB = sourceImageAliasKey({ width: 2, height: 1, rgba: aliasWithDifferentAlpha, alphaMode: "BLEND" });
assert.notEqual(blendedA, blendedB, "materials that use alpha retain separate RGBA identities");
assert.notEqual(opaqueA, sourceImageAliasKey({ width: 1, height: 2, rgba: source, alphaMode: "OPAQUE", alphaUsed: false }),
"equal pixel bytes at another image shape do not alias");
assert.notEqual(opaqueA, sourceImageAliasKey({ width: 2, height: 1, rgba: source, alphaMode: "OPAQUE", alphaUsed: false, baseColorFactor: [0.5, 1, 1, 1] }),
"material base-color factors remain part of rendered source equivalence");
});
test("instance TRS expansion preserves UV rank and accounts for transformed area and cells", async () => {
const temporaryDirectory = await mkdtemp(path.join(os.tmpdir(), "rom-quality-instancing-test-"));
const fixtureFile = path.join(temporaryDirectory, "instances.glb");
try {
const document = new Document();
const buffer = document.createBuffer();
const positions = document.createAccessor("POSITION")
.setType(Accessor.Type.VEC3)
.setArray(new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]))
.setBuffer(buffer);
const primitive = document.createPrimitive().setAttribute("POSITION", positions);
const node = document.createNode("fixture-node")
.setMesh(document.createMesh("fixture-mesh").addPrimitive(primitive))
.setTranslation([5, 2, 0])
.setScale([2, 1, 1]);
const instanceExtension = document.createExtension(EXTMeshGPUInstancing);
const instancedMesh = instanceExtension.createInstancedMesh()
.setAttribute("TRANSLATION", document.createAccessor("TRANSLATION")
.setType(Accessor.Type.VEC3)
.setArray(new Float32Array([0, 0, 0, 40, 0, 0]))
.setBuffer(buffer))
.setAttribute("ROTATION", document.createAccessor("ROTATION")
.setType(Accessor.Type.VEC4)
.setArray(new Float32Array([0, 0, 0, 1, 0, 0, Math.SQRT1_2, Math.SQRT1_2]))
.setBuffer(buffer))
.setAttribute("SCALE", document.createAccessor("SCALE")
.setType(Accessor.Type.VEC3)
.setArray(new Float32Array([2, 1, 1, 1, 3, 1]))
.setBuffer(buffer));
node.setExtension("EXT_mesh_gpu_instancing", instancedMesh);
document.createScene("fixture-scene").addChild(node);
const io = new NodeIO().registerExtensions([EXTMeshGPUInstancing]);
await io.write(fixtureFile, document);
const parsed = await io.read(fixtureFile);
const parsedNode = parsed.getRoot().listNodes().find((candidate) => candidate.getName() === "fixture-node");
const transforms = nodeInstanceTransforms(parsedNode);
assert.equal(transforms.length, 2, "NodeIO reads both instance records");
const worldMatrix = parsedNode.getWorldMatrix();
const triangle = [[0, 0, 0], [1, 0, 0], [0, 1, 0]];
const uvTriangle = [[0, 0], [1, 0], [0, 1]];
const collinearUvs = [[0, 0], [1, 1], [2, 2]];
const expandedTriangles = transforms.map((transform) => triangle.map((point) =>
transformInstancedPoint(worldMatrix, point, transform)));
const areas = expandedTriangles.map(triangleArea);
assert.ok(Math.abs(areas[0] - 2) < 1e-9 && Math.abs(areas[1] - 3) < 1e-6,
"instance and node scales transform each triangle's area");
assert.ok(Math.abs(areas.reduce((total, area) => total + area, 0) - 5) < 1e-6,
"both placed triangles contribute their transformed surface area");
const cells = expandedTriangles.map((points) => {
const centroidX = points.reduce((total, point) => total + point[0] / 3, 0);
return Math.floor(centroidX / 20);
});
assert.deepEqual(cells, [0, 4], "instance TRS precedes the non-identity node world transform");
for (const points of expandedTriangles) {
const valid = mappingMetrics(points, uvTriangle, 1024, 1024);
const degenerate = mappingMetrics(points, collinearUvs, 1024, 1024);
assert.ok(valid && valid.uvDoubleArea > 0 && valid.smallestStretchPxPerMeter > 0,
"an invertible texture mapping retains UV rank under instance TRS");
assert.equal(degenerate?.uvDoubleArea, 0, "collinear UVs remain degenerate under instance TRS");
}
} finally {
await rm(temporaryDirectory, { recursive: true, force: true });
}
});