📄 vmath
字号:
// Component-wise negation
inline const Matrix operator -() const
{
Matrix result;
for (unsigned int i = 0; i < N*M; i++) result._data[i] = -_data[i];
return result;
}
// Component-wise subtraction with matrix
inline const Matrix operator -(const Matrix & m) const
{
Matrix result;
for (unsigned int i = 0; i < N*M; i++) result._data[i] = _data[i] - m._data[i];
return result;
}
// Component-wise subtraction with scalar
inline const Matrix operator -(const T & value) const
{
Matrix result;
for (unsigned int i = 0; i < N*M; i++) result._data[i] = _data[i] - value;
return result;
}
// Component-wise subtraction with scalar (scalar - component)
inline const Matrix inverseSubtract(const T & value) const
{
Matrix result;
for (unsigned int i = 0; i < N*M; i++) result._data[i] = value - _data[i];
return result;
}
// Component-wise subtraction with matrix (into self)
inline const Matrix operator -=(const Matrix & m)
{
for (unsigned int i = 0; i < N*M; i++) _data[i] -= m._data[i];
return *this;
}
// Component-wise subtraction with scalar (into self)
inline const Matrix operator -=(const T & value)
{
for (unsigned int i = 0; i < N*M; i++) _data[i] -= value;
return *this;
}
// Total all components
inline T total()
{
T tot = static_cast<T>(0);
for (unsigned int i = 0; i < N*M; i++) tot += _data[i];
return tot;
}
// Comparison for equality
inline const bool operator ==(const Matrix & m) const
{
for (unsigned int i = 0; i < N*M; i++) if (_data[i] != m._data[i]) return false;
return true;
}
// Comparison for inequality
inline const bool operator !=(const Matrix & m) const
{
return !(*this == m);
}
inline const bool operator <(const Matrix & m) const
{
for (unsigned int i = 0; i < N*M; i++) if (_data[i] >= m._data[i]) return false;
return true;
}
inline const bool operator <=(const Matrix & m) const
{
for (unsigned int i = 0; i < N*M; i++) if (_data[i] > m._data[i]) return false;
return true;
}
inline const bool operator >(const Matrix & m) const
{
for (unsigned int i = 0; i < N*M; i++) if (_data[i] <= m._data[i]) return false;
return true;
}
inline const bool operator >=(const Matrix & m) const
{
for (unsigned int i = 0; i < N*M; i++) if (_data[i] < m._data[i]) return false;
return true;
}
// Generates a converted matrix. Result is a matrix that has been converted from one type to another.
//
// Offers two options:
//
// rowColumnSwap: if true, toggle between row-major and column-major
// leftRightSwap: if true, toggle between left-handed and right-handed coordinate systems
//
// Default behaviour is a row-/column-major swap, but not a left-/right-handed swap.
inline Matrix genConvertedType(const bool rowColumnSwap = true, const bool leftRightSwap = false) const
{
TemplateAssert(N >= 3 && M >= 3);
Matrix result = *this;
if (leftRightSwap)
{
for (unsigned int i = 2; i < N; i++)
{
result(i,2) = -result(i,2);
}
}
if (rowColumnSwap)
{
result.transpose();
}
return result;
}
// Orthogonal transpose
//
// Note that matrix must be square (i.e. N == M)
inline void transpose()
{
TemplateAssert(N == M);
// Transpose the matrix
Matrix result;
for (unsigned int j = 0; j < M; j++)
{
for (unsigned int i = 0; i < N; i++)
{
result(j,i) = (*this)(i,j);
}
}
*this = result;
}
// Returns determinant of the matrix (4x4 only)
inline T determinant()
{
TemplateAssert(N == 4 && M == 4);
Matrix & m = *this;
return (m(0,0) * m(1,1) - m(1,0) * m(0,1)) * (m(2,2) * m(3,3) - m(3,2) * m(2,3))
- (m(0,0) * m(2,1) - m(2,0) * m(0,1)) * (m(1,2) * m(3,3) - m(3,2) * m(1,3))
+ (m(0,0) * m(3,1) - m(3,0) * m(0,1)) * (m(1,2) * m(2,3) - m(2,2) * m(1,3))
+ (m(1,0) * m(2,1) - m(2,0) * m(1,1)) * (m(0,2) * m(3,3) - m(3,2) * m(0,3))
- (m(1,0) * m(3,1) - m(3,0) * m(1,1)) * (m(0,2) * m(2,3) - m(2,2) * m(0,3))
+ (m(2,0) * m(3,1) - m(3,0) * m(2,1)) * (m(0,2) * m(1,3) - m(1,2) * m(0,3));
}
// Inverts the matrix (4x4 only)
inline void invert()
{
TemplateAssert(N == 4 && M == 4);
T d = determinant();
if (d == 0.0) return;
d = 1.0 / d;
Matrix & m = *this;
Matrix result;
result(0,0) = d * (m(1,1) * (m(2,2) * m(3,3) - m(3,2) * m(2,3)) + m(2,1) * (m(3,2) * m(1,3) - m(1,2) * m(3,3)) + m(3,1) * (m(1,2) * m(2,3) - m(2,2) * m(1,3)));
result(1,0) = d * (m(1,2) * (m(2,0) * m(3,3) - m(3,0) * m(2,3)) + m(2,2) * (m(3,0) * m(1,3) - m(1,0) * m(3,3)) + m(3,2) * (m(1,0) * m(2,3) - m(2,0) * m(1,3)));
result(2,0) = d * (m(1,3) * (m(2,0) * m(3,1) - m(3,0) * m(2,1)) + m(2,3) * (m(3,0) * m(1,1) - m(1,0) * m(3,1)) + m(3,3) * (m(1,0) * m(2,1) - m(2,0) * m(1,1)));
result(3,0) = d * (m(1,0) * (m(3,1) * m(2,2) - m(2,1) * m(3,2)) + m(2,0) * (m(1,1) * m(3,2) - m(3,1) * m(1,2)) + m(3,0) * (m(2,1) * m(1,2) - m(1,1) * m(2,2)));
result(0,1) = d * (m(2,1) * (m(0,2) * m(3,3) - m(3,2) * m(0,3)) + m(3,1) * (m(2,2) * m(0,3) - m(0,2) * m(2,3)) + m(0,1) * (m(3,2) * m(2,3) - m(2,2) * m(3,3)));
result(1,1) = d * (m(2,2) * (m(0,0) * m(3,3) - m(3,0) * m(0,3)) + m(3,2) * (m(2,0) * m(0,3) - m(0,0) * m(2,3)) + m(0,2) * (m(3,0) * m(2,3) - m(2,0) * m(3,3)));
result(2,1) = d * (m(2,3) * (m(0,0) * m(3,1) - m(3,0) * m(0,1)) + m(3,3) * (m(2,0) * m(0,1) - m(0,0) * m(2,1)) + m(0,3) * (m(3,0) * m(2,1) - m(2,0) * m(3,1)));
result(3,1) = d * (m(2,0) * (m(3,1) * m(0,2) - m(0,1) * m(3,2)) + m(3,0) * (m(0,1) * m(2,2) - m(2,1) * m(0,2)) + m(0,0) * (m(2,1) * m(3,2) - m(3,1) * m(2,2)));
result(0,2) = d * (m(3,1) * (m(0,2) * m(1,3) - m(1,2) * m(0,3)) + m(0,1) * (m(1,2) * m(3,3) - m(3,2) * m(1,3)) + m(1,1) * (m(3,2) * m(0,3) - m(0,2) * m(3,3)));
result(1,2) = d * (m(3,2) * (m(0,0) * m(1,3) - m(1,0) * m(0,3)) + m(0,2) * (m(1,0) * m(3,3) - m(3,0) * m(1,3)) + m(1,2) * (m(3,0) * m(0,3) - m(0,0) * m(3,3)));
result(2,2) = d * (m(3,3) * (m(0,0) * m(1,1) - m(1,0) * m(0,1)) + m(0,3) * (m(1,0) * m(3,1) - m(3,0) * m(1,1)) + m(1,3) * (m(3,0) * m(0,1) - m(0,0) * m(3,1)));
result(3,2) = d * (m(3,0) * (m(1,1) * m(0,2) - m(0,1) * m(1,2)) + m(0,0) * (m(3,1) * m(1,2) - m(1,1) * m(3,2)) + m(1,0) * (m(0,1) * m(3,2) - m(3,1) * m(0,2)));
result(0,3) = d * (m(0,1) * (m(2,2) * m(1,3) - m(1,2) * m(2,3)) + m(1,1) * (m(0,2) * m(2,3) - m(2,2) * m(0,3)) + m(2,1) * (m(1,2) * m(0,3) - m(0,2) * m(1,3)));
result(1,3) = d * (m(0,2) * (m(2,0) * m(1,3) - m(1,0) * m(2,3)) + m(1,2) * (m(0,0) * m(2,3) - m(2,0) * m(0,3)) + m(2,2) * (m(1,0) * m(0,3) - m(0,0) * m(1,3)));
result(2,3) = d * (m(0,3) * (m(2,0) * m(1,1) - m(1,0) * m(2,1)) + m(1,3) * (m(0,0) * m(2,1) - m(2,0) * m(0,1)) + m(2,3) * (m(1,0) * m(0,1) - m(0,0) * m(1,1)));
result(3,3) = d * (m(0,0) * (m(1,1) * m(2,2) - m(2,1) * m(1,2)) + m(1,0) * (m(2,1) * m(0,2) - m(0,1) * m(2,2)) + m(2,0) * (m(0,1) * m(1,2) - m(1,1) * m(0,2)));
*this = result;
}
// Fill the matrix with a single value
inline void fill(const T & value)
{
T *ptr = _data;
for (unsigned int i = 0; i < N*M; i++, ptr++) *ptr = value;
}
// Generate identity matrix
//
// Note that matrix must be square (i.e. N == M)
static const Matrix genIdentity()
{
TemplateAssert(N == M);
// Make it identity
Matrix result;
T *ptr = result._data;
for (unsigned int j = 0; j < M; j++)
{
for (unsigned int i = 0; i < N; i++, ptr++)
{
if (i == j) *ptr = static_cast<T>(1);
else *ptr = static_cast<T>(0);
}
}
return result;
}
// Generate rotation matrix (3x3) for rotation about the X axis (i.e. rotation happens along the Y/Z plane)
//
// Rotation happens in a counter-clockwise direction around the X vector
static const Matrix genXRotation(const T & theta)
{
TemplateAssert(N >= 3 && M >= 3);
// Start with identity
Matrix result = genIdentity();
// Fill it in
T ct = static_cast<T>(cos(static_cast<double>(theta)));
T st = static_cast<T>(sin(static_cast<double>(theta)));
result(1,1) = ct;
result(2,1) = -st;
result(1,2) = st;
result(2,2) = ct;
return result;
}
// Generate rotation matrix (3x3) for rotation about the Y axis (i.e. rotation happens along the X/Z plane)
//
// Rotation happens in a counter-clockwise direction around the Y vector
//
// Note that the matrix must be a minimum of 3x3
static const Matrix genYRotation(const T & theta)
{
TemplateAssert(N >= 3 && M >= 3);
// Start with identity
Matrix result = genIdentity();
// Fill it in
T ct = static_cast<T>(cos(static_cast<double>(theta)));
T st = static_cast<T>(sin(static_cast<double>(theta)));
result(0,0) = ct;
result(2,0) = st;
result(0,2) = -st;
result(2,2) = ct;
return result;
}
// Generate rotation matrix (3x3) for rotation about the Z axis (i.e. rotation happens along the X/Y plane)
//
// Rotation happens in a counter-clockwise direction around the Z vector
//
// Note that this matrix is allowed to be only 2x2 as this is a 2-D rotation
static const Matrix genZRotation(const T & theta)
{
TemplateAssert(N >= 3 && M >= 3);
// Start with identity
Matrix result = genIdentity();
// Fill it in
T ct = static_cast<T>(cos(static_cast<double>(theta)));
T st = static_cast<T>(sin(static_cast<double>(theta)));
result(0,0) = ct;
result(1,0) = -st;
result(0,1) = st;
result(1,1) = ct;
return result;
}
// Generate a concatenated rotation matrix (3x3) for rotation about all axes (i.e. arbitrary rotation)
//
// Rotation happens in a counter-clockwise direction around each vector
//
// Rotation happens in the following order: First Z, then Y and finally X.
static const Matrix genRotation(const T & xTheta, const T & yTheta, const T & zTheta)
{
return genZRotation(zTheta) >> genYRotation(yTheta) >> genXRotation(xTheta);
}
// Generate a 'look-at' matrix. Must be a 3x3 result because this routine uses a cross product
static const Matrix<3, 3, T> genLookat(const Matrix<3, 1, T> & v, const T & theta = static_cast<T>(0))
{
Matrix<3, 1, T> zAxis = v;
zAxis.normalize();
Matrix<3, 1, T> yAxis;
yAxis.fill(static_cast<T>(0));
// Handle the degenerate case... (this acts exactly like 3DS-R4)
if (!zAxis.x() && !zAxis.z()) yAxis.z() = -zAxis.y();
else yAxis.y() = static_cast<T>(1);
Matrix<3, 1, T> xAxis = yAxis % zAxis;
xAxis.normalize();
yAxis = xAxis % zAxis;
yAxis.normalize();
yAxis = -yAxis;
Matrix<3, 3, T> m(xAxis, yAxis, zAxis);
return m >> genZRotation(theta);
}
// Scale a matrix
inline void scale(const Matrix<N, 1, T> & m)
{
TemplateAssert(N <= M);
for (unsigned int i = 0; i < N; i++)
{
(*this)(i,i) *= m(i,0);
}
}
// Generate a scale matrix
static Matrix genScale(const Matrix<N, 1, T> & m)
{
TemplateAssert(N <= M);
Matrix result;
result = genIdentity();
for (unsigned int i = 0; i < N; i++)
{
result(i,i) *= m(i,0);
}
return result;
}
// Generate a translation matrix
static Matrix genTranslate(const Matrix<N, 1, T> & m)
{
TemplateAssert(M <= N);
Matrix result;
result = genIdentity();
for (unsigned int i = 0; i < M; i++)
{
result(N-1,i) += m(i,0);
}
return result;
}
// Generate a shear matrix
static Matrix genShear(const T x, const T y)
{
TemplateAssert(N > 1 && M > 1);
Matrix result;
result = genIdentity();
result(1,0) = x;
result(0,1) = y;
return result;
}
// Generate a (4x4) perspective projection matrix (as per D3D)
static const Matrix<4, 4, T> genProjectPerspectiveD3D(const T & fov, const T & aspect, const T & n, const T & f)
{
T w = static_cast<T>(1.0 / tan(fov / static_cast<T>(2)));
T h = static_cast<T>(1.0 / tan(fov / static_cast<T>(2)));
if (aspect > 1.0) w /= aspect;
else h *= aspect;
T q = f / (f - n);
Matrix<4, 4, T> result;
result.fill(static_cast<T>(0));
result(0,0) = w;
result(1,1) = h;
result(2,2) = q;
result(3,2) = -q*n;
result(2,3) = 1;
return result;
}
// Generate a (4x4) perspective projection matrix (as per Blinn)
static const Matrix<4, 4, T> genProjectPerspectiveBlinn(const T & fov, const T & aspect, const T & n, const T & f)
{
T w = static_cast<T>(cos(fov / static_cast<T>(2)));
T h = static_cast<T>(cos(fov / static_cast<T>(2)));
if (aspect > 1.0) w /= aspect;
else h *= aspect;
T s = static_cast<T>(sin(fov / static_cast<T>(2)));
T d = static_cast<T>(1) - n/f;
Matrix<4, 4, T> result;
result.fill(static_cast<T>(0));
result(0,0) = w;
result(1,1) = h;
result(2,2) = s / d;
result(3,2) = -(s * n / d);
result(2,3) = s;
return result;
}
// Generate a (4x4) perspective projection matrix (as per glFrustum)
static const Matrix<4, 4, T> genProjectPerspectiveGlFrustum(const T & l, const T & r, const T & b, const T & t, const T & n, const T & f)
{
Matrix<4, 4, T> result;
result.fill(static_cast<T>(0));
result(0,0) = (2*n)/(r-l);
result(2,0) = (r+l)/(r-l);
result(1,1) = (2*n)/(t-b);
result(2,1) = (t+b)/(t-b);
result(2,2) = (-(f+n))/(f-n);
result(3,2) = (-2*f*n)/(f-n);
result(2,3) = -1;
return result;
}
// Generate a (4x4) orthogonal projection matrix (as per glOrtho)
static const Matrix<4, 4, T> genProjectGlOrtho(const T & l, const T & r, const T & b, const T & t, const T & n, const T & f)
{
Matrix<4, 4, T> result;
result.fill(static_cast<T>(0));
result(0,0) = 2/(r-l);
result(1,1) = 2/(t-b);
result(2,2) = -2/(f-n);
result(3,3) = 1;
result(3,0) = -((r+l)/(r-l));
result(3,1) = -((t+b)/(t-b));
result(3,2) = -((f+n)/(f-n));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -