|
|
|
|
namespace Magnum { namespace Math {
|
|
|
|
|
/** @page matrix-vector Operations with matrices and vectors
|
|
|
|
|
|
|
|
|
|
@brief Introduction to essential classes of the graphics pipeline.
|
|
|
|
|
|
|
|
|
|
@tableofcontents
|
|
|
|
|
|
|
|
|
|
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. This
|
|
|
|
|
page will overview their usage and introduce some tricks to make your life
|
|
|
|
|
easier.
|
|
|
|
|
|
|
|
|
|
@section matrix-vector-hierarchy Matrix and vector classes
|
|
|
|
|
|
|
|
|
|
%Magnum has three main matrix and vector classes: RectangularMatrix, (square)
|
|
|
|
|
Matrix and Vector. To achieve greatest code reuse, %Matrix is internally
|
Math: matrix/vector rework, part 2: matrix as array of column vectors.
Overall architecture is simplififed with this change and also it's not
needed to use reinterpret_cast in matrix internals anymore, thus there
is no need for operator() and [][] works now always as expected without
any risk of GCC misoptimizations.
On the other side, constructing matrix from list of elements is not
possible anymore. You have to specify the elements as list of
column vectors, which might be less convenient to write, but it helps to
distinguish what is column and what is row:
Matrix<2, int> a(1, 2, // before
3, 4);
Matrix<2, int> a(Vector<2, int>(1, 2), // now
Vector<2, int>(3, 4));
For some matrix specializations (i.e. Matrix3 and Matrix4) it is
possible to use list-initialization instead of explicit type
specification:
Matrix<3, int>({1, 2, 3},
{4, 5, 6},
{7, 8, 9});
I didn't yet figure out how to properly implement the general
(constexpr) constructor to also take lists, so it's a bit ugly for now.
Matrix operations are now done column-wise, which should help with
future SIMD implementations, documentation is also updated accordingly.
I also removed forgotten remains of matrix/matrix operator*=(), which
can be confusing, as the multiplication is not commutative. Why it is
not present is explained in d9c900f076f2f87c7b7ba3f37a3179c0c0e4a02c.
13 years ago
|
|
|
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 Matrix3 and Matrix4,
|
|
|
|
|
implementing various transformation in 2D and 3D, Vector2, Vector3 and 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. Color3 and Color4 for
|
|
|
|
|
color handling and conversion.
|
|
|
|
|
|
|
|
|
|
@section matrix-vector-construction Constructing matrices and vectors
|
|
|
|
|
|
|
|
|
|
Default constructors of RectangularMatrix and Vector (and Vector2, Vector3,
|
|
|
|
|
Vector4, Color3) create zero-filled objects. Matrix (and Matrix3, Matrix4) is
|
|
|
|
|
by default constructed as identity matrix. Color4 has alpha value set to opaque.
|
|
|
|
|
@code
|
|
|
|
|
RectangularMatrix<2, 3, Int> a; // zero-filled
|
|
|
|
|
Vector<3, Int> b; // zero-filled
|
|
|
|
|
|
|
|
|
|
Matrix<3, Int> identity; // diagonal set to 1
|
|
|
|
|
Matrix<3, Int> zero(Matrix<3, Int>::Zero); // zero-filled
|
|
|
|
|
|
|
|
|
|
Color4<Float> black1; // {0.0f, 0.0f, 0.0f, 1.0f}
|
|
|
|
|
Color4<unsigned char> black2; // {0, 0, 0, 255}
|
|
|
|
|
@endcode
|
|
|
|
|
|
Math: matrix/vector rework, part 2: matrix as array of column vectors.
Overall architecture is simplififed with this change and also it's not
needed to use reinterpret_cast in matrix internals anymore, thus there
is no need for operator() and [][] works now always as expected without
any risk of GCC misoptimizations.
On the other side, constructing matrix from list of elements is not
possible anymore. You have to specify the elements as list of
column vectors, which might be less convenient to write, but it helps to
distinguish what is column and what is row:
Matrix<2, int> a(1, 2, // before
3, 4);
Matrix<2, int> a(Vector<2, int>(1, 2), // now
Vector<2, int>(3, 4));
For some matrix specializations (i.e. Matrix3 and Matrix4) it is
possible to use list-initialization instead of explicit type
specification:
Matrix<3, int>({1, 2, 3},
{4, 5, 6},
{7, 8, 9});
I didn't yet figure out how to properly implement the general
(constexpr) constructor to also take lists, so it's a bit ugly for now.
Matrix operations are now done column-wise, which should help with
future SIMD implementations, documentation is also updated accordingly.
I also removed forgotten remains of matrix/matrix operator*=(), which
can be confusing, as the multiplication is not commutative. Why it is
not present is explained in d9c900f076f2f87c7b7ba3f37a3179c0c0e4a02c.
13 years ago
|
|
|
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.
|
|
|
|
|
@code
|
|
|
|
|
Vector3<Int> vec(0, 1, 2);
|
Math: matrix/vector rework, part 2: matrix as array of column vectors.
Overall architecture is simplififed with this change and also it's not
needed to use reinterpret_cast in matrix internals anymore, thus there
is no need for operator() and [][] works now always as expected without
any risk of GCC misoptimizations.
On the other side, constructing matrix from list of elements is not
possible anymore. You have to specify the elements as list of
column vectors, which might be less convenient to write, but it helps to
distinguish what is column and what is row:
Matrix<2, int> a(1, 2, // before
3, 4);
Matrix<2, int> a(Vector<2, int>(1, 2), // now
Vector<2, int>(3, 4));
For some matrix specializations (i.e. Matrix3 and Matrix4) it is
possible to use list-initialization instead of explicit type
specification:
Matrix<3, int>({1, 2, 3},
{4, 5, 6},
{7, 8, 9});
I didn't yet figure out how to properly implement the general
(constexpr) constructor to also take lists, so it's a bit ugly for now.
Matrix operations are now done column-wise, which should help with
future SIMD implementations, documentation is also updated accordingly.
I also removed forgotten remains of matrix/matrix operator*=(), which
can be confusing, as the multiplication is not commutative. Why it is
not present is explained in d9c900f076f2f87c7b7ba3f37a3179c0c0e4a02c.
13 years ago
|
|
|
|
|
|
|
|
Matrix3<Int> mat({0, 1, 2},
|
Math: matrix/vector rework, part 2: matrix as array of column vectors.
Overall architecture is simplififed with this change and also it's not
needed to use reinterpret_cast in matrix internals anymore, thus there
is no need for operator() and [][] works now always as expected without
any risk of GCC misoptimizations.
On the other side, constructing matrix from list of elements is not
possible anymore. You have to specify the elements as list of
column vectors, which might be less convenient to write, but it helps to
distinguish what is column and what is row:
Matrix<2, int> a(1, 2, // before
3, 4);
Matrix<2, int> a(Vector<2, int>(1, 2), // now
Vector<2, int>(3, 4));
For some matrix specializations (i.e. Matrix3 and Matrix4) it is
possible to use list-initialization instead of explicit type
specification:
Matrix<3, int>({1, 2, 3},
{4, 5, 6},
{7, 8, 9});
I didn't yet figure out how to properly implement the general
(constexpr) constructor to also take lists, so it's a bit ugly for now.
Matrix operations are now done column-wise, which should help with
future SIMD implementations, documentation is also updated accordingly.
I also removed forgotten remains of matrix/matrix operator*=(), which
can be confusing, as the multiplication is not commutative. Why it is
not present is explained in d9c900f076f2f87c7b7ba3f37a3179c0c0e4a02c.
13 years ago
|
|
|
{3, 4, 5},
|
|
|
|
|
{6, 7, 8});
|
|
|
|
|
@endcode
|
|
|
|
|
All constructors check number of passed arguments and the errors are catched
|
|
|
|
|
at compile time.
|
|
|
|
|
|
|
|
|
|
You can specify all components of vector or whole diagonal of square matrix at
|
|
|
|
|
once:
|
|
|
|
|
@code
|
|
|
|
|
Matrix3<Int> diag(Matrix3<Int>::Identity, 2); // diagonal set to 2, zeros elsewhere
|
|
|
|
|
Vector3<Int> fill(10); // {10, 10, 10}
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
It is possible to create matrices from other matrices and vectors with the
|
|
|
|
|
same row count; vectors from vector and scalar:
|
|
|
|
|
@code
|
|
|
|
|
RectangularMatrix<2, 3, Int> a;
|
|
|
|
|
Vector3<Int> b, c;
|
|
|
|
|
Matrix3<Int> mat(a, b);
|
|
|
|
|
Vector<8, Int> vec(1, b, 2, c);
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
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 };
|
|
|
|
|
RectangularMatrix<2, 3, 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.
|
|
|
|
|
|
|
|
|
|
You can also *explicitly* convert between data types:
|
|
|
|
|
@code
|
|
|
|
|
Vector4<Float> floating(1.3f, 2.7f, -15.0f, 7.0f);
|
|
|
|
|
Vector4<Int> integral(floating); // {1, 2, -15, 7}
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@section matrix-vector-component-access Accessing matrix and vector components
|
|
|
|
|
|
|
|
|
|
Column vectors of matrices and vector components can be accessed using square
|
|
|
|
|
brackets, there is also round bracket operator for accessing matrix components
|
|
|
|
|
directly:
|
|
|
|
|
@code
|
|
|
|
|
RectangularMatrix<3, 2, Int> a;
|
|
|
|
|
a[2] /= 2; // third column (column major indexing, see explanation below)
|
|
|
|
|
a[0][1] = 5; // first column, second element
|
|
|
|
|
|
|
|
|
|
Vector<3, Int> b;
|
|
|
|
|
b[1] = 1; // second element
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
Fixed-size vector subclasses have functions for accessing named components
|
|
|
|
|
and subparts:
|
|
|
|
|
@code
|
|
|
|
|
Vector4<Int> a;
|
|
|
|
|
Int x = a.x();
|
|
|
|
|
a.y() += 5;
|
|
|
|
|
|
|
|
|
|
Vector3<Int> 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 swizzle() function:
|
|
|
|
|
@code
|
|
|
|
|
Vector<4, Int> original(-1, 2, 3, 4);
|
|
|
|
|
Vector<4, Int> bgra = swizzle<'b', 'g', 'r', 'a'>(original); // { 3, 2, -1, 4 }
|
|
|
|
|
Vector<6, Int> w10xyz = swizzle<'w', '1', '0', 'x', 'y', 'z'>(original); // { 4, 1, 0, -1, 2, 3 }
|
|
|
|
|
@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 RectangularMatrix is also
|
|
|
|
|
column-major:
|
|
|
|
|
@code
|
|
|
|
|
RectangularMatrix<2, 3, Int> mat; // two columns, three rows
|
|
|
|
|
@endcode
|
Math: matrix/vector rework, part 2: matrix as array of column vectors.
Overall architecture is simplififed with this change and also it's not
needed to use reinterpret_cast in matrix internals anymore, thus there
is no need for operator() and [][] works now always as expected without
any risk of GCC misoptimizations.
On the other side, constructing matrix from list of elements is not
possible anymore. You have to specify the elements as list of
column vectors, which might be less convenient to write, but it helps to
distinguish what is column and what is row:
Matrix<2, int> a(1, 2, // before
3, 4);
Matrix<2, int> a(Vector<2, int>(1, 2), // now
Vector<2, int>(3, 4));
For some matrix specializations (i.e. Matrix3 and Matrix4) it is
possible to use list-initialization instead of explicit type
specification:
Matrix<3, int>({1, 2, 3},
{4, 5, 6},
{7, 8, 9});
I didn't yet figure out how to properly implement the general
(constexpr) constructor to also take lists, so it's a bit ugly for now.
Matrix operations are now done column-wise, which should help with
future SIMD implementations, documentation is also updated accordingly.
I also removed forgotten remains of matrix/matrix operator*=(), which
can be confusing, as the multiplication is not commutative. Why it is
not present is explained in d9c900f076f2f87c7b7ba3f37a3179c0c0e4a02c.
13 years ago
|
|
|
- Order of components in matrix constructors is also column-major, further
|
|
|
|
|
emphasized by requirement that you have to pass directly column vectors:
|
|
|
|
|
@code
|
|
|
|
|
Matrix3<Int> mat({0, 1, 2},
|
Math: matrix/vector rework, part 2: matrix as array of column vectors.
Overall architecture is simplififed with this change and also it's not
needed to use reinterpret_cast in matrix internals anymore, thus there
is no need for operator() and [][] works now always as expected without
any risk of GCC misoptimizations.
On the other side, constructing matrix from list of elements is not
possible anymore. You have to specify the elements as list of
column vectors, which might be less convenient to write, but it helps to
distinguish what is column and what is row:
Matrix<2, int> a(1, 2, // before
3, 4);
Matrix<2, int> a(Vector<2, int>(1, 2), // now
Vector<2, int>(3, 4));
For some matrix specializations (i.e. Matrix3 and Matrix4) it is
possible to use list-initialization instead of explicit type
specification:
Matrix<3, int>({1, 2, 3},
{4, 5, 6},
{7, 8, 9});
I didn't yet figure out how to properly implement the general
(constexpr) constructor to also take lists, so it's a bit ugly for now.
Matrix operations are now done column-wise, which should help with
future SIMD implementations, documentation is also updated accordingly.
I also removed forgotten remains of matrix/matrix operator*=(), which
can be confusing, as the multiplication is not commutative. Why it is
not present is explained in d9c900f076f2f87c7b7ba3f37a3179c0c0e4a02c.
13 years ago
|
|
|
{3, 4, 5},
|
|
|
|
|
{6, 7, 8}); // first column is {0, 1, 2}
|
|
|
|
|
@endcode
|
Math: matrix/vector rework, part 2: matrix as array of column vectors.
Overall architecture is simplififed with this change and also it's not
needed to use reinterpret_cast in matrix internals anymore, thus there
is no need for operator() and [][] works now always as expected without
any risk of GCC misoptimizations.
On the other side, constructing matrix from list of elements is not
possible anymore. You have to specify the elements as list of
column vectors, which might be less convenient to write, but it helps to
distinguish what is column and what is row:
Matrix<2, int> a(1, 2, // before
3, 4);
Matrix<2, int> a(Vector<2, int>(1, 2), // now
Vector<2, int>(3, 4));
For some matrix specializations (i.e. Matrix3 and Matrix4) it is
possible to use list-initialization instead of explicit type
specification:
Matrix<3, int>({1, 2, 3},
{4, 5, 6},
{7, 8, 9});
I didn't yet figure out how to properly implement the general
(constexpr) constructor to also take lists, so it's a bit ugly for now.
Matrix operations are now done column-wise, which should help with
future SIMD implementations, documentation is also updated accordingly.
I also removed forgotten remains of matrix/matrix operator*=(), which
can be confusing, as the multiplication is not commutative. Why it is
not present is explained in d9c900f076f2f87c7b7ba3f37a3179c0c0e4a02c.
13 years ago
|
|
|
- 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
|
Math: matrix/vector rework, part 2: matrix as array of column vectors.
Overall architecture is simplififed with this change and also it's not
needed to use reinterpret_cast in matrix internals anymore, thus there
is no need for operator() and [][] works now always as expected without
any risk of GCC misoptimizations.
On the other side, constructing matrix from list of elements is not
possible anymore. You have to specify the elements as list of
column vectors, which might be less convenient to write, but it helps to
distinguish what is column and what is row:
Matrix<2, int> a(1, 2, // before
3, 4);
Matrix<2, int> a(Vector<2, int>(1, 2), // now
Vector<2, int>(3, 4));
For some matrix specializations (i.e. Matrix3 and Matrix4) it is
possible to use list-initialization instead of explicit type
specification:
Matrix<3, int>({1, 2, 3},
{4, 5, 6},
{7, 8, 9});
I didn't yet figure out how to properly implement the general
(constexpr) constructor to also take lists, so it's a bit ugly for now.
Matrix operations are now done column-wise, which should help with
future SIMD implementations, documentation is also updated accordingly.
I also removed forgotten remains of matrix/matrix operator*=(), which
can be confusing, as the multiplication is not commutative. Why it is
not present is explained in d9c900f076f2f87c7b7ba3f37a3179c0c0e4a02c.
13 years ago
|
|
|
mat[2][0] = 5; // first element of first 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.
|
|
|
|
|
*/
|
|
|
|
|
}}
|