mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
351 lines
13 KiB
351 lines
13 KiB
/* |
|
This file is part of Magnum. |
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016 |
|
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. |
|
|
|
- Previous page: @ref types |
|
- Next page: @ref transformations |
|
|
|
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 documentation of these namespaces for more |
|
information about usage with CMake. |
|
|
|
@tableofcontents |
|
|
|
@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 achieve greatest code |
|
reuse, Matrix is internally square RectangularMatrix and RectangularMatrix |
|
is internally array of one or more 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 and for most common |
|
vector and matrix sizes there are specialized classes @ref Math::Matrix3 and |
|
@ref Math::Matrix4, implementing various transformations in 2D and 3D, |
|
@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 RectangularMatrix are returned as Vector, but when accessing |
|
columns of e.g. Matrix3, they are returned as Vector3. |
|
|
|
There are also even more specialized subclasses, e.g. @ref Color3 and |
|
@ref Color4 for color handling and conversion. |
|
|
|
Commonly used types have convenience aliases in @ref Magnum namespace, so you |
|
can write e.g. `Vector3i` instead of `Math::Vector3<Int>`. See @ref types and |
|
namespace documentation for more information. |
|
|
|
@section matrix-vector-construction Constructing matrices and vectors |
|
|
|
Default constructors of @ref Math::RectangularMatrix and @ref Math::Vector (and |
|
@ref Math::Vector2, @ref Math::Vector3, @ref Math::Vector4, @ref Color3) create |
|
zero-filled objects. @ref Math::Matrix (and @ref Math::Matrix3, @ref Math::Matrix4) |
|
is by default constructed as identity matrix. @ref Color4 has alpha value set |
|
to opaque. |
|
@code |
|
Matrix2x3 a; // zero-filled |
|
Vector3i b; // zero-filled |
|
|
|
Matrix3 identity; // diagonal set to 1 |
|
Matrix3 zero(Matrix::Zero); // zero-filled |
|
|
|
Color4 black1; // {0.0f, 0.0f, 0.0f, 1.0f} |
|
Color4ub black2; // {0, 0, 0, 255} |
|
@endcode |
|
|
|
Most common and most efficient way to create vector is to pass all values to |
|
constructor, matrix is created by passing all column vectors to the |
|
constructor. All constructors check number of passed arguments and the errors |
|
are catched at compile time. |
|
@code |
|
Vector3i vec(0, 1, 2); |
|
|
|
Matrix3 mat({0.0f, 1.9f, 2.2f}, |
|
{3.5f, 4.0f, 5.1f}, |
|
{6.0f, 7.3f, 8.0f}); |
|
@endcode |
|
|
|
You can specify all components of vector or whole diagonal of square matrix |
|
with single value or create diagonal matrix from vector: |
|
@code |
|
Matrix3 diag(Matrix3::Identity, 2.0f); // diagonal set to 2.0f, zeros elsewhere |
|
Vector3i fill(10); // {10, 10, 10} |
|
auto diag2 = Matrix3::fromDiagonal({3.0f, 2.0f, 1.0f}); |
|
@endcode |
|
|
|
It is possible to create matrices from other matrices and vectors with the same |
|
row count; vectors from vector and scalar: |
|
@code |
|
Math::Matrix2x3<Int> a; |
|
Math::Vector3<Int> b, c; |
|
Math::Matrix3<Int> mat(a, b); |
|
Math::Vector<8, Int> vec(1, b, 2, c); |
|
@endcode |
|
|
|
@todo Implement this ^ already. |
|
|
|
It is also possible to create them from an C-style array. The function does |
|
simple type cast without any copying, so it's possible to conveniently operate |
|
on the array itself: |
|
@code |
|
Int[] mat = { 2, 4, 6, |
|
1, 3, 5 }; |
|
Math::Matrix2x3<Int>::from(mat) *= 2; // mat == { 4, 8, 12, 2, 6, 10 } |
|
@endcode |
|
|
|
Note that, unlike constructors, this function has no way to check whether the |
|
array is long enough to contain all elements, so use with caution. |
|
|
|
@section matrix-vector-component-access Accessing matrix and vector components |
|
|
|
Column vectors of matrices and vector components can be accessed using square |
|
brackets: |
|
@code |
|
Matrix3x2 a; |
|
a[2] /= 2.0f; // third column (column major indexing, see explanation below) |
|
a[0][1] = 5.3f; // first column, second element |
|
|
|
Vector3i b; |
|
b[1] = 1; // second element |
|
@endcode |
|
|
|
Row vectors can be accessed too, but only for reading, and the access is slower |
|
due to the way the matrix is stored (see @ref matrix-vector-column-major "explanation below"): |
|
@code |
|
Vector2i c = a.row(2); // third row |
|
@endcode |
|
|
|
Fixed-size vector subclasses have functions for accessing named components |
|
and subparts: |
|
@code |
|
Vector4i a; |
|
Int x = a.x(); |
|
a.y() += 5; |
|
|
|
Vector3i xyz = a.xyz(); |
|
xyz.xy() *= 5; |
|
@endcode |
|
Color3 and Color4 name their components `rgba` instead of `xyzw`. |
|
|
|
For more involved operations with components there is the @ref swizzle() |
|
function: |
|
@code |
|
Vector4i original(-1, 2, 3, 4); |
|
Vector4i bgra = swizzle<'b', 'g', 'r', 'a'>(original); // { 3, 2, -1, 4 } |
|
Math::Vector<6, Int> w10xyz = swizzle<'w', '1', '0', 'x', 'y', 'z'>(original); // { 4, 1, 0, -1, 2, 3 } |
|
@endcode |
|
|
|
@section matrix-vector-conversion Converting between different underlying types |
|
|
|
All vector, matrix and other classes in @ref Math namespace and also |
|
@ref Color3 and @ref Color4 classes are able to be constructed from type with |
|
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 *explicit* constructor. That might sound inconvenient, |
|
but doing the conversion explicitly avoids common issues like precision loss |
|
(or, on the other hand, doing computations in unnecessarily high precision). |
|
|
|
To further emphasise the intent of conversion (so it doesn't look like accident |
|
or typo), you are encouraged to use `auto b = Type{a}` instead of `Type b{a}`. |
|
@code |
|
Vector3 a{2.2f, 0.25f, -5.1f}; |
|
//Vector3i b = a; // error, implicit conversion not allowed |
|
auto c = Vector3i{a}; // {2, 0, -5} |
|
auto d = Vector3d{a}; // {2.2, 0.25, -5.1} |
|
@endcode |
|
|
|
For normalizing and denormalizing there are @ref Math::normalize() and |
|
@ref Math::denormalize() functions: |
|
@code |
|
Color3 a{0.8f, 1.0f, 0.3f}; |
|
auto b = Math::denormalize<Color3ub>(a); // {204, 255, 76} |
|
|
|
Color3ub c{64, 127, 89}; |
|
auto d = Math::normalize<Color3>(c); // {0.251, 0.498, 0.349} |
|
@endcode |
|
|
|
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 |
|
scalar with vector: |
|
@code |
|
Vector3 a(1.0f, 2.0f, 3.0f); |
|
Vector3 b = a*5.0f - Vector3(3.0f, -0.5f, -7.5f); // b == {5.0f, 9.5f, 7.5f} |
|
Vector3 c = 1.0f/a; // c == {1.0f, 0.5f, 0.333f} |
|
@endcode |
|
|
|
As in GLSL, vectors can be also multiplied or divided component-wise: |
|
@code |
|
Vector3 a(1.0f, 2.0f, 3.0f); |
|
Vector3 b = a*Vector3(-0.5f, 2.0f, -7.0f); // b == {-0.5f, 4.0f, -21.0f} |
|
@endcode |
|
|
|
When working with integral vectors (i.e. 24bit RGB values), it is often |
|
desirable to multiply them with floating-point values but with integral result. |
|
In Magnum all mulitplication/division operations involving integral vectors |
|
will have integral result, you need to convert both arguments to the same |
|
floating-point type to have floating-point result. |
|
@code |
|
Color3ub color(80, 116, 34); |
|
Color3ub lighter = color*1.5f; // lighter = {120, 174, 51} |
|
|
|
Vector3i a(4, 18, -90); |
|
Vector3 multiplier(2.2f, 0.25f, 0.1f); |
|
Vector3i b = a*multiplier; // b == {8, 4, -9} |
|
Vector3 c = Vector3(a)*multiplier; // c == {8.0f, 4.5f, -9.0f} |
|
@endcode |
|
|
|
You can use also all bitwise operations on integral vectors: |
|
@code |
|
Vector2i size(256, 256); |
|
Vector2i mipLevel3Size = size >> 3; // == {32, 32} |
|
@endcode |
|
|
|
Matrices can be added, subtracted and multiplied with matrix multiplication. |
|
@code |
|
Matrix3x2 a; |
|
Matrix3x2 b; |
|
Matrix3x2 c = a + (-b); |
|
|
|
Matrix2x3 d; |
|
Matrix2x2 e = d*b; |
|
Matrix3x3 f = b*d; |
|
@endcode |
|
|
|
You can also multiply (properly sized) vectors with matrices. These operations |
|
are just convenience shortcuts for multiplying with single-column matrices: |
|
@code |
|
Matrix3x4 a; |
|
Vector3 b; |
|
Vector4 c = a*b; |
|
|
|
Math::RectangularMatrix<4, 1, Float> d; |
|
Matrix4x3 e = b*d; |
|
@endcode |
|
|
|
@section matrix-vector-componentwise Component-wise and inter-vector operations |
|
|
|
As shown above, vectors can be added and multiplied component-wise using the |
|
`+` or `*` operator. You can use @ref Math::Vector::sum() "sum()" and |
|
@ref Math::Vector::product() "product()" for sum or product of components in |
|
one vector: |
|
@code |
|
Float a = Vector3{1.5f, 0.3f, 8.0f}.sum(); // 8.8f |
|
Int b = Vector3i{32, -5, 7}.product() // 1120 |
|
@endcode |
|
|
|
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. |
|
@code |
|
Vector3i a{-5, 7, 24}; |
|
Vector3i b{8, -2, 12}; |
|
|
|
Vector3i min = Math::min(a, b); // {-5, -2, 12} |
|
Int max = a.max(); // 24 |
|
@endcode |
|
|
|
The vectors can be also compared component-wise, the result is returned in |
|
@ref Math::BoolVector class: |
|
@code |
|
BoolVector<3> largerOrEqual = a >= b; // {false, true, true} |
|
bool anySmaller = (a < b).any(); // true |
|
bool allLarger = (a > b).all(); // false |
|
@endcode |
|
|
|
There are also function for component-wise rounding, sign operations, square |
|
root, various interpolation and (de)normalization functionality: |
|
@code |
|
Vector3 a{5.5f, -0.3f, 75.0f}; |
|
Vector3 b = Math::round(a); // {5.0f, 0.0f, 75.0f} |
|
Vector3 c = Math::abs(a); // {5.5f, -0.3f, 75.0f} |
|
Vector3 d = Math::clamp(a, -0.2f, 55.0f); // {5.5f, -0.2f, 55.0f} |
|
@endcode |
|
|
|
Component-wise functions are implemented only for vectors and not for matrices |
|
to keep the math library in sane and maintainable size. Instead, you can |
|
reinterpret the matrix as vector and do the operation on it (and vice versa): |
|
@code |
|
Matrix3x2 mat; |
|
Math::Vector<6, Float> vec = mat.toVector(); |
|
// ... |
|
mat = Matrix3x2::fromVector(vec); |
|
@endcode |
|
|
|
Note that all component-wise functions in Math namespace work also for scalars: |
|
@code |
|
std::pair<Int, Int> minmax = Math::minmax(24, -5); // -5, 24 |
|
Int a = Math::lerp(0, 360, 0.75f); // 270 |
|
auto b = Math::denormalize<UnsignedByte>(0.89f); // 226 |
|
@endcode |
|
|
|
@section matrix-vector-column-major Matrices are column-major and vectors are columns |
|
|
|
OpenGL matrices are column-major, thus it is reasonable to have matrices in |
|
Magnum also column major (and vectors as columns). This has naturally some |
|
implications and it may differ from what is common in mathematics: |
|
|
|
- Order of template arguments in specification of @ref Math::RectangularMatrix |
|
is also column-major: |
|
@code |
|
Math::RectangularMatrix<2, 5, Int> mat; // two columns, five rows |
|
@endcode |
|
- Order of components in matrix constructors is also column-major, further |
|
emphasized by requirement that you have to pass directly column vectors: |
|
@code |
|
Math::Matrix3<Int> mat({0, 1, 2}, |
|
{3, 4, 5}, |
|
{6, 7, 8}); // first column is {0, 1, 2} |
|
@endcode |
|
- Element accessing order is also column-major, thus the bracket operator is |
|
accessing columns. Returned vector has also its own bracket operator, which |
|
is then indexing rows. |
|
@code |
|
mat[0] *= 2; // first column |
|
mat[2][0] = 5; // first element of third column |
|
@endcode |
|
- 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 user decision to |
|
operate with transposed matrices or use the slower non-transposed |
|
alternative of the algorithm. |
|
|
|
|
|
|
|
- Previous page: @ref types |
|
- Next page: @ref transformations |
|
*/ |
|
}
|
|
|