OffAxisProjection class final

A frustum whose four sides are given separately, so the axis need not be in the middle of it.

What it exists for is a headset. A perspective projection has one angle and a viewport aspect, and from those the frustum is symmetric by construction. An eye is not: the lens sits off the centre of its half of the display, the two eyes are mirror images of each other, and the runtime hands over four angles per eye that no single field of view can reproduce. Feeding their average to PerspectiveProjection gets a picture that looks right on a monitor and, in a headset, disagrees with the other eye by a degree or so — which is not a subtle artefact but the thing that makes people take the device off.

The four values are tangents of the angles from the view axis, which is what XrFovf gives after tan and what the matrix needs anyway. tanLeft and tanDown are negative for a frustum that contains its own axis.

toMatrix ignores the request's aspect, and that is deliberate. The shape of this frustum is already stated by the four tangents, and the viewport it will be drawn into was chosen to match them; there is nothing left for an aspect ratio to decide. Dividing by one here — which is what the signature invites — would squash the image by the ratio between the eye's own aspect and the viewport's, and a fraction of a degree of that is enough for the two eyes to fight.

Inheritance

Constructors

OffAxisProjection({required double tanLeft, required double tanRight, required double tanDown, required double tanUp, double near = 0.1, double far = 1000.0})
A frustum with edges at the tangents tanLeft, tanRight, tanDown and tanUp, between near and far metres.
const
OffAxisProjection.fromAngles({required double left, required double right, required double down, required double up, double near = 0.1, double far = 1000.0})
From the four angles a runtime states, in radians, as XrFovf does.
factory
OffAxisProjection.symmetric({double fieldOfView = math.pi / 4, double aspect = 1.0, double near = 0.1, double far = 1000.0})
The frustum a PerspectiveProjection of this shape would have, for comparing the two and for a stereo pair that wants a symmetric fallback.
factory

Properties

far → double
Distance from the eye to the far clip plane, in metres.
final
hashCode → int
The hash code for this object.
no setterinherited
near → double
Distance from the eye to the near clip plane, in metres.
final
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
tanDown → double
Tangent of the angle from the view axis to the bottom edge, negative below: offset over distance, a unitless ratio.
final
tanLeft → double
Tangent of the angle from the view axis to the left edge, negative to the left: offset over distance, a unitless ratio.
final
tanRight → double
Tangent of the angle from the view axis to the right edge: offset over distance, a unitless ratio.
final
tanUp → double
Tangent of the angle from the view axis to the top edge: offset over distance, a unitless ratio.
final
verticalFieldOfView → double?
The symmetric angle covering the same vertical extent.
no setteroverride

Methods

copyWith({double? tanLeft, double? tanRight, double? tanDown, double? tanUp, double? near, double? far}) → OffAxisProjection
Returns a copy with the given fields replaced; null leaves a field as it is.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
projectToNdc(Vector3 eyePosition, {double aspect = 1.0}) → Vector3
Projects an eye-space point to NDC.
inherited
toMatrix(ProjectionRequest request) → Matrix4
Builds the projection matrix for the target request describes: its aspect ratio and, where the caller knows them, its size in pixels.
override
toString() → String
A string representation of this object.
inherited

Operators

operator ==(Object other) → bool
The equality operator.
inherited