Frame the model
Choose a fitted camera direction, screen-up vector, projection, and margin while nanoraster solves placement from referenced geometry.
With a fitted camera, you choose an orientation. nanoraster solves the optical target, distance, and clip planes from indexed geometry that can be drawn. Use it for thumbnails, contact sheets, and any capture that must keep the whole subject in frame.
Set direction and screen up
direction points from the subject toward the camera. up establishes screen
vertical and preserves roll. Both are Cartesian vectors in the declared caller
world. The renderer ignores their magnitudes. Fitting may translate the camera
and optical target together without changing orientation.
Omit up on a fit camera and it becomes the declared world.up. Supply up
to roll the camera. A plan view's direction runs along that same axis and
names no roll. Screen-up comes from world.forward instead, so a plan view
needs no up.
import { directionFromOrbit, renderImage } from 'nanoraster';const world = { up: '+z', forward: '-y', unit: 'meter' } as const;const image = await renderImage(glb, { format: 'webp', world, camera: { framing: 'fit', direction: directionFromOrbit({ azimuth: 45, elevation: 30 }, world), },});Rendering…
advanced · direction XYZ
This worked request authors a three-quarter view in Z-up metres. nanoraster converts it once to the GLB frame. The live azimuth and elevation controls move the two angles in the copyable code. Expand advanced · direction XYZ for raw vector entry.
Turn angles into directions
directionFromOrbit converts orbit
angles to the Cartesian direction a fitted camera takes.
orbitFromDirection inverts it. Both
resolve their axes from the world you pass, so pass the same world the
request declares, as the example above does. Read a direction back the same
way:
import { orbitFromDirection } from 'nanoraster';
const { azimuth, elevation } = orbitFromDirection([0.61, -0.61, 0.5], world);Azimuth is the angle in the world horizontal plane. It is zero on
world.forward and positive toward the viewer's right. Elevation is the angle
above it. This convention is the pair's own, not the one the removed
phi/theta options carried. The wire stays Cartesian: a turntable is a
sequence of azimuths.
Choose the fitted projection
Perspective is the default. Its verticalFieldOfView is the exact rectilinear
angle in degrees. An orthographic fit uses the same referenced geometry and
margin but removes depth scaling.
const perspective = {
framing: 'fit',
direction: [1, 0.4, 1],
projection: { kind: 'perspective', verticalFieldOfView: 52 },
} as const;
const plan = {
framing: 'fit',
direction: [0, 1, 0],
projection: { kind: 'orthographic' },
} as const;Fit framing has no zoom by design. margin is its one size control.
Use a fixed camera when a caller must own magnification.
Set the empty border
camera.margin is the minimum empty fraction around contained fitted
geometry, from 0 to 0.5. The default is 0.1.
const image = await renderImage(glb, {
format: 'webp',
camera: { framing: 'fit', margin: 0.02 },
});Fitting uses width / height, so set the output size before you tune the
margin. Annotations may loosen a fitted camera to keep the model clear of
their fixed screen-space slots. The non-limiting image axis may have more
whitespace. Annotations never change a fixed camera.
Very wide perspective
The 1..179 degree range is rectilinear. Near 180 degrees, positive front
clearance can add whitespace beyond margin. Use a narrower field for
photographic framing. Fisheye is a different projection.