Use camera Z-up coordinates without modifying GLB imports

This commit is contained in:
2026-09-20 17:14:37 +08:00
parent 8cafbb326b
commit 53285d04af
7 changed files with 20 additions and 42 deletions

View File

@@ -28,22 +28,6 @@ export const MACHINE_PART_ROLES: MachinePartRole[] = ["base", "x", "y", "z", "to
export const roleLabel = (role: MachinePartRole, coordinates: string) => ({ base: "床身底座", x: "X 轴部件", y: "Y 轴部件", z: "Z 轴部件", tool: "主轴/刀具", tilt: `${coordinates === "XYZBC" ? "B" : "A"} 轴部件`, c: "C 轴部件", work: "工件/工作台" }[role]);
export const expectedParentRole = (role: MachinePartRole): MachinePartRole | null => ({ base: null, x: "base", y: "x", z: "y", tool: "z", tilt: "base", c: "tilt", work: "c" }[role] as MachinePartRole | null);
// glTF uses Y-up. The editor exposes the machine's right-handed X/Y/Z frame
// with Z-up: machine (x, y, z) -> Three.js (x, z, -y).
export const machineToThree = (value: Vec3): Vec3 => [value[0], value[2], -value[1]];
export const threeToMachine = (value: Vec3): Vec3 => [value[0], -value[2], value[1]];
export const machineFrameQuaternion = () => new THREE.Quaternion().setFromRotationMatrix(new THREE.Matrix4().set(1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1));
export function machineEulerToThreeQuaternion(rotationDeg: Vec3) {
const machine = new THREE.Euler(...rotationDeg.map(THREE.MathUtils.degToRad) as Vec3, "XYZ");
const source = new THREE.Matrix4().makeRotationFromEuler(machine);
const frame = new THREE.Matrix4().set(1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1);
return new THREE.Quaternion().setFromRotationMatrix(frame.clone().multiply(source).multiply(frame.clone().invert()));
}
export function threeQuaternionToMachineEuler(rotation: THREE.Quaternion) {
const frame = machineFrameQuaternion();
const machine = frame.clone().invert().multiply(rotation);
return new THREE.Euler().setFromQuaternion(machine, "XYZ").toArray().slice(0, 3).map((radians) => THREE.MathUtils.radToDeg(Number(radians))) as Vec3;
}
const finite3 = (value: Vec3, label: string) => {
if (value.length !== 3 || value.some((number) => !Number.isFinite(number))) throw new Error(`${label}需要三个有限数值`);
@@ -137,10 +121,10 @@ export async function buildManagedMachine(input: { coordinates: "XYZAC" | "XYZBC
for (const role of MACHINE_PART_ROLES) {
const part = byRole.get(role)!;
const placement = new THREE.Group(); placement.name = `component_${part.id}`; placement.visible = part.visible;
placement.position.fromArray(machineToThree(part.translationMm)).multiplyScalar(.001);
placement.quaternion.copy(machineEulerToThreeQuaternion(part.rotationDeg));
placement.position.fromArray(part.translationMm).multiplyScalar(.001);
placement.rotation.set(...part.rotationDeg.map(THREE.MathUtils.degToRad) as Vec3);
placement.userData.machinePart = { role, filename: part.filename, hash: part.hash, originMm: [...part.originMm] };
const visual = cloneMachinePartScene(part.scene); visual.position.fromArray(machineToThree(part.originMm).map((value) => -value) as Vec3).multiplyScalar(.001); placement.add(visual); links[role].add(placement);
const visual = cloneMachinePartScene(part.scene); visual.position.fromArray(part.originMm).multiplyScalar(-.001); placement.add(visual); links[role].add(placement);
}
links.base.userData.linuxcncMachineGeometry = metadata;
const signature = JSON.stringify({ metadata, hashes: MACHINE_PART_ROLES.map((role) => byRole.get(role)!.hash) });