Files
supart-ComfyUI-TY360-Photo-…/web/pano_preview_render.js
T

94 lines
2.6 KiB
JavaScript

// Shared preview render-facing primitives.
// Kept intentionally small in this refactor phase; runtime still hosts the
// full draw pipeline and can be incrementally migrated here.
import { getCutoutShotParams } from "./pano_cutout_projection.js";
import { clamp, wrapYaw, shortestYawDelta } from "./pano_math.js";
export const DEG2RAD = Math.PI / 180;
export const RAD2DEG = 180 / Math.PI;
export { clamp, wrapYaw, shortestYawDelta };
export function vec3(x, y, z) {
return { x, y, z };
}
export function add(a, b) {
return vec3(a.x + b.x, a.y + b.y, a.z + b.z);
}
export function mul(a, s) {
return vec3(a.x * s, a.y * s, a.z * s);
}
export function dot(a, b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}
export function cross(a, b) {
return vec3(
a.y * b.z - a.z * b.y,
a.z * b.x - a.x * b.z,
a.x * b.y - a.y * b.x,
);
}
export function norm(a) {
const l = Math.hypot(a.x, a.y, a.z) || 1e-8;
return vec3(a.x / l, a.y / l, a.z / l);
}
export function yawPitchToDir(yawDeg, pitchDeg) {
const yaw = yawDeg * DEG2RAD;
const pitch = pitchDeg * DEG2RAD;
const cp = Math.cos(pitch);
return vec3(cp * Math.sin(yaw), Math.sin(pitch), cp * Math.cos(yaw));
}
export function cameraBasis(yawDeg, pitchDeg, rollDeg = 0) {
const fwd = yawPitchToDir(yawDeg, pitchDeg);
const worldUp = vec3(0, 1, 0);
let right = cross(worldUp, fwd);
if (Math.hypot(right.x, right.y, right.z) < 1e-6) right = vec3(1, 0, 0);
right = norm(right);
const up0 = norm(cross(fwd, right));
const rr = rollDeg * DEG2RAD;
const cr = Math.cos(rr);
const sr = Math.sin(rr);
const r2 = add(mul(right, cr), mul(up0, sr));
const u2 = add(mul(right, -sr), mul(up0, cr));
return { fwd, right: norm(r2), up: norm(u2) };
}
export function parseState(text, bg = "#00ff00") {
const base = {
version: 1,
projection_model: "pinhole_rectilinear",
alpha_mode: "straight",
bg_color: bg,
output_preset: 2048,
assets: {},
stickers: [],
shots: [],
active: { selected_sticker_id: null },
};
const trimmed = String(text || "").trim();
if (!trimmed) return base;
try {
const p = JSON.parse(trimmed);
if (!p || typeof p !== "object") return base;
return {
...base,
...p,
assets: p.assets && typeof p.assets === "object" && !Array.isArray(p.assets) ? p.assets : {},
stickers: Array.isArray(p.stickers) ? p.stickers : [],
shots: Array.isArray(p.shots) ? p.shots : [],
active: p.active && typeof p.active === "object" && !Array.isArray(p.active) ? p.active : base.active,
};
} catch {
return base;
}
}
export { getCutoutShotParams };