diff --git a/cockpit/public/torso-frames/torso_000.png b/cockpit/public/torso-frames/torso_000.png index a86aef2a6..f5a1307a9 100644 Binary files a/cockpit/public/torso-frames/torso_000.png and b/cockpit/public/torso-frames/torso_000.png differ diff --git a/cockpit/public/torso-frames/torso_001.png b/cockpit/public/torso-frames/torso_001.png index 51333cb71..4dd67c791 100644 Binary files a/cockpit/public/torso-frames/torso_001.png and b/cockpit/public/torso-frames/torso_001.png differ diff --git a/cockpit/public/torso-frames/torso_002.png b/cockpit/public/torso-frames/torso_002.png index b78930177..3eab89230 100644 Binary files a/cockpit/public/torso-frames/torso_002.png and b/cockpit/public/torso-frames/torso_002.png differ diff --git a/cockpit/public/torso-frames/torso_003.png b/cockpit/public/torso-frames/torso_003.png index e213da1a6..20bdc6c79 100644 Binary files a/cockpit/public/torso-frames/torso_003.png and b/cockpit/public/torso-frames/torso_003.png differ diff --git a/cockpit/public/torso-frames/torso_004.png b/cockpit/public/torso-frames/torso_004.png index 2d42a10ad..13a125821 100644 Binary files a/cockpit/public/torso-frames/torso_004.png and b/cockpit/public/torso-frames/torso_004.png differ diff --git a/cockpit/public/torso-frames/torso_005.png b/cockpit/public/torso-frames/torso_005.png index 9aa34aaef..8fae3a85e 100644 Binary files a/cockpit/public/torso-frames/torso_005.png and b/cockpit/public/torso-frames/torso_005.png differ diff --git a/cockpit/public/torso-frames/torso_006.png b/cockpit/public/torso-frames/torso_006.png index c42cec1fa..07576ba2c 100644 Binary files a/cockpit/public/torso-frames/torso_006.png and b/cockpit/public/torso-frames/torso_006.png differ diff --git a/cockpit/public/torso-frames/torso_007.png b/cockpit/public/torso-frames/torso_007.png index c730f4ea7..019921f31 100644 Binary files a/cockpit/public/torso-frames/torso_007.png and b/cockpit/public/torso-frames/torso_007.png differ diff --git a/cockpit/public/torso-frames/torso_008.png b/cockpit/public/torso-frames/torso_008.png index bf7b7444a..f849b6552 100644 Binary files a/cockpit/public/torso-frames/torso_008.png and b/cockpit/public/torso-frames/torso_008.png differ diff --git a/cockpit/public/torso-frames/torso_009.png b/cockpit/public/torso-frames/torso_009.png index 21441a1df..1d355e909 100644 Binary files a/cockpit/public/torso-frames/torso_009.png and b/cockpit/public/torso-frames/torso_009.png differ diff --git a/cockpit/public/torso-frames/torso_010.png b/cockpit/public/torso-frames/torso_010.png index 03d841802..356fda5ca 100644 Binary files a/cockpit/public/torso-frames/torso_010.png and b/cockpit/public/torso-frames/torso_010.png differ diff --git a/cockpit/public/torso-frames/torso_011.png b/cockpit/public/torso-frames/torso_011.png index 760e0b1de..4fec8b2cc 100644 Binary files a/cockpit/public/torso-frames/torso_011.png and b/cockpit/public/torso-frames/torso_011.png differ diff --git a/cockpit/public/torso-frames/torso_012.png b/cockpit/public/torso-frames/torso_012.png index 1ccc71605..f0ebe639b 100644 Binary files a/cockpit/public/torso-frames/torso_012.png and b/cockpit/public/torso-frames/torso_012.png differ diff --git a/cockpit/public/torso-frames/torso_013.png b/cockpit/public/torso-frames/torso_013.png index 1782541ef..78e139194 100644 Binary files a/cockpit/public/torso-frames/torso_013.png and b/cockpit/public/torso-frames/torso_013.png differ diff --git a/cockpit/public/torso-frames/torso_014.png b/cockpit/public/torso-frames/torso_014.png index 045f3b680..87402eef1 100644 Binary files a/cockpit/public/torso-frames/torso_014.png and b/cockpit/public/torso-frames/torso_014.png differ diff --git a/cockpit/public/torso-frames/torso_015.png b/cockpit/public/torso-frames/torso_015.png index 679a95ab7..449179653 100644 Binary files a/cockpit/public/torso-frames/torso_015.png and b/cockpit/public/torso-frames/torso_015.png differ diff --git a/cockpit/public/torso-frames/torso_016.png b/cockpit/public/torso-frames/torso_016.png index f3564a0ed..576f14379 100644 Binary files a/cockpit/public/torso-frames/torso_016.png and b/cockpit/public/torso-frames/torso_016.png differ diff --git a/cockpit/public/torso-frames/torso_017.png b/cockpit/public/torso-frames/torso_017.png index b8ec6e441..aa48ff34c 100644 Binary files a/cockpit/public/torso-frames/torso_017.png and b/cockpit/public/torso-frames/torso_017.png differ diff --git a/cockpit/public/torso-frames/torso_018.png b/cockpit/public/torso-frames/torso_018.png index d6b2c257b..e22c490c0 100644 Binary files a/cockpit/public/torso-frames/torso_018.png and b/cockpit/public/torso-frames/torso_018.png differ diff --git a/cockpit/public/torso-frames/torso_019.png b/cockpit/public/torso-frames/torso_019.png index 81df57a17..aa5f16139 100644 Binary files a/cockpit/public/torso-frames/torso_019.png and b/cockpit/public/torso-frames/torso_019.png differ diff --git a/cockpit/src/TorsoMap.tsx b/cockpit/src/TorsoMap.tsx index 8ac423951..e462ff7b9 100644 --- a/cockpit/src/TorsoMap.tsx +++ b/cockpit/src/TorsoMap.tsx @@ -44,8 +44,8 @@ interface Spl3 { } // SPL3 body (22 B): pos 3f | normal 3i8 | rgb 3u8 | opacity u8 | scale u8 | node_row u16. -// Orientation: +90 about X, (x,y,z) -> (x,-z,y) — matches the bake/driver so the -// body stands head-up (BodyParts3D model +Z is superior). +// Orientation: (x,y,z) -> (-x, z, y), a proper rotation that stands the body head-up +// in three.js's Y-up world (BodyParts3D model +Z is superior -> +Y up). function decodeSpl3(buf: ArrayBuffer): Spl3 { const dv = new DataView(buf); const magic = String.fromCharCode(dv.getUint8(0), dv.getUint8(1), dv.getUint8(2), dv.getUint8(3)); @@ -62,9 +62,9 @@ function decodeSpl3(buf: ArrayBuffer): Spl3 { for (let i = 0; i < count; i++) { const b = off + i * 22; const x = dv.getFloat32(b, true), y = dv.getFloat32(b + 4, true), z = dv.getFloat32(b + 8, true); - positions[i * 3] = x; positions[i * 3 + 1] = -z; positions[i * 3 + 2] = y; + positions[i * 3] = -x; positions[i * 3 + 1] = z; positions[i * 3 + 2] = y; const nx = dv.getInt8(b + 12) / 127, ny = dv.getInt8(b + 13) / 127, nz = dv.getInt8(b + 14) / 127; - normals[i * 3] = nx; normals[i * 3 + 1] = -nz; normals[i * 3 + 2] = ny; + normals[i * 3] = -nx; normals[i * 3 + 1] = nz; normals[i * 3 + 2] = ny; colors[i * 3] = dv.getUint8(b + 15) / 255; colors[i * 3 + 1] = dv.getUint8(b + 16) / 255; colors[i * 3 + 2] = dv.getUint8(b + 17) / 255; diff --git a/cockpit/src/TorsoMesh.tsx b/cockpit/src/TorsoMesh.tsx index 201ea1727..c956fcd6d 100644 --- a/cockpit/src/TorsoMesh.tsx +++ b/cockpit/src/TorsoMesh.tsx @@ -35,7 +35,10 @@ interface Mesh { // | bbox_min 3f | bbox_max 3f // vertex body vert_count x 21 B: pos 3f | normal 3i8 | rgb 3u8 | opacity u8 | node_row u16 // index body tri_count x 12 B: 3x u32 (global vertex indices) -// Orientation +90 about X, (x,y,z) -> (x,-z,y), so the body stands head-up. +// Orientation (x,y,z) -> (-x, z, y): a proper rotation (det +1, so triangle winding +// and gl_FrontFacing stay correct) that stands the body head-up in three.js's Y-up +// world (model +Z superior -> world +Y up; +Y anterior -> +Z toward viewer). No +// screen-flip — three.js is Y-up, so the rotation lives entirely in the decode. function decodeSpm1(buf: ArrayBuffer): Mesh { const dv = new DataView(buf); const magic = String.fromCharCode(dv.getUint8(0), dv.getUint8(1), dv.getUint8(2), dv.getUint8(3)); @@ -50,9 +53,9 @@ function decodeSpm1(buf: ArrayBuffer): Mesh { for (let i = 0; i < vertCount; i++) { const b = voff + i * 21; const x = dv.getFloat32(b, true), y = dv.getFloat32(b + 4, true), z = dv.getFloat32(b + 8, true); - positions[i * 3] = x; positions[i * 3 + 1] = -z; positions[i * 3 + 2] = y; - normals[i * 3] = dv.getInt8(b + 12) / 127; - normals[i * 3 + 1] = -dv.getInt8(b + 14) / 127; + positions[i * 3] = -x; positions[i * 3 + 1] = z; positions[i * 3 + 2] = y; + normals[i * 3] = -dv.getInt8(b + 12) / 127; + normals[i * 3 + 1] = dv.getInt8(b + 14) / 127; normals[i * 3 + 2] = dv.getInt8(b + 13) / 127; colors[i * 3] = dv.getUint8(b + 15); colors[i * 3 + 1] = dv.getUint8(b + 16); diff --git a/cockpit/src/TorsoSplat.tsx b/cockpit/src/TorsoSplat.tsx index 69aecf61c..af84b26d3 100644 --- a/cockpit/src/TorsoSplat.tsx +++ b/cockpit/src/TorsoSplat.tsx @@ -61,11 +61,12 @@ function decodeSpl3(buf: ArrayBuffer): Spl3 { const scale = new Float32Array(count); for (let i = 0; i < count; i++) { const b = off + i * 22; - // upright: +90 about X, (x,y,z) -> (x,-z,y) (matches bake/driver); normals too. + // upright: (x,y,z) -> (-x, z, y), a proper rotation that stands the body head-up + // in three.js's Y-up world (model +Z superior -> +Y up). normals rotate the same way. const x = dv.getFloat32(b, true), y = dv.getFloat32(b + 4, true), z = dv.getFloat32(b + 8, true); - positions[i * 3] = x; positions[i * 3 + 1] = -z; positions[i * 3 + 2] = y; - normals[i * 3] = dv.getInt8(b + 12) / 127; - normals[i * 3 + 1] = -dv.getInt8(b + 14) / 127; + positions[i * 3] = -x; positions[i * 3 + 1] = z; positions[i * 3 + 2] = y; + normals[i * 3] = -dv.getInt8(b + 12) / 127; + normals[i * 3 + 1] = dv.getInt8(b + 14) / 127; normals[i * 3 + 2] = dv.getInt8(b + 13) / 127; colors[i * 3] = dv.getUint8(b + 15); colors[i * 3 + 1] = dv.getUint8(b + 16);