OrbitFollow
Puts the camera on a sphere around the target, or on a surface through three rings. Three InputAxis pick the spot: horizontal goes around the target and vertical up and down, both in degrees, and radial zooms. They can be driven by the mouse, touch, the wheel and pinches through an input controller, or from code. Pair it with an Aim that looks at the same target, like HardLookAt, for an orbit or third person camera.
The camera sits radius × exp(radial) away from the target. radial is the natural log of the zoom: 0 is radius, ln 2 twice as far, ln 0.5 half as far. That way each step of the wheel zooms by the same ratio near and far, and a pinch zooms exactly as much as the fingers spread.
To start from a specific spot, pass a position to the camera's initialState. horizontal and vertical are set from its direction around the target, radial keeps its value. Later on, setFromPosition(position) and setFromRotation(rotation) on the body ease the camera there with the axes' damping. On OrbitFollowBodyThree they also take a Vector3 and a Quaternion.
Settings
Axes
Every axis starts at its center. Dragging right with a positive gain turns the view right, the same way as PanTilt.
Axes with the same recentering.time recenter together: input on one of them restarts the wait on the others. With recenteringTarget: 'trackingTarget', the default, horizontal recenters to its center measured from behind the target's forward, -Z, whatever the bindingMode: 0 is right behind it, 180 in front of it.
Three rings
With orbitStyle: 'threeRing', vertical runs from the bottom ring at the start of its range, through center, to the top ring at its end, and radial scales the whole surface. The rings let the camera come closer when it looks from above or below.
By default all three rings have a radius of 10, at heights -10, 0 and 10: a plain cylinder whose center ring is where the sphere starts.
Damping
damping makes the camera lag behind a moving target. Going around the orbit is never delayed by it, the camera turns around the target right away. To smooth the input itself, set damping on the axes.
An Aim with damping, like RotationComposer, also follows the turns of the orbit without its damping, so the target stays in place on screen while the user drags.
Usage
import { HardLookAtAim, OrbitFollowBody, targetPose } from '@pmndrs/klipp';
import { InputControllerDom } from '@pmndrs/klipp/dom';
const player = targetPose.create(); // keep player.position up to date
const body = new OrbitFollowBody(player, { radius: 8, damping: 0.3, radial: { damping: 0.15 } });
camera.body = body;
camera.aim = new HardLookAtAim(player);
const orbit = { axes: { x: body.horizontal, y: body.vertical }, gain: 0.3 };
const controller = new InputControllerDom({
mouseButtons: { left: orbit },
touches: { one: orbit },
wheel: { axis: body.radial, gain: 0.001, invert: true },
pinch: { axis: body.radial, invert: true },
});
klipp.whileOnScreen(camera, () => {
controller.connect(canvas);
return () => controller.disconnect();
});
klipp.registerUpdate(() => controller.update());
Scrolling up and spreading a pinch are positive, while zooming in makes radial smaller, hence invert.
Recentering
const recentering = { enabled: true, wait: 1, time: 0.5 };
body.horizontal.recentering = recentering;
body.vertical.recentering = recentering;
import { Vector3 } from 'three';
import { HardLookAtAimThree, OrbitFollowBodyThree } from '@pmndrs/klipp/three';
const body = new OrbitFollowBodyThree(player, {
radius: 8,
targetOffset: new Vector3(0, 1.5, 0),
damping: 0.3,
radial: { damping: 0.15 },
});
camera.body = body;
camera.aim = new HardLookAtAimThree(player);
Map the input as on the core.
import { Aim, Body, InputController, VirtualCamera } from '@pmndrs/klipp/react';
const orbit = { axes: { x: 'horizontal', y: 'vertical' }, gain: 0.3 };
<VirtualCamera name="orbit" priority={10}>
<Body.OrbitFollow target={playerRef} radius={8} damping={0.3} radial={{ damping: 0.15 }}>
<InputController
mouseButtons={{ left: orbit }}
touches={{ one: orbit }}
wheel={{ axis: 'radial', gain: 0.001, invert: true }}
pinch={{ axis: 'radial', invert: true }}
/>
</Body.OrbitFollow>
<Aim.HardLookAt target={playerRef} />
</VirtualCamera>
ref gives you the OrbitFollowBodyThree. Removing an axis setting brings back its default without moving the axis.
Recentering
const recentering = { enabled: true, wait: 1, time: 0.5 };
<Body.OrbitFollow target={playerRef} horizontal={{ recentering }} vertical={{ recentering }} />