///////////////////////////////////////////////////////////////////// // Collection of Linear Math Stuff // © Dan Andersson 2013 ///////////////////////////////////////////////////////////////////// #pragma once #ifndef LINEARMATH_H #define LINEARMATH_H #include "Vector.h" #include "Matrix.h" #include "Quaternion.h" #include namespace LinearAlgebra { // x2 template Matrix2x2 operator * ( const Matrix2x2 &left, const Matrix2x2 &right ) { return Matrix2x2( (left.m11 * right.m11) + (left.m21 * right.m12), (left.m11 * right.m21) + (left.m21 * right.m22), (left.m12 * right.m11) + (left.m22 * right.m12), (left.m12 * right.m21) + (left.m22 * right.m22) ); } template Vector2 operator * ( const Matrix2x2 &matrix, const Vector2 &vector ) { return Vector2( (matrix.m11 * vector.x) + (matrix.m21 * vector.y), (matrix.m12 * vector.x) + (matrix.m22 * vector.y) ); } template Vector2 operator * ( const Vector2 &vector, const Matrix2x2 &left ) { return Vector2( (vector.x * matrix.m11) + (vector.y * matrix.m12), (vector.x * matrix.m21) + (vector.y * matrix.m22) ); } // x3 template Matrix3x3 operator * ( const Matrix3x3 &left, const Matrix3x3 &right ) { Matrix3x3 product, leftT = left.getTranspose(); for( int i = 0; i < 3; ++i ) for( int j = 0; j < 3; ++j ) product.m[i][j] = leftT.v[i].dot(right.v[j]); return product; } template Vector3 operator * ( const Matrix3x3 &matrix, const Vector3 &vector ) { return Vector3( (matrix.m11 * vector.x) + (matrix.m21 * vector.y) + (matrix.m31 * vector.z), (matrix.m12 * vector.x) + (matrix.m22 * vector.y) + (matrix.m32 * vector.z), (matrix.m13 * vector.x) + (matrix.m23 * vector.y) + (matrix.m33 * vector.z) ); } template Vector3 operator * ( const Vector3 &vector, const Matrix3x3 &left ) { return Vector3( (vector.x * matrix.m11) + (vector.y * matrix.m12) + (vector.z * matrix.m13), (vector.x * matrix.m21) + (vector.y * matrix.m22) + (vector.z * matrix.m23), (vector.x * matrix.m31) + (vector.y * matrix.m32) + (vector.z * matrix.m33) ); } // x4 template Matrix4x4 operator * ( const Matrix4x4 &left, const Matrix4x4 &right ) { Matrix4x4 product, rightT = right.getTranspose(); for( int i = 0; i < 4; ++i ) { product.m[i][0] = left.v[i].dot(rightT.v[0]); product.m[i][1] = left.v[i].dot(rightT.v[1]); product.m[i][2] = left.v[i].dot(rightT.v[2]); product.m[i][3] = left.v[i].dot(rightT.v[3]); } return product; } template Vector4 operator * ( const Matrix4x4 &matrix, const Vector4 &vector ) { return Vector4( (matrix.m11 * vector.x) + (matrix.m21 * vector.y) + (matrix.m31 * vector.z) + (matrix.m41 * vector.w), (matrix.m12 * vector.x) + (matrix.m22 * vector.y) + (matrix.m32 * vector.z) + (matrix.m42 * vector.w), (matrix.m13 * vector.x) + (matrix.m23 * vector.y) + (matrix.m33 * vector.z) + (matrix.m43 * vector.w), (matrix.m14 * vector.x) + (matrix.m24 * vector.y) + (matrix.m34 * vector.z) + (matrix.m44 * vector.w) ); } template // works for column weighted matrixes Vector4 operator * ( const Vector4 &vector, const Matrix4x4 &matrix ) { return Vector4( (vector.x * matrix.m11) + (vector.y * matrix.m12) + (vector.z * matrix.m13) + (vector.w * matrix.m14), (vector.x * matrix.m21) + (vector.y * matrix.m22) + (vector.z * matrix.m23) + (vector.w * matrix.m24), (vector.x * matrix.m31) + (vector.y * matrix.m32) + (vector.z * matrix.m33) + (vector.w * matrix.m34), (vector.x * matrix.m41) + (vector.y * matrix.m42) + (vector.z * matrix.m43) + (vector.w * matrix.m44) ); } namespace _2D { template inline void translationMatrix( Matrix3x3 &output, const Vector2 &position ) // { output = Matrix3x3( 1, 0, position.x, 0, 1, position.y, 0, 0, 1 ); } { output = Matrix3x3( 1, 0, 0, 0, 1, 0, position.x, position.y, 1 ); } template void rotationMatrix( Matrix2x2 &output, const ElementType &radian ) { ElementType s = std::sin( radian ), c = std::cos( radian ); // output = Matrix2x2( c, -s, s, c ); output = Matrix2x2( c, s, -s, c ); } template void rotationMatrix( Matrix3x3 &output, const ElementType &radian ) { ElementType s = std::sin( radian ), c = std::cos( radian ); // output = Matrix3x3( c, -s, 0, s, c, 0, 0, 0, 1 ); output = Matrix3x3( c, s, 0, -s, c, 0, 0, 0, 1 ); } template void rigidBodyMatrix( Matrix3x3 &output, const ElementType &radian, const Vector2 &position ) { ElementType s = std::sin( radian ), c = std::cos( radian ); // output = Matrix3x3( c, -s, position.x, s, c, position.y, 0, 0, 1 ); output = Matrix3x3( c, s, 0, -s, c, 0, position.x, position.y, 1 ); } } namespace _3D { template inline void translationMatrix( Matrix4x4 &output, const Vector3 &position ) // { output = Matrix4x4( 1, 0, 0, position.x, 0, 1, 0, position.y, 0, 0, 1, position.z, 0, 0, 0, 1 ); } { output = Matrix4x4( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, position.x, position.y, position.z, 1 ); } template void inverseRigidBody( Matrix4x4 &output, const Matrix4x4 &rigidBody ) { output = Matrix4x4( rigidBody.m11, rigidBody.m21, rigidBody.m31, 0, rigidBody.m12, rigidBody.m22, rigidBody.m32, 0, rigidBody.m13, rigidBody.m23, rigidBody.m33, 0, -rigidBody.v[3].xyz.dot(rigidBody.v[0].xyz), -rigidBody.v[3].xyz.dot(rigidBody.v[1].xyz), -rigidBody.v[3].xyz.dot(rigidBody.v[2].xyz), 1 ); } template void rotationMatrix_AxisX( Matrix3x3 &output, const ElementType &radian ) { ElementType s = std::sin( radian ), c = std::cos( radian ); // output = Matrix3x3( 1, 0, 0, 0, c, -s, 0, s, c ); output = Matrix3x3( 1, 0, 0, 0, c, s, 0, -s, c ); } template void rotationMatrix_AxisX( Matrix4x4 &output, const ElementType &radian ) { ElementType s = std::sin( radian ), c = std::cos( radian ); // output = Matrix4x4( 1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1 ); output = Matrix4x4( 1, 0, 0, 0, 0, c, s, 0, 0, -s, c, 0, 0, 0, 0, 1 ); } template void rotationMatrix_AxisY( Matrix3x3 &output, const ElementType &radian ) { ElementType s = std::sin( radian ), c = std::cos( radian ); // output = Matrix3x3( c, 0, s, 0, 1, 0, -s, 0, c ); output = Matrix3x3( c, 0, -s, 0, 1, 0, s, 0, c ); } template void rotationMatrix_AxisY( Matrix4x4 &output, const ElementType &radian ) { ElementType s = std::sin( radian ), c = std::cos( radian ); // output = Matrix4x4( c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1 ); output = Matrix4x4( c, 0, -s, 0, 0, 1, 0, 0, s, 0, c, 0, 0, 0, 0, 1 ); } template inline void rotationMatrix_AxisZ( Matrix3x3 &output, const ElementType &radian ) { ::LinearAlgebra::_2D::rotationMatrix( output, radian ); } template void rotationMatrix_AxisZ( Matrix4x4 &output, const ElementType &radian ) { ElementType s = std::sin( radian ), c = std::cos( radian ); // output = Matrix4x4( c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ); output = Matrix4x4( c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ); } template void rotationMatrix( Matrix4x4 &output, const Vector3 &normalizedAxis, const ElementType &radian ) { // TODO : Optimize ElementType r = radian * 0.5f, s = std::sin( r ), c = std::cos( r ); Quaternion q( normalizedAxis * s, c ), qConj = q.getConjugate(); output.v[0] = Vector4( (q*Vector3(1,0,0)*qConj).imaginary, 0 ); output.v[1] = Vector4( (q*Vector3(0,1,0)*qConj).imaginary, 0 ); output.v[2] = Vector4( (q*Vector3(0,0,1)*qConj).imaginary, 0 ); output.v[3] = Vector4( 0, 0, 0, 1 ); } /* returns a deltaAngularAxis which is a vectorProduct of the movementVector and leverVector. angular: (1/I) * L, there I is known as the "moment of inertia", L as the "angular momentum vector". lever: Displacement vector relative to the rotation pivot. Recommended reading: http://en.wikipedia.org/wiki/Torque */ template inline Vector3 deltaAngularAxis( const Vector3 &movement, const Vector3 &lever ) { return movement.cross( lever ); } template inline Vector3 particleRotationMovement( const Vector3 &deltaRadian, const Vector3 &lever ) { return lever.cross(deltaRadian) /= lever.dot(lever); } template inline Vector3 vectorProjection( const Vector3 &vector, const Vector3 &axis ) { return axis * ( vector.dot(axis) / axis.dot(axis) ); } /* output; is set to a rigibody matrix that revolve/rotate around centerOfMass and then translates. sumDeltaAngularAxis: Sum of all ( (1/I) * ( L x D ) )-vectorproducts. There I is known as "moment of inertia", L as "angular momentum vector" and D the "lever vector". sumTranslation: Sum of all the translation vectors. centerOfMass: The point the particles is to revolve around, prior to translation. Default set to null vector aka origo. Recommended reading: http://en.wikipedia.org/wiki/Torque */ template void rigidBodyMatrix( Matrix4x4 &output, const Vector3 &sumDeltaAngularAxis, const Vector3 &sumTranslation, const Vector3 ¢erOfMass = Vector3::null ) { ElementType deltaRadian = sumDeltaAngularAxis.length(); if( deltaRadian != 0 ) { Vector3 axis = sumDeltaAngularAxis / deltaRadian; rotationMatrix( output, axis, deltaRadian ); output.v[3].xyz = centerOfMass; output.v[3].x -= centerOfMass.dot( output.v[0].xyz ); output.v[3].y -= centerOfMass.dot( output.v[1].xyz ); output.v[3].z -= centerOfMass.dot( output.v[2].xyz ); } else output = Matrix4x4::identity; output.v[3].xyz += sumTranslation; } /* output; is set to an orthographic projection matrix. width; of the projection sample volume. height; of the projection sample volume. nearClip: Distance to the nearClippingPlane. farClip: Distance to the farClippingPlane */ template void projectionMatrix_Orthographic( Matrix4x4 &output, const ElementType &width, const ElementType &height, const ElementType &nearClip, const ElementType &farClip ) { ElementType c = 1; c /= nearClip - farClip; output = Matrix4x4( 2/width, 0, 0, 0, 0, 2/height, 0, 0, 0, 0, -c, 0, 0, 0, nearClip*c, 1 ); } /* output; is set to a perspective transform matrix. vertFoV; is the vertical field of vision in radians. (se FoV Hor+ ) aspect; is the screenratio width/height (example 16/9 or 16/10 ) nearClip: Distance to the nearClippingPlane farClip: Distance to the farClippingPlane */ template void projectionMatrix_Perspective( Matrix4x4 &output, const ElementType &vertFoV, const ElementType &aspect, const ElementType &nearClip, const ElementType &farClip ) { ElementType fov = 1 / ::std::tan( vertFoV * 0.5f ), dDepth = farClip; dDepth /= farClip - nearClip; output = Matrix4x4( fov / aspect, 0, 0, 0, 0, fov, 0, 0, 0, 0, dDepth, 1, 0, 0, -(dDepth * nearClip), 0 ); } } } #endif