Files
Aislo/resources/tester/helper_135_2_grayscale.cjs
T
eomsangdonandClaude Sonnet 5.5 db83a06a6b test(508-1b 옛 헬퍼 공용 불러오기 1/7): 헬퍼 26 곳 loadTs 베낌 걷고 makeLoader 로 — 공용 불러오기에 옵션 넷(requireFor · interop · cache · fileStub) 늘림
- helper_ts_stub_loader: 옛 헬퍼가 저마다 다르게 쓰던 것(풀이 함수 직접 · esModuleInterop · 캐시 끔 · 파일 통째 대역)을 옵션으로 · 기본 풀이는 그대로
- 헬퍼 동작 그대로(풀이 함수 본문은 옮겨 담음) · 제품 코드 안 고침
- 확인: 이 묶음 헬퍼를 쓰는 시험 241 개 전 241 통과 → 후 241 통과 (비교 = 시험별 junit)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 17:06:06 +09:00

94 lines
3.7 KiB
JavaScript

/* PLAN 135-2 — 흑백 지형 단추: 분할본 색 = 지형 원래 색 · far 색 버퍼 따로 · 원래 색 기억 = 색 버퍼 열쇠.
* TS 를 트랜스파일해 돌리고 결과(JSON)를 낸다(helper_115_8 과 같은 방식). */
const fs = require("fs");
const path = require("path");
const ROOT = path.resolve(__dirname, "..", "..");
const NM = path.join(ROOT, "config", "node_modules");
const { makeLoader } = require("./helper_ts_stub_loader.cjs");
const THREE = require(path.join(NM, "three"));
const { loadTs } = makeLoader({
root: ROOT,
cache: false,
requireFor: (full) => {
return (r) => (r === "three" ? THREE : require(r));
},
});
const B05 = (name) => path.join(ROOT, "B05_Profile", `${name}.ts`);
const { TerrainBandSplit, ORIGINAL_COLORS } = loadTs(B05("B05_Profile_UI_Corridor_Split"));
// 뷰어 applyGrayscaleTo 와 같은 규칙(색 버퍼 열쇠로 원본 한 번만 기억).
function gray(object, on) {
object.traverse((child) => {
const color = child.geometry?.getAttribute("color");
if (!color) return;
const target = color.array;
let original = ORIGINAL_COLORS.get(color);
if (!original) {
original = target.slice();
ORIGINAL_COLORS.set(color, original);
}
if (on) {
for (let i = 0; i + 2 < original.length; i += 3) {
const g = 0.299 * original[i] + 0.587 * original[i + 1] + 0.114 * original[i + 2];
target[i] = target[i + 1] = target[i + 2] = g;
}
} else target.set(original);
});
}
// 지형 — 40 × 40 m 격자 · 색 = 빨강 → 초록(회색과 다름).
const N = 21;
const pos = [];
const col = [];
const idx = [];
for (let j = 0; j < N; j += 1)
for (let i = 0; i < N; i += 1) {
pos.push(i * 2 - 20, 0, j * 2 - 20);
col.push(1, i / (N - 1), 0);
}
for (let j = 0; j + 1 < N; j += 1)
for (let i = 0; i + 1 < N; i += 1) {
const a = j * N + i;
idx.push(a, a + N, a + 1, a + 1, a + N, a + N + 1);
}
const geometry = new THREE.BufferGeometry();
geometry.setAttribute("position", new THREE.Float32BufferAttribute(pos, 3));
geometry.setAttribute("color", new THREE.Float32BufferAttribute(col, 3));
geometry.setIndex(idx);
const terrain = new THREE.Group();
terrain.add(new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({ vertexColors: true })));
const original = Float32Array.from(col);
gray(terrain, true); // 기본 흑백 — 지형 적재 직후 회색 먼저.
const split = new TerrainBandSplit(terrain, { minX: -5, maxX: 5, minZ: -5, maxZ: 5 });
const near = split.near[0].geometry.getAttribute("color");
const far = split.far[0].geometry.getAttribute("color");
const same = (a, b) => a.length === b.length && a.every((v, k) => Math.abs(v - b[k]) < 1e-6);
const r = {};
r.nearOriginal = same(near.array, original);
r.farOriginal = same(far.array, original);
r.farOwnBuffer = near !== far && near.array !== far.array;
// far 를 감싼 메시 두 번(③ 다시 짬) — 흑백 → 끔이 원래 색으로.
const wrap = () => {
const root = new THREE.Group();
root.add(new THREE.Mesh(split.far[0].geometry, split.far[0].material));
return root;
};
const first = wrap();
gray(first, true);
r.nearUntouchedByFarGray = same(near.array, original);
const second = wrap();
gray(second, true); // 새 메시 — 회색을 원본으로 잡으면 안 됨.
gray(second, false);
r.farBackToOriginal = same(far.array, original);
gray(terrain, false);
r.terrainBackToOriginal = same(geometry.getAttribute("color").array, original);
// 뷰어가 같은 열쇠를 쓰는가.
const viewer = fs.readFileSync(B05("B05_Profile_UI_Viewer"), "utf8");
r.viewerUsesKey =
viewer.includes("ORIGINAL_COLORS.get(color)") && !viewer.includes("userData.originalColors");
process.stdout.write(JSON.stringify(r));