Documentation
¶
Overview ¶
Package pose is the orientation arithmetic an XR viewer needs: quaternions, the Euler conventions headsets actually report, recentring, and smoothing.
It knows nothing about devices or rendering. That is the point — orientation is where sign and axis-order mistakes hide, and they hide best when the only way to exercise the code is to put a headset on. Everything here is pure and tested against known rotations, so a wrong axis fails a test instead of making the horizon tilt.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Euler ¶
type Euler struct{ Roll, Pitch, Yaw float64 }
Euler is an orientation as three angles in DEGREES, the unit head trackers report. Yaw turns the head left/right, pitch tips it up/down, roll tilts it.
type Quat ¶
type Quat struct{ W, X, Y, Z float64 }
Quat is a rotation as a unit quaternion. The zero value is not a rotation; use Identity.
func FromEulerZXY ¶
FromEulerZXY builds a rotation applying ROLL about Z first, then pitch about X, then yaw about Y -- the Z, X, Y of the name is the order the rotations are applied in, giving R = Ry(yaw) . Rx(pitch) . Rz(roll).
The order is not a detail to pick by taste, and getting it backwards is not a subtle error. Yaw must be applied LAST, about the global up axis, or it stops being a horizontal turn: compose it first instead and pitching to 90 degrees no longer looks straight up, so the horizon swings as the viewer raises their head. This is the convention head trackers report in, and the one that makes pitch = 90 degrees the degenerate case rather than an arbitrary direction.
func Slerp ¶
Slerp interpolates along the shortest arc from q to r, with t clamped to [0,1]. Taking the shortest arc matters: a quaternion and its negation are the same rotation, so interpolating without the sign check can travel the long way round and spin the view through 300° to reach a neighbouring angle.
func (Quat) EulerZXY ¶
EulerZXY decomposes a rotation back into the same convention FromEulerZXY builds from. Pitch is clamped to ±90°, where yaw and roll become degenerate (gimbal lock): there the decomposition puts the whole remaining rotation into yaw and leaves roll at zero, which is a choice, not a recovery of information the orientation no longer distinguishes.
type Recentre ¶
type Recentre struct {
// contains filtered or unexported fields
}
Recentre makes one orientation the new "straight ahead". A viewer sits how they like, presses recentre, and the content is in front of them.
func NewRecentre ¶
func NewRecentre() *Recentre
NewRecentre starts with no offset, so Apply is the identity.
type Smoother ¶
type Smoother struct {
// Alpha is how much of each new sample is taken, in (0,1]. 1 is no
// smoothing; smaller is smoother and lags more. Values outside the range are
// clamped, so a zero value means "no smoothing" rather than "freeze".
Alpha float64
// contains filtered or unexported fields
}
Smoother low-pass filters a stream of orientations. A head tracker's output is noisy at rest, and that noise is visible as a shimmer in a magnified view.
func (*Smoother) Current ¶
Current returns the last smoothed value, and whether any sample has arrived.
type Vec3 ¶
type Vec3 struct{ X, Y, Z float64 }
Vec3 is a vector in a right-handed space: +X right, +Y up, +Z towards the viewer, which is the convention OpenGL, OpenXR and this package share. A viewer looking straight ahead looks down -Z.