|
|
|
|
/*
|
|
|
|
|
This file is part of Magnum.
|
|
|
|
|
|
|
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
|
|
|
|
|
2020, 2021, 2022, 2023, 2024
|
|
|
|
|
Vladimír Vondruš <mosra@centrum.cz>
|
|
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
to deal in the Software without restriction, including without limitation
|
|
|
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
|
|
|
in all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
DEALINGS IN THE SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
namespace Magnum {
|
|
|
|
|
/** @page matrix-vector Operations with matrices and vectors
|
|
|
|
|
@brief Introduction to essential classes of the graphics pipeline.
|
|
|
|
|
|
|
|
|
|
@m_keyword{Matrices and vectors,,}
|
|
|
|
|
|
|
|
|
|
@tableofcontents
|
|
|
|
|
@m_footernavigation
|
|
|
|
|
|
|
|
|
|
Matrices and vectors are the most important part of graphics programming and
|
|
|
|
|
one of Magnum goals is to make their usage as intuitive as possible.
|
|
|
|
|
|
|
|
|
|
@section matrix-vector-hierarchy Matrix and vector classes
|
|
|
|
|
|
|
|
|
|
Magnum has three main matrix and vector classes --- a
|
|
|
|
|
@ref Math::RectangularMatrix, a (square) @ref Math::Matrix and a
|
|
|
|
|
@ref Math::Vector. To maximize code reuse, the @ref Math::Matrix is internally
|
|
|
|
|
a square @ref Math::RectangularMatrix and a @ref Math::RectangularMatrix is
|
|
|
|
|
internally an array of one or more @ref Math::Vector instances. Both vectors
|
|
|
|
|
and matrices can have arbitrary size (known at compile time) and can store any
|
|
|
|
|
arithmetic type, including a @ref Half or e.g. a @ref Rad.
|
|
|
|
|
|
|
|
|
|
Each subclass brings some specialization to its superclass. The
|
|
|
|
|
@ref Math::Vector2, @ref Math::Vector3 and @ref Math::Vector4 classes implement
|
|
|
|
|
direct access to named components, @ref Math::Matrix adds determinant
|
|
|
|
|
calculation or matrix inversion and @ref Math::Matrix3 / @ref Math::Matrix4
|
|
|
|
|
implement 2D and 3D transformations. Functions of each class return the most
|
|
|
|
|
specialized type known to make subsequent operations more convenient ---
|
|
|
|
|
columns of @ref Math::RectangularMatrix are returned as a @ref Math::Vector,
|
|
|
|
|
but when accessing columns of e.g. @ref Math::Matrix3, they are returned as a
|
|
|
|
|
@ref Math::Vector3.
|
|
|
|
|
|
|
|
|
|
There are also even more specialized subclasses, e.g. @ref Math::Color3 and
|
|
|
|
|
@ref Math::Color4 for color handling and conversion.
|
|
|
|
|
|
|
|
|
|
Commonly used types have convenience aliases in the @ref Magnum namespace, so
|
|
|
|
|
you can write e.g. @ref Vector3i instead of
|
|
|
|
|
@ref Math::Vector3 "Math::Vector3<Int>". See @ref types and the @ref Magnum
|
|
|
|
|
namespace documentation for more information.
|
|
|
|
|
|
|
|
|
|
@section matrix-vector-construction Constructing matrices and vectors
|
|
|
|
|
|
|
|
|
|
The default constructors of @ref Math::RectangularMatrix and @ref Math::Vector
|
|
|
|
|
(and @ref Math::Vector2, @ref Math::Vector3, @ref Math::Vector4,
|
|
|
|
|
@ref Math::Color3, @ref Math::Color4) create zero-filled objects, equivalent
|
|
|
|
|
to using the @ref Math::ZeroInit tag. @ref Math::Matrix (and
|
|
|
|
|
@ref Math::Matrix3, @ref Math::Matrix4) is by default constructed as an
|
|
|
|
|
identity matrix, equivalent to using the @ref Math::IdentityInit tag.
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-construct
|
|
|
|
|
|
|
|
|
|
The most common and most efficient way to create a vector is to pass all values
|
|
|
|
|
to the constructor. A matrix is created by passing all *column* vectors to the
|
|
|
|
|
constructor. The constructors check correct number of passed arguments at
|
|
|
|
|
compile time.
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-construct-value
|
|
|
|
|
|
|
|
|
|
You can specify all components of a vector or a matrix with a single value, or
|
|
|
|
|
specify just values on the matrix diagonal:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-construct-diagonal
|
|
|
|
|
|
|
|
|
|
There are also shortcuts to create a vector with all but one component set to
|
|
|
|
|
zero or one which are useful for transformations:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-construct-axis
|
|
|
|
|
|
|
|
|
|
It is also possible to create matrices and vectors from a C-style array. The
|
|
|
|
|
function performs a simple type cast without copying anything, so it's possible
|
|
|
|
|
to conveniently operate on the array itself:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-construct-from
|
|
|
|
|
|
|
|
|
|
@attention Note that, unlike a constructor, this function has no way to check
|
|
|
|
|
whether the array is long enough to contain all the elements, so use it
|
|
|
|
|
with caution.
|
|
|
|
|
|
|
|
|
|
To make handling colors easier, their behavior is a bit different with a
|
|
|
|
|
richer feature set. Implicit construction of @ref Math::Color4 from just the
|
|
|
|
|
RGB components will set the alpha to the max value (thus @cpp 1.0f @ce for
|
|
|
|
|
@ref Color4 and @cpp 255 @ce for @ref Color4ub):
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-construct-color
|
|
|
|
|
|
|
|
|
|
Similar to axes and scales in vectors, you can create single color shades too:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-construct-color-axis
|
|
|
|
|
|
|
|
|
|
There are also builtin colorspace conversion functions --- it's possible to
|
|
|
|
|
create a RGB color from a HSV value, a linear color value from a sRGB
|
|
|
|
|
representation, or convert from CIE XYZ / xyY. And the other way as well:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-construct-color-colorspace
|
|
|
|
|
|
|
|
|
|
Finally, the namespace @ref Math::Literals provides convenient
|
|
|
|
|
@link Math::Literals::ColorLiterals::operator""_rgb() operator""_rgb() @endlink
|
|
|
|
|
/ @link Math::Literals::ColorLiterals::operator""_rgbf() operator""_rgbf() @endlink
|
|
|
|
|
and @link Math::Literals::ColorLiterals::operator""_rgba() operator""_rgba() @endlink
|
|
|
|
|
/ @link Math::Literals::ColorLiterals::operator""_rgbaf() operator""_rgbaf() @endlink
|
|
|
|
|
literals for entering colors in hex representation. These literals assume
|
|
|
|
|
linear RGB input and don't do any gamma correction. For sRGB input, there is
|
|
|
|
|
@link Math::Literals::ColorLiterals::operator""_srgb() operator""_srgb() @endlink
|
|
|
|
|
/ @link Math::Literals::ColorLiterals::operator""_srgba() operator""_srgba() @endlink
|
|
|
|
|
and @link Math::Literals::ColorLiterals::operator""_srgbf() operator""_srgbf() @endlink
|
|
|
|
|
/ @link Math::Literals::ColorLiterals::operator""_srgbaf() operator""_srgbaf() @endlink,
|
|
|
|
|
see their documentation for more information.
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-construct-color-literal
|
|
|
|
|
|
|
|
|
|
@section matrix-vector-component-access Accessing matrix and vector components
|
|
|
|
|
|
|
|
|
|
Column vectors of matrices and components of vectors can be accessed using
|
|
|
|
|
square brackets:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-access
|
|
|
|
|
|
|
|
|
|
Row vectors can be accessed too, but only for reading, and access is slower
|
|
|
|
|
due to the matrix being stored @ref matrix-vector-column-major "in column-major order":
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-access-row
|
|
|
|
|
|
|
|
|
|
Fixed-size vector subclasses have functions for accessing named components
|
|
|
|
|
and subparts using either `xyzw` or `rgba`:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-access-named
|
|
|
|
|
|
|
|
|
|
For more involved operations with components there are the @ref Math::gather()
|
|
|
|
|
and @ref Math::scatter() functions:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-access-swizzle
|
|
|
|
|
|
|
|
|
|
@section matrix-vector-conversion Converting between different underlying types
|
|
|
|
|
|
|
|
|
|
All classes in @ref Math namespace can be constructed from an instance with a
|
|
|
|
|
different underlying type (e.g. convert between integer and floating-point type
|
|
|
|
|
or betweeen @ref Float, @ref Double and @ref Half). Unlike with plain C++ data
|
|
|
|
|
types, the conversion is *explicit*. That might sound inconvenient at first,
|
|
|
|
|
but performing the conversion explicitly avoids common issues like precision
|
|
|
|
|
loss (or, on the other hand, expensive computation with unnecessarily high
|
|
|
|
|
precision).
|
|
|
|
|
|
|
|
|
|
To further emphasise the intent of conversion (so it doesn't look like an
|
|
|
|
|
accident or a typo), you are encouraged to use @cpp auto b = Type{a} @ce
|
|
|
|
|
instead of @cpp Type b{a} @ce.
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-convert
|
|
|
|
|
|
|
|
|
|
For packing floats into integers and unpacking them back use the
|
|
|
|
|
@ref Math::pack() and @ref Math::unpack() functions:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-convert-pack
|
|
|
|
|
|
|
|
|
|
See below for more information about other available
|
|
|
|
|
@ref matrix-vector-componentwise "component-wise operations".
|
|
|
|
|
|
|
|
|
|
@section matrix-vector-operations Operations with matrices and vectors
|
|
|
|
|
|
|
|
|
|
Vectors can be added, subtracted, negated and multiplied or divided with
|
|
|
|
|
scalars, as is common in mathematics. Magnum also adds the ability to divide
|
|
|
|
|
a scalar with vector:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-operations-vector
|
|
|
|
|
|
|
|
|
|
As in GLSL, vectors can be also multiplied or divided component-wise:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-operations-multiply
|
|
|
|
|
|
|
|
|
|
When working with integral vectors (i.e. 24bit RGB values), it is often
|
|
|
|
|
desirable to multiply them with floating-point values but retain an integral
|
|
|
|
|
result. In Magnum, all multiplication/division operations involving integral
|
|
|
|
|
vectors will return an integer result, you need to convert both arguments to
|
|
|
|
|
the same floating-point type to have a floating-point result.
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-operations-integer
|
|
|
|
|
|
|
|
|
|
You can also use all bitwise operations on integral vectors:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-operations-bitwise
|
|
|
|
|
|
|
|
|
|
Matrices can be added, subtracted and multiplied with matrix multiplication.
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-operations-matrix
|
|
|
|
|
|
|
|
|
|
You can also multiply (properly sized) vectors with matrices. These operations
|
|
|
|
|
are equivalent to multiplying with single-column matrices:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-operations-multiply-matrix
|
|
|
|
|
|
|
|
|
|
@section matrix-vector-componentwise Component-wise and inter-vector operations
|
|
|
|
|
|
|
|
|
|
As shown above, vectors can be added and multiplied component-wise using the
|
|
|
|
|
@cpp + @ce or @cpp * @ce operator. For a sum or product of components *inside*
|
|
|
|
|
a vector you can use @ref Math::Vector::sum() "sum()" and
|
|
|
|
|
@ref Math::Vector::product() "product()" instead:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-operations-componentwise
|
|
|
|
|
|
|
|
|
|
Component-wise minimum and maximum of two vectors can be done using
|
|
|
|
|
@ref Math::min(), @ref Math::max() or @ref Math::minmax(), similarly with
|
|
|
|
|
@ref Math::Vector::min() "min()", @ref Math::Vector::max() "max()" and
|
|
|
|
|
@ref Vector2::minmax() "minmax()" for components in one vector.
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-operations-minmax
|
|
|
|
|
|
|
|
|
|
The vectors can be also compared component-wise, the result is returned in a
|
|
|
|
|
@ref Math::BitVector class:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-operations-compare
|
|
|
|
|
|
|
|
|
|
There are also function for component-wise rounding, sign operations, square
|
|
|
|
|
root and various interpolation and (de)normalization functionality:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-operations-functions
|
|
|
|
|
|
|
|
|
|
Component-wise functions are implemented only for vectors and not for matrices
|
|
|
|
|
to keep the math library in a sane and maintainable size. Instead, you can
|
|
|
|
|
reinterpret the matrix as a vector and do the operation on it (and vice versa)
|
|
|
|
|
--- because you get a reference that way, the operation will affect the
|
|
|
|
|
original data:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-operations-functions-componentwise
|
|
|
|
|
|
|
|
|
|
Note that all component-wise functions in the @ref Math namespace also work for
|
|
|
|
|
scalars --- and on the special @ref Deg / @ref Rad types too.
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-operations-functions-scalar
|
|
|
|
|
|
|
|
|
|
For types with units the only exception are power functions such as
|
|
|
|
|
@ref Math::pow() or @ref Math::log() --- the resulting unit of such an
|
|
|
|
|
operation cannot be represented and thus will only work on unitless types.
|
|
|
|
|
|
|
|
|
|
@section matrix-vector-linear-algebra Linear algebra operations
|
|
|
|
|
|
|
|
|
|
Also available are common linear algebra operations --- the dot or cross
|
|
|
|
|
product, vector, reflection or angle calculation. These are mostly available
|
|
|
|
|
as free functions in the @ref Math namespace, with more advanced functionality
|
|
|
|
|
such as QR or SVD decomposition in @ref Math::Algorithms.
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-linear-algebra
|
|
|
|
|
|
|
|
|
|
@section matrix-vector-column-major Matrices are column-major and vectors are columns
|
|
|
|
|
|
|
|
|
|
For consistency with GLSL, Magnum stores matrices as column-major (the vectors
|
|
|
|
|
are columns). This naturally has some implications and it may differ from what
|
|
|
|
|
you're used to from linear algebra or other graphics toolkits:
|
|
|
|
|
|
|
|
|
|
<ul><li>
|
|
|
|
|
Order of template arguments in specification of @ref Math::RectangularMatrix
|
|
|
|
|
is also column-major:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-column-major-template
|
|
|
|
|
</li><li>
|
|
|
|
|
Order of components in matrix constructors is also column-major, further
|
|
|
|
|
emphasized by the requirement that you must pass column vectors directly:
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-column-major-construct
|
|
|
|
|
</li><li>
|
|
|
|
|
Element access order is also column-major, thus the bracket operator
|
|
|
|
|
accesses columns. The returned vector also has its own bracket operator,
|
|
|
|
|
which then indexes rows.
|
|
|
|
|
|
|
|
|
|
@snippet Math.cpp matrix-vector-column-major-access
|
|
|
|
|
</li><li>
|
|
|
|
|
Various algorithms which commonly operate on matrix rows (such as
|
|
|
|
|
@ref Math::Algorithms::gaussJordanInPlace() "Gauss-Jordan elimination")
|
|
|
|
|
have faster alternatives which operate on columns. It's then up to the user
|
|
|
|
|
to operate with transposed matrices or use the slower non-transposed
|
|
|
|
|
alternative of the algorithm.
|
|
|
|
|
</li></ul>
|
|
|
|
|
|
|
|
|
|
Note that the @ref Corrade::Utility::Debug utility always prints the matrices
|
|
|
|
|
in the expected layout --- rows are rows and columns are columns. You are
|
|
|
|
|
encouraged to use it for data visualization purposes.
|
|
|
|
|
*/
|
|
|
|
|
}
|