Automatic camera positioning to fit objects, bounding boxes, and spheres with configurable padding and framing options.
Automatically position camera to frame bounding boxes or Three.js objects with configurable padding.
/**
* Fit camera to view a bounding box or Three.js object
* @param box3OrObject - Three.js Box3 or Object3D to fit to
* @param enableTransition - Whether to animate the camera movement
* @param options - Optional padding and framing configuration
* @returns Promise array that resolves when all movements complete
*/
fitToBox(
box3OrObject: THREE.Box3 | THREE.Object3D,
enableTransition: boolean,
options?: Partial<FitToOptions>
): Promise<void[]>;
interface FitToOptions {
cover: boolean; // true = fill viewport, false = fit entirely
paddingLeft: number; // Left padding (0-1 or pixels)
paddingRight: number; // Right padding (0-1 or pixels)
paddingBottom: number; // Bottom padding (0-1 or pixels)
paddingTop: number; // Top padding (0-1 or pixels)
}Usage Examples:
import * as THREE from 'three';
// Fit to a mesh with default settings
const mesh = new THREE.Mesh(geometry, material);
await cameraControls.fitToBox(mesh, true);
// Fit with custom padding (values 0-1 for viewport percentage)
await cameraControls.fitToBox(mesh, true, {
paddingLeft: 0.1, // 10% left padding
paddingRight: 0.1, // 10% right padding
paddingTop: 0.2, // 20% top padding
paddingBottom: 0.05 // 5% bottom padding
});
// Cover mode (fills viewport, may crop object)
await cameraControls.fitToBox(mesh, true, {
cover: true,
paddingLeft: 0.05,
paddingRight: 0.05,
paddingTop: 0.05,
paddingBottom: 0.05
});
// Fit to explicit bounding box
const customBox = new THREE.Box3(
new THREE.Vector3(-5, -3, -2),
new THREE.Vector3(5, 7, 8)
);
await cameraControls.fitToBox(customBox, true);
// Multiple objects using group
const group = new THREE.Group();
group.add(mesh1, mesh2, mesh3);
await cameraControls.fitToBox(group, true);Automatically position camera to frame bounding spheres or Three.js objects.
/**
* Fit camera to view a bounding sphere or Three.js object
* @param sphereOrMesh - Three.js Sphere or Object3D to fit to
* @param enableTransition - Whether to animate the camera movement
* @returns Promise array that resolves when all movements complete
*/
fitToSphere(
sphereOrMesh: THREE.Sphere | THREE.Object3D,
enableTransition: boolean
): Promise<void[]>;Usage Examples:
// Fit to mesh using computed bounding sphere
const mesh = new THREE.Mesh(geometry, material);
await cameraControls.fitToSphere(mesh, true);
// Fit to explicit sphere
const customSphere = new THREE.Sphere(
new THREE.Vector3(0, 5, 0), // center
10 // radius
);
await cameraControls.fitToSphere(customSphere, true);
// Instant fitting without transition
await cameraControls.fitToSphere(mesh, false);
// Create bounding sphere from object using static method
const boundingSphere = CameraControls.createBoundingSphere(complexObject);
await cameraControls.fitToSphere(boundingSphere, true);Multi-Object Fitting:
// Fit to multiple objects using group
const scene = new THREE.Scene();
const group = new THREE.Group();
// Add multiple objects to group
group.add(
new THREE.Mesh(geometry1, material1),
new THREE.Mesh(geometry2, material2),
new THREE.Mesh(geometry3, material3)
);
scene.add(group);
// Fit camera to encompass all objects
await cameraControls.fitToBox(group, true, {
paddingLeft: 0.1,
paddingRight: 0.1,
paddingTop: 0.1,
paddingBottom: 0.1
});Responsive Fitting:
// Fit with different padding based on viewport size
const aspectRatio = window.innerWidth / window.innerHeight;
const padding = aspectRatio > 1.5 ? 0.05 : 0.15; // Less padding on wide screens
await cameraControls.fitToBox(mesh, true, {
paddingLeft: padding,
paddingRight: padding,
paddingTop: padding,
paddingBottom: padding
});Sequential Fitting:
// Fit to multiple objects in sequence
const objects = [mesh1, mesh2, mesh3];
for (const obj of objects) {
await cameraControls.fitToBox(obj, true, {
paddingLeft: 0.2,
paddingRight: 0.2,
paddingTop: 0.2,
paddingBottom: 0.2
});
// Wait before fitting to next object
await new Promise(resolve => setTimeout(resolve, 2000));
}Cover vs Contain:
// Contain mode (default): entire object visible with padding
await cameraControls.fitToBox(mesh, true, {
cover: false,
paddingLeft: 0.1,
paddingRight: 0.1,
paddingTop: 0.1,
paddingBottom: 0.1
});
// Cover mode: object fills viewport, may be partially cropped
await cameraControls.fitToBox(mesh, true, {
cover: true, // Fill viewport
paddingLeft: 0,
paddingRight: 0,
paddingTop: 0,
paddingBottom: 0
});Use distance calculation utilities for manual camera positioning:
// From boundaries-constraints.md - repeated here for context
getDistanceToFitBox(width: number, height: number, depth: number, cover?: boolean): number;
getDistanceToFitSphere(radius: number): number;Manual Fitting Examples:
// Calculate and apply distance manually
const box = new THREE.Box3().setFromObject(mesh);
const size = box.getSize(new THREE.Vector3());
const center = box.getCenter(new THREE.Vector3());
// Calculate distance
const distance = cameraControls.getDistanceToFitBox(size.x, size.y, size.z);
// Apply manually with custom target
await Promise.all([
cameraControls.setTarget(center.x, center.y, center.z, true),
cameraControls.dollyTo(distance, true)
]);
// Sphere fitting manually
geometry.computeBoundingSphere();
const sphere = geometry.boundingSphere;
const sphereDistance = cameraControls.getDistanceToFitSphere(sphere.radius);
await Promise.all([
cameraControls.setTarget(sphere.center.x, sphere.center.y, sphere.center.z, true),
cameraControls.dollyTo(sphereDistance, true)
]);Combine fitting with viewport configuration for advanced layout scenarios:
// Set viewport before fitting
cameraControls.setViewport(0, 0, 800, 600);
await cameraControls.fitToBox(mesh, true);
// Reset viewport after fitting
cameraControls.setViewport(null);
// Multi-viewport fitting
const leftViewport = new THREE.Vector4(0, 0, 400, 600);
const rightViewport = new THREE.Vector4(400, 0, 400, 600);
// Fit for left viewport
cameraControls.setViewport(leftViewport);
await cameraControls.fitToBox(leftObject, true);
// Fit for right viewport
cameraControls.setViewport(rightViewport);
await cameraControls.fitToBox(rightObject, true);// Check for valid geometry before fitting
if (mesh.geometry && mesh.geometry.boundingBox) {
await cameraControls.fitToBox(mesh, true);
} else {
console.warn('Mesh has no bounding box for fitting');
mesh.geometry.computeBoundingBox();
await cameraControls.fitToBox(mesh, true);
}
// Handle empty or degenerate boxes
const box = new THREE.Box3().setFromObject(mesh);
if (!box.isEmpty()) {
await cameraControls.fitToBox(box, true);
} else {
console.warn('Object has empty bounding box');
}
// Ensure minimum padding for small objects
const minPadding = 0.05;
await cameraControls.fitToBox(mesh, true, {
paddingLeft: Math.max(calculatedPadding, minPadding),
paddingRight: Math.max(calculatedPadding, minPadding),
paddingTop: Math.max(calculatedPadding, minPadding),
paddingBottom: Math.max(calculatedPadding, minPadding)
});