Conventions
This section attempts to describe the mathematical conventions
that the io7m-r1 package
uses with respect to coordinate systems. The
io7m-r1 package generally
does not deviate from standard OpenGL conventions, and this section does
not attempt to give a rigorous formal definition of these existing conventions. It
does however attempt to establish the naming conventions
that the package uses to refer to the standard coordinate spaces
.
The
io7m-r1 package
uses the
jtensors
package for all mathematical operations on the CPU, and therefore
shares its conventions with regards to coordinate system handedness.
Important parts are repeated here, but the documentation for the
jtensors package should be inspected
for details.
Any of the matrix functions that deal with rotations
assume a right-handed coordinate system. This
matches the system conventionally used by
OpenGL (and most
mathematics literature). A right-handed coordinate system
assumes that if the viewer is standing at the origin and
looking towards negative infinity on the Z axis, then the
X axis runs horizontally (left towards negative infinity
and right towards positive infinity), and the Y axis runs
vertically (down towards negative infinity and up towards
positive infinity). The following image demonstrates this
axis configuration:
The jtensors package adheres
to the convention that a positive rotation around an axis
represents a counter-clockwise rotation when viewing the
system along the negative direction of the axis in question.
The package uses the following matrices to define rotations
around each axis:
Which results in the following matrix for rotating r radians around the axis given
by (x, y, z), assuming
s = sin(r) and c = cos(r)
:
Object space
Object space is the local
coordinate system used to describe the positions of vertices
in
meshes. For
example, a
unit cube with the
origin placed at the center of the cube would have eight
vertices with positions expressed as object-space coordinates:
In other rendering systems, object space
is sometimes referred to as local space,
or model space.
World space
In order to position objects in a scene, they must be
assigned a
transform
that can be applied to each of their
object space vertices
to yield absolute positions in so-called
world space.
As an example, if the unit cube described above was
assigned a transform that moved its origin to
(3, 5, 1), then its
object space vertex (-0.5, 0.5, 0.5)
would end up at
(3 + -0.5, 5 + 0.5, 1 + 0.5) = (2.5, 5.5, 1.5)
in world space.
In the
io7m-r1 package,
a
transform applied
to an object produces a 4x4
model matrix. Multiplying the model matrix
with the positions of the object space vertices yields vertices in
world space.
Eye space
Eye space represents the coordinate
system of the
camera of
a given
visible set.
In eye space, the observer is implicitly fixed at the origin
(0.0, 0.0, 0.0) and is
looking towards infinity in the negative Z direction.
The main purpose of eye space is to simplify
the mathematics required to implement various algorithms such
as lighting. The problem with implementing these sorts of
algorithms in world space is that one must constantly take into
account the position of the observer (typically by subtracting
the location of the observer from each set of world space
coordinates and accounting for any change in orientation of the
observer). By fixing the orientation of the observer towards
negative Z, and the position of the observer at
(0.0, 0.0, 0.0), and
by transforming all vertices of all objects into the same system,
the mathematics of lighting are greatly simplified.
The majority of the rendering algorithms used in the
io7m-r1 package
are implemented in eye space.
In the
io7m-r1 package,
the
camera produces
a 4x4
view matrix. Multiplying
the view matrix with any given world space position yields
a position in eye space. In practice, the view matrix
v
and the current object's model matrix
m are concatenated (multiplied)
to produce a
model-view matrix
mv = v * m
, and
mv is then
passed directly to the renderer's
vertex shaders to transform the
current object's vertices
.
Additionally, as the
io7m-r1 package
does all lighting in eye space, it's necessary to transform the
object space normal vectors
given in mesh data to eye space. However, the usual model-view matrix
will almost certainly contain some sort of translational component and possibly
a scaling component. Normal vectors are not supposed to be translated; they
represent directions! A non-uniform scale applied to an object will also deform the
normal vectors, making them non-perpendicular to the surface they're associated
with:
With the scaled triangle on the right, the normal vector is now not perpendicular
to the surface (in addition to no longer being of unit length). The red vector
indicates what the surface normal should be.
Therefore it's necessary to derive another 3x3 matrix known as the
normal matrix from the model-view matrix that
contains just the rotational component of the original matrix. The full
derivation of this matrix is given in
Mathematics for 3D Game Programming and Computer Graphics, Third Edition
. Briefly, the normal matrix is equal to
the
inverse transpose of the top left
3x3 elements of an arbitrary 4x4 model-view matrix.
In other rendering systems, eye space
is sometimes referred to as camera space,
or view space.
In the
io7m-r1 package,
eye space is indicated by the
RSpaceEyeType.
Clip space
Clip space is a homogeneous coordinate
system in which OpenGL performs clipping
of primitives (such as triangles). In OpenGL,
clip space is effectively a
left-handed coordinate system by default
. Intuitively, coordinates in
eye space are transformed with a
projection (normally either an
orthographic or
perspective projection) such that
all vertices are projected into a homogeneous unit cube placed at
the origin - clip space - resulting
in four-dimensional (x, y, z, w)
positions. Positions that end up outside of the cube are
clipped (discarded) by dedicated
clipping hardware, typically producing more triangles as a result.
A projection effectively
determines how objects in the three-dimensional scene are projected
onto the two-dimensional viewing plane
(a computer screen, in most cases).
A perspective projection
transforms vertices such that objects that are further away from
the viewing plane appear to be smaller than objects that are close
to it, while an orthographic
projection preserves the perceived sizes of objects regardless of
their distance from the viewing plane.
Because
eye space is
a right-handed coordinate system by convention, but by default
clip space is
left-handed, the projection matrix used will invert the sign of the
z component of any given point.
In the
io7m-r1 package,
the
camera produces
a 4x4
projection matrix. The
projection matrix is passed, along with
the
model-view
matrix, to the renderer's
vertex shaders.
As is normal in OpenGL, the vertex shader produces
clip space coordinates which are then
used by the hardware rasterizer to produce color fragments onscreen.
In the
io7m-r1 package,
clip space is indicated by the
RSpaceClipType.
Screen space
Screen space is, by default, a left-handed coordinate
system representing the screen (or window) that is displaying the actual
results of rendering. If the screen is of width w
and height h,
and the current depth range of the window
is [n, f], then the range of values
in screen space coordinates runs from [(0, 0, n), (w, h, f)].
The origin (0, 0, 0) is assumed to be at
the bottom-left corner.
The depth range is actually a configurable
value, but the io7m-r1 package
keeps the OpenGL default. From the glDepthRange
function manual page:
As OpenGL, by default, specifies a depth range of
[0, 1], the positive Z axis
points away from the observer, making the coordinate system left handed.