-
Notifications
You must be signed in to change notification settings - Fork 32
Interop with graphics APIs
At some point you're probably going to need to send vectors and/or matrices to graphics APIs such as OpenGL, Direct3D, Vulkan, etc.
Did you pick row-major or column-major ?
Either way, if you plan to send a matrix to OpenGL
(for instance, via glUniformMatrix4fv()
), you'll be interested in the following.
-
There's no guarantee that matrix elements are tightly packed in memory!
This is especially the case for matrices ofrepr_simd
modules!
To ensure that elements are tightly packed in memory, you MUST call theis_packed()
method.
If it returnsfalse
, don'tpanic!
, there is stillinto_row_array()
andinto_col_array()
.
Either way,as_row_ptr()
andas_col_ptr()
do implicitlyassert!(self.is_packed())
. - Matrices provide a
gl_should_transpose(&self)
method.
If you don't have a matrix instance handy, you may also useGL_SHOULD_TRANSPOSE
associated constant.
They both give you abool
which you may cast to aGLboolean
as thetranspose
parameter, as shown below.
// Assuming m is an instance of row-major matrix...
assert!(m.is_packed());
glUniformMatrix4fv(loc, 1, m.gl_should_transpose() as _, m.as_row_ptr());
// Assuming m is an instance of column-major matrix...
assert!(m.is_packed());
glUniformMatrix4fv(loc, 1, m.gl_should_transpose() as _, m.as_col_ptr());
// Assuming m is a matrix with any storage layout...
let rows = m.into_row_array();
glUniformMatrix4fv(loc, 1, m.gl_should_transpose() as _, &rows);
glUniformMatrix4fv(loc, 1, GL_TRUE, &rows);
let cols = m.into_col_array();
glUniformMatrix4fv(loc, 1, m.gl_should_transpose() as _, &cols);
glUniformMatrix4fv(loc, 1, GL_FALSE, &cols);
Projection matrix functions are suffixed by either _zo
or _no
, which mean, respectively,
"Zero to One" and "Negative one to One".
- Direct3D and Vulkan: It's [0; 1].
Note that in Vulkan, the Y axis points downwards! See this article, for instance. - OpenGL: It's [-1; 1].
But, since OpenGL 4.5 (or with theGL_ARB_clip_control
extension), this can be changed to be [0; 1] by usingglClipControl()
.
Most projection matrix functions have a _lh
or _rh
suffix, that tells if they are
intended for, respectively, left-handed and right-handed spaces.
You might have a hard time making sense of what a left-handed projection matrix does differently from
a right-handed one.
The answer lies in the handedness of Normalized Device Coordinates (NDC).
It just so happens that, in both Direct3D and OpenGL, NDC space
is left-handed, because either 0 or -1 is "near", and 1 is "far" (i.e "forward").
I know of no other graphics API that reverses this, therefore vek
assumes it (just like GLM does). Just be careful if you reverse the mapping via glDepthRange()
.
Therefore, "left-handed" projection matrices map from left-handed (your space) to left-handed (NDC).
"Right-handed" projection matrices do some more work since they map from right-handed (your space) to left-handed (NDC).
One thing where handedness shouldn't make sense is model/view matrices, because essentially,
the need to change handedness only arises when projecting your world into NDC.
GLM does provide lookAtRH
and lookAtLH
, but all the right-handed version does is flip the Z-axis of transformed points.
vek
has them too, but they will remain private until someone proves to me that there is a sane use case for these.