Renderer · class
Gizmo
Explained in Hello world.
class Gizmoimport { Gizmo } from '@driftengine/core';Constructor
new
constructor(ringSegments?: number)ringSegments is the resolution of a rotation ring, and it also sets every buffer's
capacity because a ring is the largest thing any one of them holds.
| Parameter | Type | Description |
|---|---|---|
ringSegments? | number |
Properties
| Name | Type | Description |
|---|---|---|
mode | GizmoMode | |
space | GizmoSpace | |
size | number | The gizmo's own world size. See gizmoScaleFor. Non-positive draws and picks nothing. |
positionreadonly | Float32Array<ArrayBuffer> | The transform being edited. Written by a drag; the caller copies it where it belongs. |
rotationreadonly | Float32Array<ArrayBuffer> | A quaternion, xyzw, identity at construction. |
scalereadonly | Float32Array<ArrayBuffer> |
Accessors
| Name | Type | Description |
|---|---|---|
hoveredget | number | What a hover last found, or GIZMO_NONE. |
activeget | number | The handle a drag is on, or GIZMO_NONE. |
draggingget | boolean | |
dragAngleget | number | How far the current rotation drag has turned, in radians, signed and unbounded.MoreThis is the only place the unwrap in |
Methods
segments
segments(group: number): LineSegmentsOne group's geometry, filled by the last build. Draw it with GIZMO_GROUP_COLORS[group].
| Parameter | Type | Description |
|---|---|---|
group | number |
pick
pick(origin: ArrayLike<number>, direction: ArrayLike<number>): numberThe handle a ray is over, or GIZMO_NONE. No side effects; hover is the one that
remembers.
| Parameter | Type | Description |
|---|---|---|
origin | ArrayLike<number> | |
direction | ArrayLike<number> |
More
Nearest along the ray wins, except that the centre handle wins outright, which is one documented exception rather than a priority table: a priority table would let a plane handle behind the camera beat an arm in front of it, which a user sees as a click landing on the wrong thing.
As the radii stand the exception decides nothing, and that is worth saying rather
than implying otherwise: an arm's pick cylinder starts at ARM_START of the size and
the centre's sphere ends at CENTRE_RADIUS, which is smaller, so the two regions do
not meet. The ordering is what keeps a later change to either radius from quietly
producing a centre nobody can click, which is the failure it is here to prevent.
direction must be unit length. camera.rayThrough gives one.
hover
hover(origin: ArrayLike<number>, direction: ArrayLike<number>): numberpick, remembered. Returns what it found. Ignored while a drag is running.
| Parameter | Type | Description |
|---|---|---|
origin | ArrayLike<number> | |
direction | ArrayLike<number> |
beginDrag
beginDrag(origin: ArrayLike<number>, direction: ArrayLike<number>): booleanGrab whatever the ray is over. Returns whether a drag started.
| Parameter | Type | Description |
|---|---|---|
origin | ArrayLike<number> | |
direction | ArrayLike<number> |
More
The transform and the axes are both captured here and neither is re-read until the drag ends. Recomputing the basis from a rotation the drag is changing feeds the answer back into its own input, and what that looks like is a ring that accelerates away from the pointer.
A grab whose anchor cannot be computed — a ray parallel to the axis it is grabbing — refuses rather than starting a drag with an arbitrary origin.
updateDrag
updateDrag(origin: ArrayLike<number>, direction: ArrayLike<number>): booleanMove the drag. Returns whether the transform changed.
| Parameter | Type | Description |
|---|---|---|
origin | ArrayLike<number> | |
direction | ArrayLike<number> |
More
Every answer is absolute, computed from the anchor rather than accumulated from the last call, so a drag cannot drift however many frames it runs for. Rotation is the one exception and §5 of the design says why: an angle has to be unwrapped against the previous one to survive the seam at ±π, so the total is accumulated and the total is what the transform is built from.
A degenerate ray keeps the previous value rather than producing one. The alternative is the object teleporting at the moment the pointer crosses the plane it is dragging in, which is the single most annoying thing a gizmo can do.
endDrag
endDrag(): voidLet go. Safe to call on a frame with no drag running.
build
build(): voidFill the five buffers for this frame's mode, transform and highlight.
More
Cheap enough to call every frame — a rotation ring at the default resolution is 48 segments of arithmetic — and it has to be, because the highlight changes with the pointer.