From f77cc9c62535906a3462c9a9d8884cff3893359a Mon Sep 17 00:00:00 2001 From: Same Tadele Date: Wed, 10 Jun 2026 23:14:25 +0300 Subject: [PATCH 1/2] change: alter fitToBbox to fit in the two dimensions and from the prespective of center --- src/three-render-objects.js | 70 +++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/src/three-render-objects.js b/src/three-render-objects.js index 1b6bbf5..6b2b0d5 100644 --- a/src/three-render-objects.js +++ b/src/three-render-objects.js @@ -223,35 +223,69 @@ export default Kapsule({ return this.fitToBbox(this.getBbox(...bboxArgs), transitionDuration, padding); }, fitToBbox: function (state, bbox, transitionDuration = 0, padding = 10) { - // based on https://discourse.threejs.org/t/camera-zoom-to-fit-object/936/24 const camera = state.camera; - if (bbox) { - const center = new three.Vector3(0, 0, 0); // reset camera aim to center - const maxBoxSide = Math.max(...Object.entries(bbox) - .map(([coordType, coords]) => Math.max(...coords.map(c => Math.abs(center[coordType] - c)))) - ) * 2; + const center = new three.Vector3( + (bbox.x[0] + bbox.x[1]) / 2, + (bbox.y[0] + bbox.y[1]) / 2, + (bbox.z[0] + bbox.z[1]) / 2 + ); + + camera.updateMatrixWorld(); + const camRight = new three.Vector3(); + const camUp = new three.Vector3(); + const camForward = new three.Vector3(); + camera.getWorldDirection(camForward); + camRight.crossVectors(camForward, camera.up).normalize(); + camUp.crossVectors(camRight, camForward).normalize(); - // find distance that fits whole bbox within padded fov const paddedFov = (1 - (padding * 2 / state.height)) * camera.fov; - const fitHeightDistance = maxBoxSide / Math.atan(paddedFov * Math.PI / 180); - const fitWidthDistance = fitHeightDistance / camera.aspect; - const distance = Math.max(fitHeightDistance, fitWidthDistance); + const vFovHalf = (paddedFov / 2) * (Math.PI / 180); + const hFovHalf = Math.atan(Math.tan(vFovHalf) * camera.aspect); + + let maxDistance = 0; + const corners = [ + new three.Vector3(bbox.x[0], bbox.y[0], bbox.z[0]), + new three.Vector3(bbox.x[0], bbox.y[0], bbox.z[1]), + new three.Vector3(bbox.x[0], bbox.y[1], bbox.z[0]), + new three.Vector3(bbox.x[0], bbox.y[1], bbox.z[1]), + new three.Vector3(bbox.x[1], bbox.y[0], bbox.z[0]), + new three.Vector3(bbox.x[1], bbox.y[0], bbox.z[1]), + new three.Vector3(bbox.x[1], bbox.y[1], bbox.z[0]), + new three.Vector3(bbox.x[1], bbox.y[1], bbox.z[1]) + ]; + + for (const corner of corners) { + const localPos = corner.clone().sub(center); + const h = Math.abs(localPos.dot(camUp)); + const w = Math.abs(localPos.dot(camRight)); + const depthOffset = localPos.dot(camForward); + + const distH = h / Math.tan(vFovHalf) - depthOffset; + const distW = w / Math.tan(hFovHalf) - depthOffset; + maxDistance = Math.max(maxDistance, distH, distW); + } - if (distance > 0) { - const newCameraPosition = center.clone() - .sub(camera.position) - .normalize() - .multiplyScalar(-distance); + const distance = maxDistance; + const dir = camForward.clone().negate(); + const newPos = { + x: center.x + dir.x * distance, + y: center.y + dir.y * distance, + z: center.z + dir.z * distance, + }; + + this.cameraPosition( + newPos, + { x: center.x, y: center.y, z: center.z }, + transitionDuration + ); - this.cameraPosition(newCameraPosition, center, transitionDuration); - } } return this; }, getBbox: function (state, objFilter = () => true) { - const box = new three.Box3(new three.Vector3(0, 0, 0), new three.Vector3(0, 0, 0)); + const box = new three.Box3(); const objs = state.objects.filter(objFilter); if (!objs.length) return null; From c6e66de8da0e1e0dc4a9377e62bbbd3ff07751b8 Mon Sep 17 00:00:00 2001 From: Same Tadele Date: Wed, 10 Jun 2026 23:15:18 +0300 Subject: [PATCH 2/2] add: example to demonstrate the effect of the new fitToBox and in extension zoom --- example/zoom-implementation/index.html | 121 +++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 example/zoom-implementation/index.html diff --git a/example/zoom-implementation/index.html b/example/zoom-implementation/index.html new file mode 100644 index 0000000..7888bb8 --- /dev/null +++ b/example/zoom-implementation/index.html @@ -0,0 +1,121 @@ + + + + + + + + + + +
+
+ + + +
+ + +