|
|
|
|
/*
|
|
|
|
|
This file is part of Magnum.
|
|
|
|
|
|
|
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
|
|
|
|
|
2020 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 goals of Magnum is to make their usage as intuitive as possible. They
|
|
|
|
|
are contained in @ref Math namespace and common variants also have aliases in
|
|
|
|
|
root @ref Magnum namespace. See the documentation of these namespaces for more
|
|
|
|
|
information about usage with CMake.
|
|
|
|
|
|
|
|
|
|
@section matrix-vector-hierarchy Matrix and vector classes
|
|
|
|
|
|
|
|
|
|
Magnum has three main matrix and vector classes: @ref Math::RectangularMatrix,
|
|
|
|
|
(square) @ref Math::Matrix and @ref Math::Vector. To maximize code reuse,
|
|
|
|
|
@ref Math::Matrix is internally square @ref Math::RectangularMatrix and
|
|
|
|
|
@ref Math::RectangularMatrix is internally 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.
|
|
|
|
|
|
|
|
|
|
Each subclass brings some specialization to its superclass. For the most common
|
|
|
|
|
vector and matrix sizes there are specialized classes @ref Math::Matrix3 and
|
|
|
|
|
@ref Math::Matrix4, implementing various transformations in 2D and 3D and
|
|
|
|
|
@ref Math::Vector2, @ref Math::Vector3 and @ref Math::Vector4, implementing
|
|
|
|
|
direct access to named components. Functions of each class try to return the
|
|
|
|
|
most specialized type known to make subsequent operations more convenient ---
|
|
|
|
|
columns of @ref Math::RectangularMatrix are returned as @ref Math::Vector, but
|
|
|
|
|
when accessing columns of e.g. @ref Math::Matrix3, they are returned as
|
|
|
|
|
@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 @ref Magnum namespace, so you
|
|
|
|
|
can write e.g. @ref Vector3i instead of @ref Math::Vector3 "Math::Vector3<Int>".
|
|
|
|
|
See @ref types and @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. @ref Math::Matrix (and
|
|
|
|
|
@ref Math::Matrix3, @ref Math::Matrix4) is by default constructed as an identity
|
|
|
|
|
matrix.
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.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 the column vectors to the
|
|
|
|
|
constructor. These constructors check the number of passed arguments and errors
|
|
|
|
|
are caught at compile time.
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.cpp matrix-vector-construct-value
|
|
|
|
|
|
|
|
|
|
You can specify all components of vectors or the diagonal of a square matrix
|
|
|
|
|
with a single value or create a diagonal matrix from a vector:
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.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 MagnumMath.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 MagnumMath.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 Color4 from @ref Color3 will
|
|
|
|
|
set the alpha to the max value (thus @cpp 1.0f @ce for @ref Color4 and @cpp 255 @ce
|
|
|
|
|
for @ref Color4ub):
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.cpp matrix-vector-construct-color
|
|
|
|
|
|
|
|
|
|
Similar to axes in vectors, you can create single color shades too, or create
|
|
|
|
|
a RGB color from a HSV representation:
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.cpp matrix-vector-construct-color-hue
|
|
|
|
|
|
|
|
|
|
Finally, the namespace @ref Math::Literals provides convenient
|
Math: sRGB support in Color classes.
At first I designed a hugely disrupting change that basically deprecated
everything related to 8-bit linear RGB colors, but then I took a step
back and reconsidered 8-bit linear RGB as a valid use case.
The documentation of Color classes, typedefs and literals was clarified
to mention that these classes should always represent linear RGB and
that 8-bit colors are commonly treated as *not* linear and one should be
aware of it.
There is now a new Color3::fromSrgb() and Color3::toSrgb() that converts
from sRGB representation to a linear RGB usable for calculations and
then back. For four-component colors, there is now
Color4::fromSrgbAlpha() and Color4::toSrgbAlpha(). Similarly to what
OpenGL sRGB behavior is regarding to alpha, the alpha channel is kept
linear, that's why I'm also calling it sRGB + alpha instead of sRGBA.
Besides that, there are four new literals _srgb, _srgba, _srgbf and
_srgbaf that have different semantics to support the sRGB workflow. The
8-bit versions are equivalent to _rgb and _rgba, though they don't
return Color3 but a non-color Vector3 to hint that the result is not a
linear RGB color. Main purpose of these is documentation. The float
versions apply an inverse sRGB curve to the input, returning a linear
RGB color.
10 years ago
|
|
|
@link Literals::operator""_rgb() operator""_rgb() @endlink /
|
|
|
|
|
@link Literals::operator""_rgbf() operator""_rgbf() @endlink and
|
|
|
|
|
@link Literals::operator""_rgba() operator""_rgba() @endlink /
|
|
|
|
|
@link Literals::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
|
Math: sRGB support in Color classes.
At first I designed a hugely disrupting change that basically deprecated
everything related to 8-bit linear RGB colors, but then I took a step
back and reconsidered 8-bit linear RGB as a valid use case.
The documentation of Color classes, typedefs and literals was clarified
to mention that these classes should always represent linear RGB and
that 8-bit colors are commonly treated as *not* linear and one should be
aware of it.
There is now a new Color3::fromSrgb() and Color3::toSrgb() that converts
from sRGB representation to a linear RGB usable for calculations and
then back. For four-component colors, there is now
Color4::fromSrgbAlpha() and Color4::toSrgbAlpha(). Similarly to what
OpenGL sRGB behavior is regarding to alpha, the alpha channel is kept
linear, that's why I'm also calling it sRGB + alpha instead of sRGBA.
Besides that, there are four new literals _srgb, _srgba, _srgbf and
_srgbaf that have different semantics to support the sRGB workflow. The
8-bit versions are equivalent to _rgb and _rgba, though they don't
return Color3 but a non-color Vector3 to hint that the result is not a
linear RGB color. Main purpose of these is documentation. The float
versions apply an inverse sRGB curve to the input, returning a linear
RGB color.
10 years ago
|
|
|
@link Literals::operator""_srgb() operator""_srgb() @endlink /
|
|
|
|
|
@link Literals::operator""_srgba() operator""_srgba() @endlink and
|
|
|
|
|
@link Literals::operator""_srgbf() operator""_srgbf() @endlink /
|
|
|
|
|
@link Literals::operator""_srgbaf() operator""_srgbaf() @endlink, see their
|
|
|
|
|
documentation for more information.
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.cpp matrix-vector-construct-color-literal
|
|
|
|
|
|
|
|
|
|
@section matrix-vector-component-access Accessing matrix and vector components
|
|
|
|
|
|
|
|
|
|
Column vectors of matrices and vector components can be accessed using square
|
|
|
|
|
brackets:
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.cpp matrix-vector-access
|
|
|
|
|
|
|
|
|
|
Row vectors can be accessed too, but only for reading, and access is slower
|
|
|
|
|
due to the way the matrix is stored (see @ref matrix-vector-column-major "explanation below"):
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.cpp matrix-vector-access-row
|
|
|
|
|
|
|
|
|
|
Fixed-size vector subclasses have functions for accessing named components
|
|
|
|
|
and subparts:
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.cpp matrix-vector-access-named
|
|
|
|
|
|
|
|
|
|
@ref Color3 and @ref Color4 name their components `rgba` instead of `xyzw`.
|
|
|
|
|
|
|
|
|
|
For more involved operations with components there is the @ref Math::gather()
|
|
|
|
|
and @ref Math::scatter() functions:
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.cpp matrix-vector-access-swizzle
|
|
|
|
|
|
|
|
|
|
@section matrix-vector-conversion Converting between different underlying types
|
|
|
|
|
|
|
|
|
|
All vector, matrix and other classes in @ref Math namespace can be
|
|
|
|
|
constructed from an instance with a different underlying type (e.g. convert
|
|
|
|
|
between integer and floating-point or betweeen @ref Float and @ref Double).
|
|
|
|
|
Unlike with plain C++ data types, the conversion is done via an *explicit*
|
|
|
|
|
constructor. That might sound inconvenient, 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 MagnumMath.cpp matrix-vector-convert
|
|
|
|
|
|
|
|
|
|
For packing and unpacking use the @ref Math::pack() and @ref Math::unpack()
|
|
|
|
|
functions:
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.cpp matrix-vector-convert-pack
|
|
|
|
|
|
|
|
|
|
See @ref matrix-vector-componentwise "below" for more information about other
|
|
|
|
|
available 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 MagnumMath.cpp matrix-vector-operations-vector
|
|
|
|
|
|
|
|
|
|
As in GLSL, vectors can be also multiplied or divided component-wise:
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.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 integers within the result, you need to convert both arguments to the same
|
|
|
|
|
floating-point type to have floating-point result.
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.cpp matrix-vector-operations-integer
|
|
|
|
|
|
|
|
|
|
You can also use all bitwise operations on integral vectors:
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.cpp matrix-vector-operations-bitwise
|
|
|
|
|
|
|
|
|
|
Matrices can be added, subtracted and multiplied with matrix multiplication.
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.cpp matrix-vector-operations-matrix
|
|
|
|
|
|
|
|
|
|
You can also multiply (properly sized) vectors with matrices. These operations
|
|
|
|
|
are just convenience shortcuts for multiplying with single-column matrices:
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.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. You can use @ref Math::Vector::sum() "sum()"
|
|
|
|
|
and @ref Math::Vector::product() "product()" for sum or product of components
|
|
|
|
|
in one vector:
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.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 Vector::min() "min()", @ref Vector::max() "max()" and
|
|
|
|
|
@ref Vector2::minmax() "minmax()" for components in one vector.
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.cpp matrix-vector-operations-minmax
|
|
|
|
|
|
|
|
|
|
The vectors can be also compared component-wise, the result is returned in
|
|
|
|
|
@ref Math::BoolVector class:
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.cpp matrix-vector-operations-compare
|
|
|
|
|
|
|
|
|
|
There are also function for component-wise rounding, sign operations, square
|
|
|
|
|
root, various interpolation and (de)normalization functionality:
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.cpp matrix-vector-operations-functions
|
|
|
|
|
|
|
|
|
|
Component-wise functions are implemented only for vectors and not for matrices
|
|
|
|
|
to keep the math library a sane and maintainable size. Instead, you can
|
|
|
|
|
reinterpret the matrix as vector and do the operation on it (and vice versa):
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.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 MagnumMath.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-column-major Matrices are column-major and vectors are columns
|
|
|
|
|
|
|
|
|
|
OpenGL matrices are column-major, thus in Magnum it is reasonable to use matrices
|
|
|
|
|
also as column-major (the vectors are the columns). This naturally has some
|
|
|
|
|
implications and it may differ from what is common in mathematics:
|
|
|
|
|
|
|
|
|
|
<ul><li>
|
|
|
|
|
Order of template arguments in specification of @ref Math::RectangularMatrix
|
|
|
|
|
is also column-major:
|
|
|
|
|
|
|
|
|
|
@snippet MagnumMath.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 MagnumMath.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 MagnumMath.cpp matrix-vector-column-major-access
|
|
|
|
|
</li><li>
|
|
|
|
|
Various algorithms which commonly operate on matrix rows (such as
|
|
|
|
|
@ref 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.
|
|
|
|
|
*/
|
|
|
|
|
}
|