ArcRotateCamera orbits a target in spherical coordinates: alpha (longitude), beta (angle down from straight up) and radius. Dragging changes the angles, the wheel the radius, and right-drag pans. It suits product viewers and overviews like First Render's:
const camera = new BABYLON.ArcRotateCamera('overview', -Math.PI / 2, Math.PI / 3, 10,
new BABYLON.Vector3(0, 1, 0), scene); // alpha, beta, radius, target
console.log(camera.position.asArray().map((c) => +c.toFixed(2)));
camera.upperRadiusLimit = 12; // zoom out no farther than 12 m
camera.lowerBetaLimit = 0.3; // never look straight down
camera.upperBetaLimit = 1.4; // stay above the floor
camera.radius = 100;
camera.beta = 0.01;
scene.render(); // limits apply as the camera updates
console.log(camera.radius, camera.beta);Output
BJS - [15:49:20]: Babylon.js v9.28.0 - WebGL2 - Parallel shader compilation [0, 6, -8.66] 12 0.3
With alpha at -90 degrees the camera sits on the -z side, 10 m from the target at 60 degrees from vertical: (0, 1 + 10 cos 60°, -10 sin 60°). The limits were enforced at the next frame, not at assignment. Also useful: wheelDeltaPercentage (zoom by a fraction of the radius), panningSensibility = 0 (no panning) and useAutoRotationBehavior (a turntable spin).
<!doctype html>
<style>
body { margin: 0; background: #f7f3ec; font: 13px system-ui, sans-serif; color: #333; }
canvas { width: 100%; max-width: 600px; height: 340px; display: block; touch-action: none; }
#info { max-width: 600px; padding: 4px 8px; font-family: monospace; }
</style>
<canvas id="view"></canvas>
<div id="info"></div>
<script src="https://cdn.jsdelivr.net/npm/babylonjs@9.28.0/babylon.js"></script>
<script>
const canvas = document.getElementById('view');
const engine = new BABYLON.Engine(canvas, true);
const scene = new BABYLON.Scene(engine);
scene.clearColor = BABYLON.Color4.FromHexString('#cfd8dcff');
new BABYLON.HemisphericLight('sky', new BABYLON.Vector3(0.3, 1, -0.4), scene)
.groundColor = new BABYLON.Color3(0.35, 0.32, 0.3);
// alpha (longitude), beta (angle down from straight up), radius, target
const camera = new BABYLON.ArcRotateCamera('overview', -Math.PI / 2, Math.PI / 3, 10,
new BABYLON.Vector3(0, 1, 0), scene);
camera.attachControl(canvas, true); // drag to orbit, wheel to zoom, right-drag to pan
camera.lowerRadiusLimit = 4;
camera.upperRadiusLimit = 12; // zoom out no farther than 12 m
camera.lowerBetaLimit = 0.3; // never look straight down
camera.upperBetaLimit = 1.4; // stay above the floor
camera.wheelDeltaPercentage = 0.01; // zoom by a fraction of the radius
camera.useAutoRotationBehavior = true; // a turntable spin until you drag
camera.autoRotationBehavior.idleRotationSpeed = 0.25;
// BookNest's empty room: 8 m wide, 6 m deep, 3 m high, front wall off
const paint = (mesh, hex) => {
mesh.material = new BABYLON.StandardMaterial(hex, scene);
mesh.material.diffuseColor = BABYLON.Color3.FromHexString(hex);
mesh.material.specularColor = BABYLON.Color3.Black();
};
paint(BABYLON.MeshBuilder.CreateGround('floor', { width: 8, height: 6 }, scene), '#b08d6a');
for (const [name, width, x, z] of [['back', 8, 0, 3], ['left', 6, -4, 0], ['right', 6, 4, 0]]) {
const wall = BABYLON.MeshBuilder.CreateBox(name, { width, height: 3, depth: 0.15 }, scene);
wall.position.set(x, 1.5, z);
wall.rotation.y = x ? Math.PI / 2 : 0;
paint(wall, '#fff3e0');
}
const COLORS = ['#1f5f8b', '#5b3f99', '#e09a10', '#3f7d3a', '#b5452f', '#2a9d8f'];
COLORS.forEach((hex, i) => { // a table of books at the target
const book = BABYLON.MeshBuilder.CreateBox('book' + i, { width: 0.5, height: 0.08, depth: 0.7 }, scene);
book.position.set(0, 0.84 + i * 0.08, 0);
book.rotation.y = i * 0.3;
paint(book, hex);
});
paint(BABYLON.MeshBuilder.CreateCylinder('table', { height: 0.8, diameter: 1.4 }, scene), '#6d4c33');
scene.getMeshByName('table').position.y = 0.4;
const info = document.getElementById('info');
const deg = (r) => (r * 180 / Math.PI).toFixed(0);
scene.onAfterRenderObservable.add(() => { // limits are enforced as the camera updates
info.textContent = `alpha ${deg(camera.alpha)}° beta ${deg(camera.beta)}° [${deg(0.3)}..${deg(1.4)}] ` +
`radius ${camera.radius.toFixed(1)} m [4..12]`;
});
engine.runRenderLoop(() => scene.render());
addEventListener('resize', () => engine.resize());
</script>