Match LiTo's project layout. Net file moves:
spz_route.py -> nodes/spz_route.py
install.py -> root (was briefly in nodes/)
server_tools/ -> web/server_tools/ (Node JS subprocess
tool — non-python
asset, sits next to
browser-served web/)
Root and nodes/ now mirror ComfyUI-LiTo:
Root: __init__.py, install.py, pyproject.toml, comfy-env-root.toml,
comfy-test.toml, README.md, LICENSE, web/, scripts/, nodes/
nodes/: __init__.py, comfy-env.toml, common.py, preview_gaussian.py,
merge_gaussians.py, load_ply.py, spz_route.py
## Root __init__.py — LiTo-style
import logging
log = logging.getLogger("comfyui-gaussianpack")
from comfy_env import register_nodes
NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS = register_nodes()
WEB_DIRECTORY = "./web"
Delegates node discovery to `comfy_env.register_nodes()`, which scans
`nodes/__init__.py` for the mappings. WEB_DIRECTORY stays at root
(points at top-level web/) so ComfyUI's static handler doesn't have to
walk into nodes/.
## nodes/__init__.py — clean child package
Imports PreviewGaussians, GaussianMerge, LoadPLY from sibling modules,
calls register_routes() for the SPZ HTTP route, exposes the two
mapping dicts. Dropped `WEB_DIRECTORY` (it belongs at root).
## nodes/comfy-env.toml — pixi env declaration
numpy + plyfile + nanogs (git pip). Same content as before — was
previously at root, where comfy-env's discovery wouldn't pick it up
for isolation purposes. Now lives where comfy-env expects.
## spz_route.py — path fix
NODE_SCRIPT was `THIS_DIR / "server_tools" / "ply_to_spz.mjs"` when the
file was at root. Now at nodes/ with server_tools moved to web/, so:
NODE_SCRIPT = THIS_DIR.parent / "web" / "server_tools" / "ply_to_spz.mjs"
Smoke test (worker pixi env):
PYTHONPATH=.../ComfyUI:. python -c "import nodes; print(nodes.NODE_CLASS_MAPPINGS)"
-> {'PreviewGaussians': ..., 'GaussianMerge': ..., 'LoadPLY': ...}
126 lines
3.7 KiB
JavaScript
126 lines
3.7 KiB
JavaScript
export const PI = Math.PI;
|
|
export function halfToFloat(h) {
|
|
const sgn = (h >> 15) & 0x1;
|
|
const exponent = (h >> 10) & 0x1f;
|
|
const mantissa = h & 0x3ff;
|
|
const signMul = sgn === 1 ? -1.0 : 1.0;
|
|
if (exponent === 0) {
|
|
return signMul * Math.pow(2, -14) * mantissa / 1024;
|
|
}
|
|
if (exponent === 31) {
|
|
return mantissa !== 0 ? NaN : signMul * Infinity;
|
|
}
|
|
return signMul * Math.pow(2, exponent - 15) * (1 + mantissa / 1024);
|
|
}
|
|
export function floatToHalf(f) {
|
|
const buffer = new ArrayBuffer(4);
|
|
const view = new DataView(buffer);
|
|
view.setFloat32(0, f);
|
|
const f32 = view.getUint32(0);
|
|
const sign = (f32 >> 31) & 0x01;
|
|
const exponent = (f32 >> 23) & 0xff;
|
|
const mantissa = f32 & 0x7fffff;
|
|
if (exponent === 0xff) {
|
|
if (mantissa === 0) {
|
|
return (sign << 15) | 0x7c00;
|
|
}
|
|
return (sign << 15) | 0x7c01;
|
|
}
|
|
const centeredExp = exponent - 127;
|
|
if (centeredExp > 15) {
|
|
return (sign << 15) | 0x7c00;
|
|
}
|
|
if (centeredExp > -15) {
|
|
return (sign << 15) | ((centeredExp + 15) << 10) | (mantissa >> 13);
|
|
}
|
|
const fullMantissa = 0x800000 | mantissa;
|
|
const shift = -(centeredExp + 14);
|
|
const newMantissa = fullMantissa >> shift;
|
|
return (sign << 15) | (newMantissa >> 13);
|
|
}
|
|
export function axisAngleQuat(scaledAxis) {
|
|
const [a0, a1, a2] = scaledAxis;
|
|
const thetaSquared = a0 * a0 + a1 * a1 + a2 * a2;
|
|
if (thetaSquared > 0) {
|
|
const theta = Math.sqrt(thetaSquared);
|
|
const halfTheta = theta * 0.5;
|
|
const k = Math.sin(halfTheta) / theta;
|
|
return normalized([Math.cos(halfTheta), a0 * k, a1 * k, a2 * k]);
|
|
}
|
|
const k = 0.5;
|
|
return normalized([1.0, a0 * k, a1 * k, a2 * k]);
|
|
}
|
|
export function isVec3f(v) {
|
|
return v.length === 3;
|
|
}
|
|
export function isQuat4f(v) {
|
|
return v.length === 4;
|
|
}
|
|
export function vec3f(data) {
|
|
return [data[0], data[1], data[2]];
|
|
}
|
|
export function quat4f(data) {
|
|
return [data[0], data[1], data[2], data[3]];
|
|
}
|
|
export function dot(a, b) {
|
|
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
}
|
|
export function squaredNorm(v) {
|
|
return v.reduce((sum, val) => sum + val * val, 0);
|
|
}
|
|
export function norm(v) {
|
|
return Math.sqrt(squaredNorm(v));
|
|
}
|
|
export function normalized(v) {
|
|
const n = norm(v);
|
|
return v.map(x => x / n);
|
|
}
|
|
// Quaternion multiplication with a vector
|
|
export function timesVec3(q, p) {
|
|
const [w, x, y, z] = q;
|
|
const [vx, vy, vz] = p;
|
|
const x2 = x + x;
|
|
const y2 = y + y;
|
|
const z2 = z + z;
|
|
const wx2 = w * x2;
|
|
const wy2 = w * y2;
|
|
const wz2 = w * z2;
|
|
const xx2 = x * x2;
|
|
const xy2 = x * y2;
|
|
const xz2 = x * z2;
|
|
const yy2 = y * y2;
|
|
const yz2 = y * z2;
|
|
const zz2 = z * z2;
|
|
return [
|
|
vx * (1.0 - (yy2 + zz2)) + vy * (xy2 - wz2) + vz * (xz2 + wy2),
|
|
vx * (xy2 + wz2) + vy * (1.0 - (xx2 + zz2)) + vz * (yz2 - wx2),
|
|
vx * (xz2 - wy2) + vy * (yz2 + wx2) + vz * (1.0 - (xx2 + yy2))
|
|
];
|
|
}
|
|
// Quaternion multiplication
|
|
export function timesQuat(a, b) {
|
|
const [w, x, y, z] = a;
|
|
const [qw, qx, qy, qz] = b;
|
|
return normalized([
|
|
w * qw - x * qx - y * qy - z * qz,
|
|
w * qx + x * qw + y * qz - z * qy,
|
|
w * qy - x * qz + y * qw + z * qx,
|
|
w * qz + x * qy - y * qx + z * qw
|
|
]);
|
|
}
|
|
// Scalar multiplication
|
|
export function timesScalar(v, s) {
|
|
return v.map(x => x * s);
|
|
}
|
|
// Vector/quaternion addition
|
|
export function plus(a, b) {
|
|
return a.map((x, i) => x + b[i]);
|
|
}
|
|
// Convert Vec3f to Quat4f with w component
|
|
export function vec3ToQuat4(v, w) {
|
|
return [w, v[0], v[1], v[2]]; // w first, then xyz
|
|
}
|
|
export function quatToVec3(q) {
|
|
return [q[1], q[2], q[3]]; // Skip w, take xyz
|
|
}
|