Command Palette

Search for a command to run...

Hectal
Course outline
Topic 7.4Intermediate ~22 min · step 4 of 6

Framing an Object

In one line

To fit an object in the picture, compute the camera distance from the field of view: d = (size / 2) / tan(fov / 2), using whichever of height and width is tighter. Then set near, far and the controls' limits from the same size, and do it again when the window changes shape.

0/6 · 0%

Think of it like this

When you photograph a painting you step back until all of it fits in the viewfinder. A wide painting needs you farther back than a tall one if your phone is held upright. The camera's field of view and the shape of the screen decide how far.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

bounding box
The smallest box, aligned with the axes, that holds an object. Box3 in three.js.
bounding sphere
The smallest sphere that holds an object. It is the same from every side, which makes it good for orbiting.
margin
Extra room around the object so it does not touch the edges of the picture.
tan(fov / 2)
Half the visible height at distance 1. Multiply by a distance to get half the visible height there.
tight side
The side of the picture (height or width) that runs out of room first, and so sets the distance.

Step by step

01Compute the distance

The first example prints a table. For each object it gives the "from any side" distance and the "face on" distance, then places a camera there and projects the 8 corners of the object's box. The largest corner coordinate shows how much of the picture it fills (1.00 would touch the edge).

02Read the table

The bike on 16:9 fills 0.87 of the height. On the upright phone it fills 0.87 of the width but only 0.26 of the height: width is the tight side. The screw prints near must go below 0.1, and the tower far must go above 100.

03Frame and refit

The second example has a frameObject() that sets the target, the position, near, far and the controls' limits from one bounding sphere. It runs for three window shapes, then for an empty group and for a scale-0 object.

04Guard before you frame

Read the last lines of the second example: the empty group and the scale-0 object are refused before any camera number changes, so the old view stays. That guard (box.isEmpty() and radius > 0) is the difference between "nothing to show yet" and a camera parked at NaN with a blank screen.

Try it yourself

  1. 1

    Remove the margin

    In the first example change margin = 1.15 to margin = 1 in fitFaceOn. The face-on bike on 16:9 prints 1.09 m fills x 0.88 y 1.00: the height now touches the top and bottom edges.

  2. 2

    A square window

    Add ["bike, square window", [1.4, 0.9, 0.12], 1], to things. The face-on distance is 1.94 m and it fills x 0.87, y 0.56: with aspect 1 the width is the tight side.

Code & diagrams

How far away for each object and screen New tab

No canvas here, only the maths and a check: the projected corners prove the fit. Face on means looking straight at the long side.

idle

Console

Run the scene to see its console.

Expected console output

bike, 16:9 screen       from any side 2.51 m | face on 1.25 m fills x 0.76 y 0.87 | near 0.1 is fine, far 100 is fine
bike, phone upright     from any side 4.98 m | face on 4.10 m fills x 0.87 y 0.26 | near 0.1 is fine, far 100 is fine
bike, ultra-wide 3.5:1  from any side 2.51 m | face on 1.25 m fills x 0.39 y 0.87 | near 0.1 is fine, far 100 is fine
a 2 cm screw            from any side 0.0319 m | face on 0.0156 m fills x 0.87 y 0.39 | near must go below 0.1, far 100 is fine
a 400 m tall tower      from any side 614 m | face on 555 m fills x 0.07 y 0.87 | near 0.1 is fine, far must go above 100
frameObject(): one function for every shape New tab

The bike here is two simple shapes. Drag to orbit: the limits came from the object's size. The last two lines are the guard for empty and scale-0 objects.

idle

Console

Run the scene to see its console.

Expected console output

16:9 screen            distance 2.65 m, limits 0.53 to 7.96 m
phone upright          distance 5.28 m, limits 0.53 to 15.83 m
phone turned sideways  distance 2.65 m, limits 0.53 to 7.96 m
nothing to frame: the object is empty or has scale 0
nothing to frame: the object is empty or has scale 0

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Forget the aspect

In fitFaceOn change the width term to width / 2 / tan (remove · aspect).

terminal
$ Run
── what you'll see ──
bike, 16:9 screen from any side 2.51 m | face on 1.94 m fills x 0.49 y 0.56 | ...
bike, phone upright from any side 4.98 m | face on 1.94 m fills x 1.84 y 0.56 | ...

Myth vs fact

Myth

Set the camera to z = 5 and it will fit everything.

Fact

Five metres fits the bike on a laptop and is far too near for the tall phone or the tower, and too far for the screw. Compute the distance from the size and the field of view.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Box3.setFromObject(object, true) uses each mesh's real vertices (precise = true) instead of the faster bounding boxes. It is more accurate for rotated parts and costs a pass over every vertex, so call it once, not every frame.

  • ▸

    A box is measured at one moment. A model that animates or moves can leave it later, so frame with a margin that covers the whole movement.

Remember this

  1. 1

    The problem this solves: a fixed camera position fits one object on one screen. A 2 cm screw, the bike and a 400 m tower, on a laptop and on a phone, each need a different distance. The distance must be computed, not guessed.

  2. 2

    The maths. Half the visible height at distance d is d · tan(fov / 2). So a height h fits when d = (h / 2) / tan(fov / 2). The visible width is the height times the aspect, so a width w fits when d = (w / 2) / (tan(fov / 2) · aspect). Use the larger of the two: the tighter side decides. Multiply by 1.15 to leave a margin.

  3. 3

    Real numbers. The bike is about 1.4 m long and 0.9 m tall. Seen from the side with fov 45° on a 16:9 screen it needs 1.25 m (the height is the tight side). On a phone held upright, aspect 9:19, the width is tight, and it needs 4.10 m. Same bike, same camera, more than three times farther.

  4. 4

    From any side. If the visitor orbits, the bike can face the camera at any angle, so fit its bounding sphere: d = radius · margin / sin(smaller / 2), where smaller is the smaller of the vertical and horizontal field of view (horizontal = 2 · atan(tan(fov / 2) · aspect)). For the bike this gives 2.51 m on 16:9 and 4.98 m on the upright phone. It is safe from every direction, a little loose from the side.

  5. 5

    Measure, do not hard-code. new THREE.Box3().setFromObject(object) gives the world-space box of an object and all its children (Topic 4.5). box.getBoundingSphere(new THREE.Sphere()) gives the centre and radius. Aim at the centre: controls.target.copy(sphere.center).

  6. 6

    Near, far and limits follow the size. A 2 cm screw seen from 1.6 cm needs near below the default 0.1, or the camera is inside the near plane. A 400 m tower needs a far above 100. Set near = distance / 100, far = distance * 100, minDistance to a share of the radius and maxDistance to a multiple of the distance, as the second example does. Keep the ratio far / near moderate (Topic 7.2).

  7. 7

    Edge cases. An empty group has an empty Box3 whose limits are Infinity: framing it gives NaN positions and an empty screen. An object with scale 0 has radius 0, so the distance is 0 and the camera lands inside it. Check box.isEmpty() and radius > 0 first. When the window changes shape, fit again, but only if the user has not moved the camera since (Topic 7.6).

Explain it without notes

01

Derive the distance at which an object h tall just fits, for a camera with vertical field of view fov.

02

Why does the same bike need a different camera distance on a phone held upright?

Practice

01

A shelf 2.4 m wide and 0.4 m tall is seen by a camera with fov 40° and aspect 2. How far must the camera be, with no margin?

02

Write the guard at the top of frameObject that stops it from framing an empty object, in one if.

Done when you can

  • Derive the fit distance from the field of view and the size

  • Choose the tight side from the aspect

  • Set near, far and the controls' limits from the object's size

  • Guard against empty and scale-0 objects and refit when the window changes shape