diff --git a/nonpacks/static/js/geo_builder.js b/nonpacks/static/js/geo_builder.js index c0029f1..fee66f8 100644 --- a/nonpacks/static/js/geo_builder.js +++ b/nonpacks/static/js/geo_builder.js @@ -202,13 +202,24 @@ var origin = c.origin || [0, 0, 0]; var size = c.size || [1, 1, 1]; var cRot = (c.rotation || [0, 0, 0]).map(function (d) { return -d * DEG; }); + var hasRot = !!(c.rotation && (c.rotation[0] || c.rotation[1] || c.rotation[2])); + // Blockbench cubes rotate around their own pivot (fall back to origin). + var cPivot = hasRot ? (c.pivot || origin) : origin; + var center = [ + origin[0] + size[0] / 2, + origin[1] + size[1] / 2, + origin[2] + size[2] / 2, + ]; var cubeWorld = multiply( world, multiply( - translation(origin[0], origin[1], origin[2]), + translation(cPivot[0], cPivot[1], cPivot[2]), multiply( rotationXYZ(cRot[0], cRot[1], cRot[2]), - translation(size[0] / 2, size[1] / 2, size[2] / 2) + multiply( + translation(-cPivot[0], -cPivot[1], -cPivot[2]), + translation(center[0], center[1], center[2]) + ) ) ) ); diff --git a/nonpacks/static/js/tests/geo_builder.test.js b/nonpacks/static/js/tests/geo_builder.test.js index 58651ac..90b294f 100644 --- a/nonpacks/static/js/tests/geo_builder.test.js +++ b/nonpacks/static/js/tests/geo_builder.test.js @@ -148,6 +148,24 @@ for (const w of wolfCenters) { assert(wTail.center[2] > 8, `wolf tail behind body (z=${wTail.center[2].toFixed(1)})`); assert(wBody && wTail.center[2] > wBody.center[2], 'tail z > body z'); +// ---------- 5. Real polar bear: cube-level pivot + rotation ---------- +// The polar bear's rear torso cube has its own pivot/rotation; rotating around +// the cube origin (not its pivot) sent it flying to z≈48. Regression test. +const polar = require(path.join(__dirname, 'fixtures', 'polar_bear.geo.json')); +const polarBuilt = GeoBuilder.build(polar); +const polarCubes = polarBuilt.cubes.map(c => ({ c, center: worldCenter(c.matrix) })); +const pRear = polarCubes.find(({ c }) => c.size[0] === 18.2 && c.size[1] === 18.2 && c.size[2] === 14.3); +assert(!!pRear, 'polar bear rear torso cube found'); +if (pRear) { + assertVec(pRear.center, [0, 17.55, 7.8], 'polar bear rear torso center (expect (0,17.55,7.8))'); +} +const pFront = polarCubes.find(({ c }) => c.size[0] === 15.6 && c.size[1] === 15.6 && c.size[2] === 13); +if (pFront) { + // Rear torso sits behind and at the same height as the front torso. + assert(pRear.center[2] > pFront.center[2], 'rear torso behind front torso'); + assert(approx(pRear.center[1], pFront.center[1], 1.5), 'rear + front torso at similar height'); +} + // ---------- summary ---------- if (failures === 0) { console.log(`geo_builder tests OK (${checks} checks)`);