2009-02-22 10:43:35 +00:00
#region - - - License - - -
/ *
Copyright ( c ) 2006 - 2008 The Open Toolkit library .
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 .
* /
#endregion
using System ;
using System.Runtime.InteropServices ;
2009-06-25 11:42:05 +00:00
namespace OpenTK
2009-02-22 10:43:35 +00:00
{
/// <summary>
2013-03-20 12:44:12 +00:00
/// Represents a 4x4 matrix containing 3D rotation, scale, transform, and projection with double-precision components.
2009-02-22 10:43:35 +00:00
/// </summary>
2013-03-20 12:44:12 +00:00
/// <seealso cref="Matrix4"/>
2009-02-22 10:43:35 +00:00
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Matrix4d : IEquatable < Matrix4d >
{
#region Fields
2009-07-17 08:27:25 +00:00
/// <summary>
/// Top row of the matrix
/// </summary>
2009-02-22 10:43:35 +00:00
public Vector4d Row0 ;
2009-07-17 08:27:25 +00:00
/// <summary>
/// 2nd row of the matrix
/// </summary>
2009-02-22 10:43:35 +00:00
public Vector4d Row1 ;
2009-07-17 08:27:25 +00:00
/// <summary>
/// 3rd row of the matrix
/// </summary>
2009-02-22 10:43:35 +00:00
public Vector4d Row2 ;
2009-07-17 08:27:25 +00:00
/// <summary>
/// Bottom row of the matrix
/// </summary>
2009-02-22 10:43:35 +00:00
public Vector4d Row3 ;
2009-07-17 08:27:25 +00:00
/// <summary>
/// The identity matrix
/// </summary>
public static Matrix4d Identity = new Matrix4d ( Vector4d . UnitX , Vector4d . UnitY , Vector4d . UnitZ , Vector4d . UnitW ) ;
2009-02-22 10:43:35 +00:00
#endregion
#region Constructors
2009-07-17 08:27:25 +00:00
/// <summary>
/// Constructs a new instance.
/// </summary>
/// <param name="row0">Top row of the matrix</param>
/// <param name="row1">Second row of the matrix</param>
/// <param name="row2">Third row of the matrix</param>
/// <param name="row3">Bottom row of the matrix</param>
public Matrix4d ( Vector4d row0 , Vector4d row1 , Vector4d row2 , Vector4d row3 )
{
Row0 = row0 ;
Row1 = row1 ;
Row2 = row2 ;
Row3 = row3 ;
}
2009-02-22 10:43:35 +00:00
2009-04-12 16:34:35 +00:00
/// <summary>
/// Constructs a new instance.
/// </summary>
/// <param name="m00">First item of the first row.</param>
/// <param name="m01">Second item of the first row.</param>
/// <param name="m02">Third item of the first row.</param>
/// <param name="m03">Fourth item of the first row.</param>
/// <param name="m10">First item of the second row.</param>
/// <param name="m11">Second item of the second row.</param>
/// <param name="m12">Third item of the second row.</param>
/// <param name="m13">Fourth item of the second row.</param>
/// <param name="m20">First item of the third row.</param>
/// <param name="m21">Second item of the third row.</param>
/// <param name="m22">Third item of the third row.</param>
/// <param name="m23">First item of the third row.</param>
/// <param name="m30">Fourth item of the fourth row.</param>
/// <param name="m31">Second item of the fourth row.</param>
/// <param name="m32">Third item of the fourth row.</param>
/// <param name="m33">Fourth item of the fourth row.</param>
public Matrix4d (
2009-09-04 13:02:23 +00:00
double m00 , double m01 , double m02 , double m03 ,
double m10 , double m11 , double m12 , double m13 ,
double m20 , double m21 , double m22 , double m23 ,
double m30 , double m31 , double m32 , double m33 )
2009-04-12 16:34:35 +00:00
{
Row0 = new Vector4d ( m00 , m01 , m02 , m03 ) ;
Row1 = new Vector4d ( m10 , m11 , m12 , m13 ) ;
Row2 = new Vector4d ( m20 , m21 , m22 , m23 ) ;
Row3 = new Vector4d ( m30 , m31 , m32 , m33 ) ;
}
2014-09-11 16:33:34 +00:00
/// <summary>
/// Constructs a new instance.
/// </summary>
/// <param name="topLeft">The top left 3x3 of the matrix.</param>
public Matrix4d ( Matrix3d topLeft )
{
Row0 . X = topLeft . Row0 . X ;
Row0 . Y = topLeft . Row0 . Y ;
Row0 . Z = topLeft . Row0 . Z ;
Row0 . W = 0 ;
Row1 . X = topLeft . Row1 . X ;
Row1 . Y = topLeft . Row1 . Y ;
Row1 . Z = topLeft . Row1 . Z ;
Row1 . W = 0 ;
Row2 . X = topLeft . Row2 . X ;
Row2 . Y = topLeft . Row2 . Y ;
Row2 . Z = topLeft . Row2 . Z ;
Row2 . W = 0 ;
Row3 . X = 0 ;
Row3 . Y = 0 ;
Row3 . Z = 0 ;
Row3 . W = 1 ;
}
2009-02-22 10:43:35 +00:00
#endregion
#region Public Members
#region Properties
/// <summary>
/// The determinant of this matrix
/// </summary>
public double Determinant
{
get
{
return
Row0 . X * Row1 . Y * Row2 . Z * Row3 . W - Row0 . X * Row1 . Y * Row2 . W * Row3 . Z + Row0 . X * Row1 . Z * Row2 . W * Row3 . Y - Row0 . X * Row1 . Z * Row2 . Y * Row3 . W
+ Row0 . X * Row1 . W * Row2 . Y * Row3 . Z - Row0 . X * Row1 . W * Row2 . Z * Row3 . Y - Row0 . Y * Row1 . Z * Row2 . W * Row3 . X + Row0 . Y * Row1 . Z * Row2 . X * Row3 . W
- Row0 . Y * Row1 . W * Row2 . X * Row3 . Z + Row0 . Y * Row1 . W * Row2 . Z * Row3 . X - Row0 . Y * Row1 . X * Row2 . Z * Row3 . W + Row0 . Y * Row1 . X * Row2 . W * Row3 . Z
+ Row0 . Z * Row1 . W * Row2 . X * Row3 . Y - Row0 . Z * Row1 . W * Row2 . Y * Row3 . X + Row0 . Z * Row1 . X * Row2 . Y * Row3 . W - Row0 . Z * Row1 . X * Row2 . W * Row3 . Y
+ Row0 . Z * Row1 . Y * Row2 . W * Row3 . X - Row0 . Z * Row1 . Y * Row2 . X * Row3 . W - Row0 . W * Row1 . X * Row2 . Y * Row3 . Z + Row0 . W * Row1 . X * Row2 . Z * Row3 . Y
- Row0 . W * Row1 . Y * Row2 . Z * Row3 . X + Row0 . W * Row1 . Y * Row2 . X * Row3 . Z - Row0 . W * Row1 . Z * Row2 . X * Row3 . Y + Row0 . W * Row1 . Z * Row2 . Y * Row3 . X ;
}
}
/// <summary>
/// The first column of this matrix
/// </summary>
public Vector4d Column0
{
get { return new Vector4d ( Row0 . X , Row1 . X , Row2 . X , Row3 . X ) ; }
2013-04-11 21:23:43 +00:00
set { Row0 . X = value . X ; Row1 . X = value . Y ; Row2 . X = value . Z ; Row3 . X = value . W ; }
2009-02-22 10:43:35 +00:00
}
/// <summary>
/// The second column of this matrix
/// </summary>
public Vector4d Column1
{
get { return new Vector4d ( Row0 . Y , Row1 . Y , Row2 . Y , Row3 . Y ) ; }
2013-04-11 21:23:43 +00:00
set { Row0 . Y = value . X ; Row1 . Y = value . Y ; Row2 . Y = value . Z ; Row3 . Y = value . W ; }
2009-02-22 10:43:35 +00:00
}
/// <summary>
/// The third column of this matrix
/// </summary>
public Vector4d Column2
{
get { return new Vector4d ( Row0 . Z , Row1 . Z , Row2 . Z , Row3 . Z ) ; }
2013-04-11 21:23:43 +00:00
set { Row0 . Z = value . X ; Row1 . Z = value . Y ; Row2 . Z = value . Z ; Row3 . Z = value . W ; }
2009-02-22 10:43:35 +00:00
}
/// <summary>
/// The fourth column of this matrix
/// </summary>
public Vector4d Column3
{
get { return new Vector4d ( Row0 . W , Row1 . W , Row2 . W , Row3 . W ) ; }
2013-04-11 21:23:43 +00:00
set { Row0 . W = value . X ; Row1 . W = value . Y ; Row2 . W = value . Z ; Row3 . W = value . W ; }
2009-02-22 10:43:35 +00:00
}
2009-05-29 16:44:12 +00:00
/// <summary>
/// Gets or sets the value at row 1, column 1 of this instance.
/// </summary>
public double M11 { get { return Row0 . X ; } set { Row0 . X = value ; } }
/// <summary>
/// Gets or sets the value at row 1, column 2 of this instance.
/// </summary>
public double M12 { get { return Row0 . Y ; } set { Row0 . Y = value ; } }
/// <summary>
/// Gets or sets the value at row 1, column 3 of this instance.
/// </summary>
public double M13 { get { return Row0 . Z ; } set { Row0 . Z = value ; } }
/// <summary>
/// Gets or sets the value at row 1, column 4 of this instance.
/// </summary>
public double M14 { get { return Row0 . W ; } set { Row0 . W = value ; } }
/// <summary>
/// Gets or sets the value at row 2, column 1 of this instance.
/// </summary>
public double M21 { get { return Row1 . X ; } set { Row1 . X = value ; } }
/// <summary>
/// Gets or sets the value at row 2, column 2 of this instance.
/// </summary>
public double M22 { get { return Row1 . Y ; } set { Row1 . Y = value ; } }
/// <summary>
/// Gets or sets the value at row 2, column 3 of this instance.
/// </summary>
public double M23 { get { return Row1 . Z ; } set { Row1 . Z = value ; } }
/// <summary>
/// Gets or sets the value at row 2, column 4 of this instance.
/// </summary>
public double M24 { get { return Row1 . W ; } set { Row1 . W = value ; } }
/// <summary>
/// Gets or sets the value at row 3, column 1 of this instance.
/// </summary>
public double M31 { get { return Row2 . X ; } set { Row2 . X = value ; } }
/// <summary>
/// Gets or sets the value at row 3, column 2 of this instance.
/// </summary>
public double M32 { get { return Row2 . Y ; } set { Row2 . Y = value ; } }
/// <summary>
/// Gets or sets the value at row 3, column 3 of this instance.
/// </summary>
public double M33 { get { return Row2 . Z ; } set { Row2 . Z = value ; } }
/// <summary>
/// Gets or sets the value at row 3, column 4 of this instance.
/// </summary>
public double M34 { get { return Row2 . W ; } set { Row2 . W = value ; } }
/// <summary>
/// Gets or sets the value at row 4, column 1 of this instance.
/// </summary>
public double M41 { get { return Row3 . X ; } set { Row3 . X = value ; } }
/// <summary>
2009-10-14 18:30:12 +00:00
/// Gets or sets the value at row 4, column 2 of this instance.
2009-05-29 16:44:12 +00:00
/// </summary>
public double M42 { get { return Row3 . Y ; } set { Row3 . Y = value ; } }
/// <summary>
/// Gets or sets the value at row 4, column 3 of this instance.
/// </summary>
public double M43 { get { return Row3 . Z ; } set { Row3 . Z = value ; } }
/// <summary>
/// Gets or sets the value at row 4, column 4 of this instance.
/// </summary>
public double M44 { get { return Row3 . W ; } set { Row3 . W = value ; } }
2013-07-18 19:52:28 +00:00
/// <summary>
/// Gets or sets the values along the main diagonal of the matrix.
/// </summary>
public Vector4d Diagonal
{
get
{
return new Vector4d ( Row0 . X , Row1 . Y , Row2 . Z , Row3 . W ) ;
}
set
{
Row0 . X = value . X ;
Row1 . Y = value . Y ;
Row2 . Z = value . Z ;
Row3 . W = value . W ;
}
}
/// <summary>
/// Gets the trace of the matrix, the sum of the values along the diagonal.
/// </summary>
public double Trace { get { return Row0 . X + Row1 . Y + Row2 . Z + Row3 . W ; } }
2009-02-22 10:43:35 +00:00
#endregion
2013-01-26 21:08:34 +00:00
#region Indexers
/// <summary>
/// Gets or sets the value at a specified row and column.
/// </summary>
public double this [ int rowIndex , int columnIndex ]
{
get
{
if ( rowIndex = = 0 ) return Row0 [ columnIndex ] ;
else if ( rowIndex = = 1 ) return Row1 [ columnIndex ] ;
else if ( rowIndex = = 2 ) return Row2 [ columnIndex ] ;
else if ( rowIndex = = 3 ) return Row3 [ columnIndex ] ;
throw new IndexOutOfRangeException ( "You tried to access this matrix at: (" + rowIndex + ", " + columnIndex + ")" ) ;
}
set
{
if ( rowIndex = = 0 ) Row0 [ columnIndex ] = value ;
else if ( rowIndex = = 1 ) Row1 [ columnIndex ] = value ;
else if ( rowIndex = = 2 ) Row2 [ columnIndex ] = value ;
else if ( rowIndex = = 3 ) Row3 [ columnIndex ] = value ;
2013-09-24 14:34:39 +00:00
else throw new IndexOutOfRangeException ( "You tried to set this matrix at: (" + rowIndex + ", " + columnIndex + ")" ) ;
2013-01-26 21:08:34 +00:00
}
}
#endregion
#region Instance
#region public void Invert ( )
/// <summary>
2009-09-04 23:11:20 +00:00
/// Converts this instance into its inverse.
/// </summary>
2009-02-22 10:43:35 +00:00
public void Invert ( )
{
this = Matrix4d . Invert ( this ) ;
}
#endregion
#region public void Transpose ( )
2009-09-04 23:11:20 +00:00
/// <summary>
/// Converts this instance into its transpose.
/// </summary>
2009-02-22 10:43:35 +00:00
public void Transpose ( )
{
this = Matrix4d . Transpose ( this ) ;
}
#endregion
2013-03-20 12:44:12 +00:00
/// <summary>
/// Returns a normalised copy of this instance.
/// </summary>
public Matrix4d Normalized ( )
{
Matrix4d m = this ;
m . Normalize ( ) ;
return m ;
}
/// <summary>
/// Divides each element in the Matrix by the <see cref="Determinant"/>.
/// </summary>
public void Normalize ( )
{
var determinant = this . Determinant ;
Row0 / = determinant ;
Row1 / = determinant ;
Row2 / = determinant ;
Row3 / = determinant ;
}
/// <summary>
/// Returns an inverted copy of this instance.
/// </summary>
public Matrix4d Inverted ( )
{
Matrix4d m = this ;
if ( m . Determinant ! = 0 )
m . Invert ( ) ;
return m ;
}
2013-04-11 21:23:43 +00:00
/// <summary>
/// Returns a copy of this Matrix4d without translation.
/// </summary>
public Matrix4d ClearTranslation ( )
{
Matrix4d m = this ;
m . Row3 . Xyz = Vector3d . Zero ;
return m ;
}
/// <summary>
/// Returns a copy of this Matrix4d without scale.
/// </summary>
public Matrix4d ClearScale ( )
{
Matrix4d m = this ;
m . Row0 . Xyz = m . Row0 . Xyz . Normalized ( ) ;
m . Row1 . Xyz = m . Row1 . Xyz . Normalized ( ) ;
m . Row2 . Xyz = m . Row2 . Xyz . Normalized ( ) ;
return m ;
}
/// <summary>
/// Returns a copy of this Matrix4d without rotation.
/// </summary>
public Matrix4d ClearRotation ( )
{
Matrix4d m = this ;
m . Row0 . Xyz = new Vector3d ( m . Row0 . Xyz . Length , 0 , 0 ) ;
m . Row1 . Xyz = new Vector3d ( 0 , m . Row1 . Xyz . Length , 0 ) ;
m . Row2 . Xyz = new Vector3d ( 0 , 0 , m . Row2 . Xyz . Length ) ;
return m ;
}
/// <summary>
/// Returns a copy of this Matrix4d without projection.
/// </summary>
public Matrix4d ClearProjection ( )
{
Matrix4d m = this ;
m . Column3 = Vector4d . Zero ;
return m ;
}
2013-03-20 12:44:12 +00:00
/// <summary>
/// Returns the translation component of this instance.
/// </summary>
public Vector3d ExtractTranslation ( ) { return Row3 . Xyz ; }
/// <summary>
/// Returns the scale component of this instance.
/// </summary>
2013-04-11 21:23:43 +00:00
public Vector3d ExtractScale ( ) { return new Vector3d ( Row0 . Xyz . Length , Row1 . Xyz . Length , Row2 . Xyz . Length ) ; }
2013-03-20 12:44:12 +00:00
/// <summary>
/// Returns the rotation component of this instance. Quite slow.
/// </summary>
/// <param name="row_normalise">Whether the method should row-normalise (i.e. remove scale from) the Matrix. Pass false if you know it's already normalised.</param>
public Quaterniond ExtractRotation ( bool row_normalise = true )
{
var row0 = Row0 . Xyz ;
var row1 = Row1 . Xyz ;
var row2 = Row2 . Xyz ;
if ( row_normalise )
{
row0 = row0 . Normalized ( ) ;
row1 = row1 . Normalized ( ) ;
row2 = row2 . Normalized ( ) ;
}
// code below adapted from Blender
Quaterniond q = new Quaterniond ( ) ;
double trace = 0.25 * ( row0 [ 0 ] + row1 [ 1 ] + row2 [ 2 ] + 1.0 ) ;
if ( trace > 0 )
{
double sq = Math . Sqrt ( trace ) ;
q . W = sq ;
sq = 1.0 / ( 4.0 * sq ) ;
q . X = ( row1 [ 2 ] - row2 [ 1 ] ) * sq ;
q . Y = ( row2 [ 0 ] - row0 [ 2 ] ) * sq ;
q . Z = ( row0 [ 1 ] - row1 [ 0 ] ) * sq ;
}
else if ( row0 [ 0 ] > row1 [ 1 ] & & row0 [ 0 ] > row2 [ 2 ] )
{
double sq = 2.0 * Math . Sqrt ( 1.0 + row0 [ 0 ] - row1 [ 1 ] - row2 [ 2 ] ) ;
q . X = 0.25 * sq ;
sq = 1.0 / sq ;
q . W = ( row2 [ 1 ] - row1 [ 2 ] ) * sq ;
q . Y = ( row1 [ 0 ] + row0 [ 1 ] ) * sq ;
q . Z = ( row2 [ 0 ] + row0 [ 2 ] ) * sq ;
}
else if ( row1 [ 1 ] > row2 [ 2 ] )
{
double sq = 2.0 * Math . Sqrt ( 1.0 + row1 [ 1 ] - row0 [ 0 ] - row2 [ 2 ] ) ;
q . Y = 0.25 * sq ;
sq = 1.0 / sq ;
q . W = ( row2 [ 0 ] - row0 [ 2 ] ) * sq ;
q . X = ( row1 [ 0 ] + row0 [ 1 ] ) * sq ;
q . Z = ( row2 [ 1 ] + row1 [ 2 ] ) * sq ;
}
else
{
double sq = 2.0 * Math . Sqrt ( 1.0 + row2 [ 2 ] - row0 [ 0 ] - row1 [ 1 ] ) ;
q . Z = 0.25 * sq ;
sq = 1.0 / sq ;
q . W = ( row1 [ 0 ] - row0 [ 1 ] ) * sq ;
q . X = ( row2 [ 0 ] + row0 [ 2 ] ) * sq ;
q . Y = ( row2 [ 1 ] + row1 [ 2 ] ) * sq ;
}
q . Normalize ( ) ;
return q ;
}
2013-04-11 21:23:43 +00:00
/// <summary>
/// Returns the projection component of this instance.
/// </summary>
public Vector4d ExtractProjection ( )
{
return Column3 ;
}
2009-02-22 10:43:35 +00:00
#endregion
#region Static
2009-09-04 13:02:23 +00:00
#region CreateFromAxisAngle
/// <summary>
/// Build a rotation matrix from the specified axis/angle rotation.
/// </summary>
/// <param name="axis">The axis to rotate about.</param>
/// <param name="angle">Angle in radians to rotate counter-clockwise (looking in the direction of the given axis).</param>
/// <param name="result">A matrix instance.</param>
public static void CreateFromAxisAngle ( Vector3d axis , double angle , out Matrix4d result )
{
2014-02-04 13:03:59 +00:00
// normalize and create a local copy of the vector.
2009-09-04 13:02:23 +00:00
axis . Normalize ( ) ;
2014-02-04 13:03:59 +00:00
double axisX = axis . X , axisY = axis . Y , axisZ = axis . Z ;
2009-09-04 13:02:23 +00:00
2014-02-04 13:03:59 +00:00
// calculate angles
double cos = System . Math . Cos ( - angle ) ;
double sin = System . Math . Sin ( - angle ) ;
double t = 1.0f - cos ;
// do the conversion math once
double tXX = t * axisX * axisX ,
tXY = t * axisX * axisY ,
tXZ = t * axisX * axisZ ,
tYY = t * axisY * axisY ,
tYZ = t * axisY * axisZ ,
tZZ = t * axisZ * axisZ ;
double sinX = sin * axisX ,
sinY = sin * axisY ,
sinZ = sin * axisZ ;
result . Row0 . X = tXX + cos ;
result . Row0 . Y = tXY - sinZ ;
result . Row0 . Z = tXZ + sinY ;
result . Row0 . W = 0 ;
result . Row1 . X = tXY + sinZ ;
result . Row1 . Y = tYY + cos ;
result . Row1 . Z = tYZ - sinX ;
result . Row1 . W = 0 ;
result . Row2 . X = tXZ - sinY ;
result . Row2 . Y = tYZ + sinX ;
result . Row2 . Z = tZZ + cos ;
result . Row2 . W = 0 ;
result . Row3 = Vector4d . UnitW ;
2009-09-04 13:02:23 +00:00
}
/// <summary>
/// Build a rotation matrix from the specified axis/angle rotation.
/// </summary>
/// <param name="axis">The axis to rotate about.</param>
/// <param name="angle">Angle in radians to rotate counter-clockwise (looking in the direction of the given axis).</param>
/// <returns>A matrix instance.</returns>
public static Matrix4d CreateFromAxisAngle ( Vector3d axis , double angle )
{
Matrix4d result ;
CreateFromAxisAngle ( axis , angle , out result ) ;
return result ;
}
#endregion
#region CreateRotation [ XYZ ]
/// <summary>
/// Builds a rotation matrix for a rotation around the x-axis.
/// </summary>
/// <param name="angle">The counter-clockwise angle in radians.</param>
2013-01-24 00:28:53 +00:00
/// <param name="result">The resulting Matrix4d instance.</param>
2009-09-04 13:02:23 +00:00
public static void CreateRotationX ( double angle , out Matrix4d result )
{
double cos = System . Math . Cos ( angle ) ;
double sin = System . Math . Sin ( angle ) ;
result . Row0 = Vector4d . UnitX ;
result . Row1 = new Vector4d ( 0 , cos , sin , 0 ) ;
result . Row2 = new Vector4d ( 0 , - sin , cos , 0 ) ;
result . Row3 = Vector4d . UnitW ;
}
/// <summary>
/// Builds a rotation matrix for a rotation around the x-axis.
/// </summary>
/// <param name="angle">The counter-clockwise angle in radians.</param>
2013-01-24 00:28:53 +00:00
/// <returns>The resulting Matrix4d instance.</returns>
2009-09-04 13:02:23 +00:00
public static Matrix4d CreateRotationX ( double angle )
{
Matrix4d result ;
CreateRotationX ( angle , out result ) ;
return result ;
}
/// <summary>
/// Builds a rotation matrix for a rotation around the y-axis.
/// </summary>
/// <param name="angle">The counter-clockwise angle in radians.</param>
2013-01-24 00:28:53 +00:00
/// <param name="result">The resulting Matrix4d instance.</param>
2009-09-04 13:02:23 +00:00
public static void CreateRotationY ( double angle , out Matrix4d result )
{
double cos = System . Math . Cos ( angle ) ;
double sin = System . Math . Sin ( angle ) ;
result . Row0 = new Vector4d ( cos , 0 , - sin , 0 ) ;
result . Row1 = Vector4d . UnitY ;
result . Row2 = new Vector4d ( sin , 0 , cos , 0 ) ;
result . Row3 = Vector4d . UnitW ;
}
/// <summary>
/// Builds a rotation matrix for a rotation around the y-axis.
/// </summary>
/// <param name="angle">The counter-clockwise angle in radians.</param>
2013-01-24 00:28:53 +00:00
/// <returns>The resulting Matrix4d instance.</returns>
2009-09-04 13:02:23 +00:00
public static Matrix4d CreateRotationY ( double angle )
{
Matrix4d result ;
CreateRotationY ( angle , out result ) ;
return result ;
}
/// <summary>
/// Builds a rotation matrix for a rotation around the z-axis.
/// </summary>
/// <param name="angle">The counter-clockwise angle in radians.</param>
2013-01-24 00:28:53 +00:00
/// <param name="result">The resulting Matrix4d instance.</param>
2009-09-04 13:02:23 +00:00
public static void CreateRotationZ ( double angle , out Matrix4d result )
{
double cos = System . Math . Cos ( angle ) ;
double sin = System . Math . Sin ( angle ) ;
result . Row0 = new Vector4d ( cos , sin , 0 , 0 ) ;
result . Row1 = new Vector4d ( - sin , cos , 0 , 0 ) ;
result . Row2 = Vector4d . UnitZ ;
result . Row3 = Vector4d . UnitW ;
}
/// <summary>
/// Builds a rotation matrix for a rotation around the z-axis.
/// </summary>
/// <param name="angle">The counter-clockwise angle in radians.</param>
2013-01-24 00:28:53 +00:00
/// <returns>The resulting Matrix4d instance.</returns>
2009-09-04 13:02:23 +00:00
public static Matrix4d CreateRotationZ ( double angle )
{
Matrix4d result ;
CreateRotationZ ( angle , out result ) ;
return result ;
}
#endregion
2009-05-29 16:44:12 +00:00
#region CreateTranslation
2009-02-22 10:43:35 +00:00
/// <summary>
2009-05-29 16:44:12 +00:00
/// Creates a translation matrix.
2009-02-22 10:43:35 +00:00
/// </summary>
2009-05-29 16:44:12 +00:00
/// <param name="x">X translation.</param>
/// <param name="y">Y translation.</param>
/// <param name="z">Z translation.</param>
/// <param name="result">The resulting Matrix4d instance.</param>
public static void CreateTranslation ( double x , double y , double z , out Matrix4d result )
2009-02-22 10:43:35 +00:00
{
2009-05-29 16:44:12 +00:00
result = Identity ;
result . Row3 = new Vector4d ( x , y , z , 1 ) ;
2009-02-22 10:43:35 +00:00
}
/// <summary>
2009-05-29 16:44:12 +00:00
/// Creates a translation matrix.
2009-02-22 10:43:35 +00:00
/// </summary>
2009-05-29 16:44:12 +00:00
/// <param name="vector">The translation vector.</param>
/// <param name="result">The resulting Matrix4d instance.</param>
public static void CreateTranslation ( ref Vector3d vector , out Matrix4d result )
2009-02-22 10:43:35 +00:00
{
2009-05-29 16:44:12 +00:00
result = Identity ;
result . Row3 = new Vector4d ( vector . X , vector . Y , vector . Z , 1 ) ;
2009-02-22 10:43:35 +00:00
}
/// <summary>
2009-05-29 16:44:12 +00:00
/// Creates a translation matrix.
2009-02-22 10:43:35 +00:00
/// </summary>
2009-05-29 16:44:12 +00:00
/// <param name="x">X translation.</param>
/// <param name="y">Y translation.</param>
/// <param name="z">Z translation.</param>
/// <returns>The resulting Matrix4d instance.</returns>
public static Matrix4d CreateTranslation ( double x , double y , double z )
2009-02-22 10:43:35 +00:00
{
Matrix4d result ;
2009-05-29 16:44:12 +00:00
CreateTranslation ( x , y , z , out result ) ;
return result ;
}
/// <summary>
/// Creates a translation matrix.
/// </summary>
/// <param name="vector">The translation vector.</param>
/// <returns>The resulting Matrix4d instance.</returns>
public static Matrix4d CreateTranslation ( Vector3d vector )
{
Matrix4d result ;
CreateTranslation ( vector . X , vector . Y , vector . Z , out result ) ;
2009-02-22 10:43:35 +00:00
return result ;
}
#endregion
2009-05-29 16:44:12 +00:00
#region CreateOrthographic
/// <summary>
/// Creates an orthographic projection matrix.
/// </summary>
/// <param name="width">The width of the projection volume.</param>
/// <param name="height">The height of the projection volume.</param>
/// <param name="zNear">The near edge of the projection volume.</param>
/// <param name="zFar">The far edge of the projection volume.</param>
/// <param name="result">The resulting Matrix4d instance.</param>
public static void CreateOrthographic ( double width , double height , double zNear , double zFar , out Matrix4d result )
{
CreateOrthographicOffCenter ( - width / 2 , width / 2 , - height / 2 , height / 2 , zNear , zFar , out result ) ;
}
/// <summary>
/// Creates an orthographic projection matrix.
/// </summary>
/// <param name="width">The width of the projection volume.</param>
/// <param name="height">The height of the projection volume.</param>
/// <param name="zNear">The near edge of the projection volume.</param>
/// <param name="zFar">The far edge of the projection volume.</param>
/// <rereturns>The resulting Matrix4d instance.</rereturns>
public static Matrix4d CreateOrthographic ( double width , double height , double zNear , double zFar )
{
Matrix4d result ;
CreateOrthographicOffCenter ( - width / 2 , width / 2 , - height / 2 , height / 2 , zNear , zFar , out result ) ;
return result ;
}
#endregion
#region CreateOrthographicOffCenter
/// <summary>
/// Creates an orthographic projection matrix.
/// </summary>
/// <param name="left">The left edge of the projection volume.</param>
/// <param name="right">The right edge of the projection volume.</param>
/// <param name="bottom">The bottom edge of the projection volume.</param>
/// <param name="top">The top edge of the projection volume.</param>
/// <param name="zNear">The near edge of the projection volume.</param>
/// <param name="zFar">The far edge of the projection volume.</param>
/// <param name="result">The resulting Matrix4d instance.</param>
public static void CreateOrthographicOffCenter ( double left , double right , double bottom , double top , double zNear , double zFar , out Matrix4d result )
{
result = new Matrix4d ( ) ;
double invRL = 1 / ( right - left ) ;
double invTB = 1 / ( top - bottom ) ;
double invFN = 1 / ( zFar - zNear ) ;
result . M11 = 2 * invRL ;
result . M22 = 2 * invTB ;
result . M33 = - 2 * invFN ;
result . M41 = - ( right + left ) * invRL ;
result . M42 = - ( top + bottom ) * invTB ;
result . M43 = - ( zFar + zNear ) * invFN ;
2009-11-02 13:25:41 +00:00
result . M44 = 1 ;
2009-05-29 16:44:12 +00:00
}
/// <summary>
/// Creates an orthographic projection matrix.
/// </summary>
/// <param name="left">The left edge of the projection volume.</param>
/// <param name="right">The right edge of the projection volume.</param>
/// <param name="bottom">The bottom edge of the projection volume.</param>
/// <param name="top">The top edge of the projection volume.</param>
/// <param name="zNear">The near edge of the projection volume.</param>
/// <param name="zFar">The far edge of the projection volume.</param>
/// <returns>The resulting Matrix4d instance.</returns>
public static Matrix4d CreateOrthographicOffCenter ( double left , double right , double bottom , double top , double zNear , double zFar )
{
Matrix4d result ;
CreateOrthographicOffCenter ( left , right , bottom , top , zNear , zFar , out result ) ;
return result ;
}
#endregion
2009-10-13 21:33:59 +00:00
#region CreatePerspectiveFieldOfView
/// <summary>
/// Creates a perspective projection matrix.
/// </summary>
/// <param name="fovy">Angle of the field of view in the y direction (in radians)</param>
/// <param name="aspect">Aspect ratio of the view (width / height)</param>
/// <param name="zNear">Distance to the near clip plane</param>
/// <param name="zFar">Distance to the far clip plane</param>
/// <param name="result">A projection matrix that transforms camera space to raster space</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown under the following conditions:
/// <list type="bullet">
/// <item>fovy is zero, less than zero or larger than Math.PI</item>
/// <item>aspect is negative or zero</item>
/// <item>zNear is negative or zero</item>
/// <item>zFar is negative or zero</item>
/// <item>zNear is larger than zFar</item>
/// </list>
/// </exception>
public static void CreatePerspectiveFieldOfView ( double fovy , double aspect , double zNear , double zFar , out Matrix4d result )
{
if ( fovy < = 0 | | fovy > Math . PI )
throw new ArgumentOutOfRangeException ( "fovy" ) ;
if ( aspect < = 0 )
throw new ArgumentOutOfRangeException ( "aspect" ) ;
if ( zNear < = 0 )
throw new ArgumentOutOfRangeException ( "zNear" ) ;
if ( zFar < = 0 )
throw new ArgumentOutOfRangeException ( "zFar" ) ;
double yMax = zNear * System . Math . Tan ( 0.5 * fovy ) ;
double yMin = - yMax ;
double xMin = yMin * aspect ;
double xMax = yMax * aspect ;
CreatePerspectiveOffCenter ( xMin , xMax , yMin , yMax , zNear , zFar , out result ) ;
}
/// <summary>
/// Creates a perspective projection matrix.
/// </summary>
/// <param name="fovy">Angle of the field of view in the y direction (in radians)</param>
/// <param name="aspect">Aspect ratio of the view (width / height)</param>
/// <param name="zNear">Distance to the near clip plane</param>
/// <param name="zFar">Distance to the far clip plane</param>
/// <returns>A projection matrix that transforms camera space to raster space</returns>
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown under the following conditions:
/// <list type="bullet">
/// <item>fovy is zero, less than zero or larger than Math.PI</item>
/// <item>aspect is negative or zero</item>
/// <item>zNear is negative or zero</item>
/// <item>zFar is negative or zero</item>
/// <item>zNear is larger than zFar</item>
/// </list>
/// </exception>
public static Matrix4d CreatePerspectiveFieldOfView ( double fovy , double aspect , double zNear , double zFar )
{
Matrix4d result ;
CreatePerspectiveFieldOfView ( fovy , aspect , zNear , zFar , out result ) ;
return result ;
}
#endregion
#region CreatePerspectiveOffCenter
/// <summary>
/// Creates an perspective projection matrix.
/// </summary>
/// <param name="left">Left edge of the view frustum</param>
/// <param name="right">Right edge of the view frustum</param>
/// <param name="bottom">Bottom edge of the view frustum</param>
/// <param name="top">Top edge of the view frustum</param>
/// <param name="zNear">Distance to the near clip plane</param>
/// <param name="zFar">Distance to the far clip plane</param>
/// <param name="result">A projection matrix that transforms camera space to raster space</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown under the following conditions:
/// <list type="bullet">
/// <item>zNear is negative or zero</item>
/// <item>zFar is negative or zero</item>
/// <item>zNear is larger than zFar</item>
/// </list>
/// </exception>
public static void CreatePerspectiveOffCenter ( double left , double right , double bottom , double top , double zNear , double zFar , out Matrix4d result )
{
if ( zNear < = 0 )
throw new ArgumentOutOfRangeException ( "zNear" ) ;
if ( zFar < = 0 )
throw new ArgumentOutOfRangeException ( "zFar" ) ;
if ( zNear > = zFar )
throw new ArgumentOutOfRangeException ( "zNear" ) ;
double x = ( 2.0 * zNear ) / ( right - left ) ;
double y = ( 2.0 * zNear ) / ( top - bottom ) ;
double a = ( right + left ) / ( right - left ) ;
double b = ( top + bottom ) / ( top - bottom ) ;
double c = - ( zFar + zNear ) / ( zFar - zNear ) ;
double d = - ( 2.0 * zFar * zNear ) / ( zFar - zNear ) ;
result = new Matrix4d ( x , 0 , 0 , 0 ,
0 , y , 0 , 0 ,
a , b , c , - 1 ,
0 , 0 , d , 0 ) ;
}
/// <summary>
/// Creates an perspective projection matrix.
/// </summary>
/// <param name="left">Left edge of the view frustum</param>
/// <param name="right">Right edge of the view frustum</param>
/// <param name="bottom">Bottom edge of the view frustum</param>
/// <param name="top">Top edge of the view frustum</param>
/// <param name="zNear">Distance to the near clip plane</param>
/// <param name="zFar">Distance to the far clip plane</param>
/// <returns>A projection matrix that transforms camera space to raster space</returns>
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown under the following conditions:
/// <list type="bullet">
/// <item>zNear is negative or zero</item>
/// <item>zFar is negative or zero</item>
/// <item>zNear is larger than zFar</item>
/// </list>
/// </exception>
public static Matrix4d CreatePerspectiveOffCenter ( double left , double right , double bottom , double top , double zNear , double zFar )
{
Matrix4d result ;
CreatePerspectiveOffCenter ( left , right , bottom , top , zNear , zFar , out result ) ;
return result ;
}
#endregion
2013-01-03 16:19:06 +00:00
#region CreateFromQuaternion
2014-02-03 10:11:36 +00:00
/// <summary>
/// Build a rotation matrix from the specified quaternion.
/// </summary>
/// <param name="q">Quaternion to translate.</param>
/// <param name="result">Matrix result.</param>
public static void CreateFromQuaternion ( ref Quaterniond q , out Matrix4d result )
{
Vector3d axis ;
double angle ;
q . ToAxisAngle ( out axis , out angle ) ;
CreateFromAxisAngle ( axis , angle , out result ) ;
}
/// <summary>
/// Builds a rotation matrix from a quaternion.
/// </summary>
/// <param name="q">The quaternion to rotate by.</param>
/// <returns>A matrix instance.</returns>
public static Matrix4d CreateFromQuaternion ( Quaterniond q )
{
Matrix4d result ;
CreateFromQuaternion ( ref q , out result ) ;
return result ;
}
2013-01-03 16:19:06 +00:00
/// <summary>
/// Build a rotation matrix from the specified quaternion.
/// </summary>
/// <param name="q">Quaternion to translate.</param>
/// <param name="m">Matrix result.</param>
2014-02-03 10:11:36 +00:00
[Obsolete("Use double-precision overload instead")]
2013-01-03 16:19:06 +00:00
public static void CreateFromQuaternion ( ref Quaternion q , ref Matrix4 m )
{
m = Matrix4 . Identity ;
float X = q . X ;
float Y = q . Y ;
float Z = q . Z ;
float W = q . W ;
float xx = X * X ;
float xy = X * Y ;
float xz = X * Z ;
float xw = X * W ;
float yy = Y * Y ;
float yz = Y * Z ;
float yw = Y * W ;
float zz = Z * Z ;
float zw = Z * W ;
m . M11 = 1 - 2 * ( yy + zz ) ;
m . M21 = 2 * ( xy - zw ) ;
m . M31 = 2 * ( xz + yw ) ;
m . M12 = 2 * ( xy + zw ) ;
m . M22 = 1 - 2 * ( xx + zz ) ;
m . M32 = 2 * ( yz - xw ) ;
m . M13 = 2 * ( xz - yw ) ;
m . M23 = 2 * ( yz + xw ) ;
m . M33 = 1 - 2 * ( xx + yy ) ;
}
/// <summary>
/// Build a rotation matrix from the specified quaternion.
/// </summary>
/// <param name="q">Quaternion to translate.</param>
/// <returns>A matrix instance.</returns>
2014-02-03 10:11:36 +00:00
[Obsolete("Use double-precision overload instead")]
2013-01-03 16:19:06 +00:00
public static Matrix4 CreateFromQuaternion ( ref Quaternion q )
{
Matrix4 result = Matrix4 . Identity ;
float X = q . X ;
float Y = q . Y ;
float Z = q . Z ;
float W = q . W ;
float xx = X * X ;
float xy = X * Y ;
float xz = X * Z ;
float xw = X * W ;
float yy = Y * Y ;
float yz = Y * Z ;
float yw = Y * W ;
float zz = Z * Z ;
float zw = Z * W ;
result . M11 = 1 - 2 * ( yy + zz ) ;
result . M21 = 2 * ( xy - zw ) ;
result . M31 = 2 * ( xz + yw ) ;
result . M12 = 2 * ( xy + zw ) ;
result . M22 = 1 - 2 * ( xx + zz ) ;
result . M32 = 2 * ( yz - xw ) ;
result . M13 = 2 * ( xz - yw ) ;
result . M23 = 2 * ( yz + xw ) ;
result . M33 = 1 - 2 * ( xx + yy ) ;
return result ;
}
#endregion
2009-05-29 16:44:12 +00:00
#region Obsolete Functions
2009-02-22 10:43:35 +00:00
#region Translation Functions
/// <summary>
/// Build a translation matrix with the given translation
/// </summary>
/// <param name="trans">The vector to translate along</param>
/// <returns>A Translation matrix</returns>
2009-05-29 16:44:12 +00:00
[Obsolete("Use CreateTranslation instead.")]
2009-02-22 10:43:35 +00:00
public static Matrix4d Translation ( Vector3d trans )
{
return Translation ( trans . X , trans . Y , trans . Z ) ;
}
/// <summary>
/// Build a translation matrix with the given translation
/// </summary>
/// <param name="x">X translation</param>
/// <param name="y">Y translation</param>
/// <param name="z">Z translation</param>
/// <returns>A Translation matrix</returns>
2009-05-29 16:44:12 +00:00
[Obsolete("Use CreateTranslation instead.")]
2009-02-22 10:43:35 +00:00
public static Matrix4d Translation ( double x , double y , double z )
{
Matrix4d result = Identity ;
2009-10-13 21:33:59 +00:00
result . Row3 = new Vector4d ( x , y , z , 1.0 ) ;
2009-05-29 16:44:12 +00:00
return result ;
}
#endregion
#endregion
#region Scale Functions
/// <summary>
/// Build a scaling matrix
/// </summary>
/// <param name="scale">Single scale factor for x,y and z axes</param>
/// <returns>A scaling matrix</returns>
public static Matrix4d Scale ( double scale )
{
return Scale ( scale , scale , scale ) ;
}
/// <summary>
/// Build a scaling matrix
/// </summary>
/// <param name="scale">Scale factors for x,y and z axes</param>
/// <returns>A scaling matrix</returns>
public static Matrix4d Scale ( Vector3d scale )
{
return Scale ( scale . X , scale . Y , scale . Z ) ;
}
/// <summary>
/// Build a scaling matrix
/// </summary>
/// <param name="x">Scale factor for x-axis</param>
/// <param name="y">Scale factor for y-axis</param>
/// <param name="z">Scale factor for z-axis</param>
/// <returns>A scaling matrix</returns>
public static Matrix4d Scale ( double x , double y , double z )
{
Matrix4d result ;
result . Row0 = Vector4d . UnitX * x ;
result . Row1 = Vector4d . UnitY * y ;
result . Row2 = Vector4d . UnitZ * z ;
result . Row3 = Vector4d . UnitW ;
2009-02-22 10:43:35 +00:00
return result ;
}
#endregion
#region Rotation Functions
/// <summary>
/// Build a rotation matrix that rotates about the x-axis
/// </summary>
/// <param name="angle">angle in radians to rotate counter-clockwise around the x-axis</param>
/// <returns>A rotation matrix</returns>
public static Matrix4d RotateX ( double angle )
{
2009-10-13 21:33:59 +00:00
double cos = System . Math . Cos ( angle ) ;
double sin = System . Math . Sin ( angle ) ;
2009-02-22 10:43:35 +00:00
Matrix4d result ;
result . Row0 = Vector4d . UnitX ;
2009-10-13 21:33:59 +00:00
result . Row1 = new Vector4d ( 0.0 , cos , sin , 0.0 ) ;
result . Row2 = new Vector4d ( 0.0 , - sin , cos , 0.0 ) ;
2009-02-22 10:43:35 +00:00
result . Row3 = Vector4d . UnitW ;
return result ;
}
/// <summary>
/// Build a rotation matrix that rotates about the y-axis
/// </summary>
/// <param name="angle">angle in radians to rotate counter-clockwise around the y-axis</param>
/// <returns>A rotation matrix</returns>
public static Matrix4d RotateY ( double angle )
{
2009-10-13 21:33:59 +00:00
double cos = System . Math . Cos ( angle ) ;
double sin = System . Math . Sin ( angle ) ;
2009-02-22 10:43:35 +00:00
Matrix4d result ;
2009-10-13 21:33:59 +00:00
result . Row0 = new Vector4d ( cos , 0.0 , - sin , 0.0 ) ;
2009-02-22 10:43:35 +00:00
result . Row1 = Vector4d . UnitY ;
2009-10-13 21:33:59 +00:00
result . Row2 = new Vector4d ( sin , 0.0 , cos , 0.0 ) ;
2009-02-22 10:43:35 +00:00
result . Row3 = Vector4d . UnitW ;
return result ;
}
/// <summary>
/// Build a rotation matrix that rotates about the z-axis
/// </summary>
/// <param name="angle">angle in radians to rotate counter-clockwise around the z-axis</param>
/// <returns>A rotation matrix</returns>
public static Matrix4d RotateZ ( double angle )
{
2009-10-13 21:33:59 +00:00
double cos = System . Math . Cos ( angle ) ;
double sin = System . Math . Sin ( angle ) ;
2009-02-22 10:43:35 +00:00
Matrix4d result ;
2009-10-13 21:33:59 +00:00
result . Row0 = new Vector4d ( cos , sin , 0.0 , 0.0 ) ;
result . Row1 = new Vector4d ( - sin , cos , 0.0 , 0.0 ) ;
2009-02-22 10:43:35 +00:00
result . Row2 = Vector4d . UnitZ ;
result . Row3 = Vector4d . UnitW ;
return result ;
}
/// <summary>
/// Build a rotation matrix to rotate about the given axis
/// </summary>
/// <param name="axis">the axis to rotate about</param>
/// <param name="angle">angle in radians to rotate counter-clockwise (looking in the direction of the given axis)</param>
/// <returns>A rotation matrix</returns>
public static Matrix4d Rotate ( Vector3d axis , double angle )
{
2009-10-13 21:33:59 +00:00
double cos = System . Math . Cos ( - angle ) ;
double sin = System . Math . Sin ( - angle ) ;
double t = 1.0 - cos ;
2009-02-22 10:43:35 +00:00
axis . Normalize ( ) ;
Matrix4d result ;
2009-10-13 21:33:59 +00:00
result . Row0 = new Vector4d ( t * axis . X * axis . X + cos , t * axis . X * axis . Y - sin * axis . Z , t * axis . X * axis . Z + sin * axis . Y , 0.0 ) ;
result . Row1 = new Vector4d ( t * axis . X * axis . Y + sin * axis . Z , t * axis . Y * axis . Y + cos , t * axis . Y * axis . Z - sin * axis . X , 0.0 ) ;
result . Row2 = new Vector4d ( t * axis . X * axis . Z - sin * axis . Y , t * axis . Y * axis . Z + sin * axis . X , t * axis . Z * axis . Z + cos , 0.0 ) ;
2009-02-22 10:43:35 +00:00
result . Row3 = Vector4d . UnitW ;
return result ;
}
/// <summary>
/// Build a rotation matrix from a quaternion
/// </summary>
/// <param name="q">the quaternion</param>
/// <returns>A rotation matrix</returns>
public static Matrix4d Rotate ( Quaterniond q )
{
Vector3d axis ;
double angle ;
q . ToAxisAngle ( out axis , out angle ) ;
return Rotate ( axis , angle ) ;
}
#endregion
#region Camera Helper Functions
/// <summary>
/// Build a world space to camera space matrix
/// </summary>
/// <param name="eye">Eye (camera) position in world space</param>
/// <param name="target">Target position in world space</param>
/// <param name="up">Up vector in world space (should not be parallel to the camera direction, that is target - eye)</param>
/// <returns>A Matrix that transforms world space to camera space</returns>
public static Matrix4d LookAt ( Vector3d eye , Vector3d target , Vector3d up )
{
Vector3d z = Vector3d . Normalize ( eye - target ) ;
Vector3d x = Vector3d . Normalize ( Vector3d . Cross ( up , z ) ) ;
Vector3d y = Vector3d . Normalize ( Vector3d . Cross ( z , x ) ) ;
2009-10-13 21:33:59 +00:00
Matrix4d rot = new Matrix4d ( new Vector4d ( x . X , y . X , z . X , 0.0 ) ,
new Vector4d ( x . Y , y . Y , z . Y , 0.0 ) ,
new Vector4d ( x . Z , y . Z , z . Z , 0.0 ) ,
2009-02-22 10:43:35 +00:00
Vector4d . UnitW ) ;
2009-05-29 16:44:12 +00:00
Matrix4d trans = Matrix4d . CreateTranslation ( - eye ) ;
2009-02-22 10:43:35 +00:00
return trans * rot ;
}
2009-08-14 12:37:18 +00:00
/// <summary>
/// Build a world space to camera space matrix
/// </summary>
/// <param name="eyeX">Eye (camera) position in world space</param>
/// <param name="eyeY">Eye (camera) position in world space</param>
/// <param name="eyeZ">Eye (camera) position in world space</param>
/// <param name="targetX">Target position in world space</param>
/// <param name="targetY">Target position in world space</param>
/// <param name="targetZ">Target position in world space</param>
/// <param name="upX">Up vector in world space (should not be parallel to the camera direction, that is target - eye)</param>
/// <param name="upY">Up vector in world space (should not be parallel to the camera direction, that is target - eye)</param>
/// <param name="upZ">Up vector in world space (should not be parallel to the camera direction, that is target - eye)</param>
/// <returns>A Matrix4 that transforms world space to camera space</returns>
public static Matrix4d LookAt ( double eyeX , double eyeY , double eyeZ , double targetX , double targetY , double targetZ , double upX , double upY , double upZ )
{
return LookAt ( new Vector3d ( eyeX , eyeY , eyeZ ) , new Vector3d ( targetX , targetY , targetZ ) , new Vector3d ( upX , upY , upZ ) ) ;
}
2009-02-22 10:43:35 +00:00
/// <summary>
/// Build a projection matrix
/// </summary>
/// <param name="left">Left edge of the view frustum</param>
/// <param name="right">Right edge of the view frustum</param>
/// <param name="bottom">Bottom edge of the view frustum</param>
/// <param name="top">Top edge of the view frustum</param>
/// <param name="near">Distance to the near clip plane</param>
/// <param name="far">Distance to the far clip plane</param>
/// <returns>A projection matrix that transforms camera space to raster space</returns>
public static Matrix4d Frustum ( double left , double right , double bottom , double top , double near , double far )
{
2009-10-13 21:33:59 +00:00
double invRL = 1.0 / ( right - left ) ;
double invTB = 1.0 / ( top - bottom ) ;
double invFN = 1.0 / ( far - near ) ;
return new Matrix4d ( new Vector4d ( 2.0 * near * invRL , 0.0 , 0.0 , 0.0 ) ,
new Vector4d ( 0.0 , 2.0 * near * invTB , 0.0 , 0.0 ) ,
new Vector4d ( ( right + left ) * invRL , ( top + bottom ) * invTB , - ( far + near ) * invFN , - 1.0 ) ,
new Vector4d ( 0.0 , 0.0 , - 2.0 * far * near * invFN , 0.0 ) ) ;
2009-02-22 10:43:35 +00:00
}
/// <summary>
/// Build a projection matrix
/// </summary>
/// <param name="fovy">Angle of the field of view in the y direction (in radians)</param>
/// <param name="aspect">Aspect ratio of the view (width / height)</param>
/// <param name="near">Distance to the near clip plane</param>
/// <param name="far">Distance to the far clip plane</param>
/// <returns>A projection matrix that transforms camera space to raster space</returns>
public static Matrix4d Perspective ( double fovy , double aspect , double near , double far )
{
2009-10-13 21:33:59 +00:00
double yMax = near * System . Math . Tan ( 0.5f * fovy ) ;
2009-02-22 10:43:35 +00:00
double yMin = - yMax ;
double xMin = yMin * aspect ;
double xMax = yMax * aspect ;
return Frustum ( xMin , xMax , yMin , yMax , near , far ) ;
}
#endregion
2013-07-18 19:52:28 +00:00
#region Add Functions
/// <summary>
/// Adds two instances.
/// </summary>
/// <param name="left">The left operand of the addition.</param>
/// <param name="right">The right operand of the addition.</param>
/// <returns>A new instance that is the result of the addition.</returns>
public static Matrix4d Add ( Matrix4d left , Matrix4d right )
{
Matrix4d result ;
Add ( ref left , ref right , out result ) ;
return result ;
}
/// <summary>
/// Adds two instances.
/// </summary>
/// <param name="left">The left operand of the addition.</param>
/// <param name="right">The right operand of the addition.</param>
/// <param name="result">A new instance that is the result of the addition.</param>
public static void Add ( ref Matrix4d left , ref Matrix4d right , out Matrix4d result )
{
result . Row0 = left . Row0 + right . Row0 ;
result . Row1 = left . Row1 + right . Row1 ;
result . Row2 = left . Row2 + right . Row2 ;
result . Row3 = left . Row3 + right . Row3 ;
}
#endregion
#region Subtract Functions
/// <summary>
/// Subtracts one instance from another.
/// </summary>
/// <param name="left">The left operand of the subraction.</param>
/// <param name="right">The right operand of the subraction.</param>
/// <returns>A new instance that is the result of the subraction.</returns>
public static Matrix4d Subtract ( Matrix4d left , Matrix4d right )
{
Matrix4d result ;
Subtract ( ref left , ref right , out result ) ;
return result ;
}
/// <summary>
/// Subtracts one instance from another.
/// </summary>
/// <param name="left">The left operand of the subraction.</param>
/// <param name="right">The right operand of the subraction.</param>
/// <param name="result">A new instance that is the result of the subraction.</param>
public static void Subtract ( ref Matrix4d left , ref Matrix4d right , out Matrix4d result )
{
result . Row0 = left . Row0 - right . Row0 ;
result . Row1 = left . Row1 - right . Row1 ;
result . Row2 = left . Row2 - right . Row2 ;
result . Row3 = left . Row3 - right . Row3 ;
}
#endregion
2009-02-22 10:43:35 +00:00
#region Multiply Functions
/// <summary>
2009-06-19 13:44:33 +00:00
/// Multiplies two instances.
2009-02-22 10:43:35 +00:00
/// </summary>
2009-03-25 21:53:12 +00:00
/// <param name="left">The left operand of the multiplication.</param>
/// <param name="right">The right operand of the multiplication.</param>
/// <returns>A new instance that is the result of the multiplication</returns>
2009-02-22 10:43:35 +00:00
public static Matrix4d Mult ( Matrix4d left , Matrix4d right )
{
2009-06-19 13:44:33 +00:00
Matrix4d result ;
2009-07-17 08:27:25 +00:00
Mult ( ref left , ref right , out result ) ;
return result ;
2009-02-22 10:43:35 +00:00
}
2009-07-17 08:27:25 +00:00
/// <summary>
/// Multiplies two instances.
/// </summary>
2009-06-19 13:44:33 +00:00
/// <param name="left">The left operand of the multiplication.</param>
/// <param name="right">The right operand of the multiplication.</param>
/// <param name="result">A new instance that is the result of the multiplication</param>
2009-02-22 10:43:35 +00:00
public static void Mult ( ref Matrix4d left , ref Matrix4d right , out Matrix4d result )
{
2011-09-04 20:52:42 +00:00
double lM11 = left . Row0 . X , lM12 = left . Row0 . Y , lM13 = left . Row0 . Z , lM14 = left . Row0 . W ,
lM21 = left . Row1 . X , lM22 = left . Row1 . Y , lM23 = left . Row1 . Z , lM24 = left . Row1 . W ,
lM31 = left . Row2 . X , lM32 = left . Row2 . Y , lM33 = left . Row2 . Z , lM34 = left . Row2 . W ,
lM41 = left . Row3 . X , lM42 = left . Row3 . Y , lM43 = left . Row3 . Z , lM44 = left . Row3 . W ,
rM11 = right . Row0 . X , rM12 = right . Row0 . Y , rM13 = right . Row0 . Z , rM14 = right . Row0 . W ,
rM21 = right . Row1 . X , rM22 = right . Row1 . Y , rM23 = right . Row1 . Z , rM24 = right . Row1 . W ,
rM31 = right . Row2 . X , rM32 = right . Row2 . Y , rM33 = right . Row2 . Z , rM34 = right . Row2 . W ,
rM41 = right . Row3 . X , rM42 = right . Row3 . Y , rM43 = right . Row3 . Z , rM44 = right . Row3 . W ;
result . Row0 . X = ( ( ( lM11 * rM11 ) + ( lM12 * rM21 ) ) + ( lM13 * rM31 ) ) + ( lM14 * rM41 ) ;
result . Row0 . Y = ( ( ( lM11 * rM12 ) + ( lM12 * rM22 ) ) + ( lM13 * rM32 ) ) + ( lM14 * rM42 ) ;
result . Row0 . Z = ( ( ( lM11 * rM13 ) + ( lM12 * rM23 ) ) + ( lM13 * rM33 ) ) + ( lM14 * rM43 ) ;
result . Row0 . W = ( ( ( lM11 * rM14 ) + ( lM12 * rM24 ) ) + ( lM13 * rM34 ) ) + ( lM14 * rM44 ) ;
result . Row1 . X = ( ( ( lM21 * rM11 ) + ( lM22 * rM21 ) ) + ( lM23 * rM31 ) ) + ( lM24 * rM41 ) ;
result . Row1 . Y = ( ( ( lM21 * rM12 ) + ( lM22 * rM22 ) ) + ( lM23 * rM32 ) ) + ( lM24 * rM42 ) ;
result . Row1 . Z = ( ( ( lM21 * rM13 ) + ( lM22 * rM23 ) ) + ( lM23 * rM33 ) ) + ( lM24 * rM43 ) ;
result . Row1 . W = ( ( ( lM21 * rM14 ) + ( lM22 * rM24 ) ) + ( lM23 * rM34 ) ) + ( lM24 * rM44 ) ;
result . Row2 . X = ( ( ( lM31 * rM11 ) + ( lM32 * rM21 ) ) + ( lM33 * rM31 ) ) + ( lM34 * rM41 ) ;
result . Row2 . Y = ( ( ( lM31 * rM12 ) + ( lM32 * rM22 ) ) + ( lM33 * rM32 ) ) + ( lM34 * rM42 ) ;
result . Row2 . Z = ( ( ( lM31 * rM13 ) + ( lM32 * rM23 ) ) + ( lM33 * rM33 ) ) + ( lM34 * rM43 ) ;
result . Row2 . W = ( ( ( lM31 * rM14 ) + ( lM32 * rM24 ) ) + ( lM33 * rM34 ) ) + ( lM34 * rM44 ) ;
result . Row3 . X = ( ( ( lM41 * rM11 ) + ( lM42 * rM21 ) ) + ( lM43 * rM31 ) ) + ( lM44 * rM41 ) ;
result . Row3 . Y = ( ( ( lM41 * rM12 ) + ( lM42 * rM22 ) ) + ( lM43 * rM32 ) ) + ( lM44 * rM42 ) ;
result . Row3 . Z = ( ( ( lM41 * rM13 ) + ( lM42 * rM23 ) ) + ( lM43 * rM33 ) ) + ( lM44 * rM43 ) ;
result . Row3 . W = ( ( ( lM41 * rM14 ) + ( lM42 * rM24 ) ) + ( lM43 * rM34 ) ) + ( lM44 * rM44 ) ;
2009-02-22 10:43:35 +00:00
}
2013-07-18 19:52:28 +00:00
/// <summary>
/// Multiplies an instance by a scalar.
/// </summary>
/// <param name="left">The left operand of the multiplication.</param>
/// <param name="right">The right operand of the multiplication.</param>
/// <returns>A new instance that is the result of the multiplication</returns>
public static Matrix4d Mult ( Matrix4d left , double right )
{
Matrix4d result ;
Mult ( ref left , right , out result ) ;
return result ;
}
/// <summary>
/// Multiplies an instance by a scalar.
/// </summary>
/// <param name="left">The left operand of the multiplication.</param>
/// <param name="right">The right operand of the multiplication.</param>
/// <param name="result">A new instance that is the result of the multiplication</param>
public static void Mult ( ref Matrix4d left , double right , out Matrix4d result )
{
result . Row0 = left . Row0 * right ;
result . Row1 = left . Row1 * right ;
result . Row2 = left . Row2 * right ;
result . Row3 = left . Row3 * right ;
}
2009-02-22 10:43:35 +00:00
#endregion
#region Invert Functions
/// <summary>
/// Calculate the inverse of the given matrix
/// </summary>
/// <param name="mat">The matrix to invert</param>
/// <returns>The inverse of the given matrix if it has one, or the input if it is singular</returns>
/// <exception cref="InvalidOperationException">Thrown if the Matrix4d is singular.</exception>
public static Matrix4d Invert ( Matrix4d mat )
{
int [ ] colIdx = { 0 , 0 , 0 , 0 } ;
int [ ] rowIdx = { 0 , 0 , 0 , 0 } ;
int [ ] pivotIdx = { - 1 , - 1 , - 1 , - 1 } ;
// convert the matrix to an array for easy looping
double [ , ] inverse = { { mat . Row0 . X , mat . Row0 . Y , mat . Row0 . Z , mat . Row0 . W } ,
2009-07-17 08:27:25 +00:00
{ mat . Row1 . X , mat . Row1 . Y , mat . Row1 . Z , mat . Row1 . W } ,
{ mat . Row2 . X , mat . Row2 . Y , mat . Row2 . Z , mat . Row2 . W } ,
{ mat . Row3 . X , mat . Row3 . Y , mat . Row3 . Z , mat . Row3 . W } } ;
2009-02-22 10:43:35 +00:00
int icol = 0 ;
int irow = 0 ;
for ( int i = 0 ; i < 4 ; i + + )
{
// Find the largest pivot value
2009-10-13 21:33:59 +00:00
double maxPivot = 0.0 ;
2009-02-22 10:43:35 +00:00
for ( int j = 0 ; j < 4 ; j + + )
{
if ( pivotIdx [ j ] ! = 0 )
{
for ( int k = 0 ; k < 4 ; + + k )
{
if ( pivotIdx [ k ] = = - 1 )
{
double absVal = System . Math . Abs ( inverse [ j , k ] ) ;
if ( absVal > maxPivot )
{
maxPivot = absVal ;
irow = j ;
icol = k ;
}
}
else if ( pivotIdx [ k ] > 0 )
{
return mat ;
}
}
}
}
+ + ( pivotIdx [ icol ] ) ;
// Swap rows over so pivot is on diagonal
if ( irow ! = icol )
{
for ( int k = 0 ; k < 4 ; + + k )
{
double f = inverse [ irow , k ] ;
inverse [ irow , k ] = inverse [ icol , k ] ;
inverse [ icol , k ] = f ;
}
}
rowIdx [ i ] = irow ;
colIdx [ i ] = icol ;
double pivot = inverse [ icol , icol ] ;
// check for singular matrix
2009-10-13 21:33:59 +00:00
if ( pivot = = 0.0 )
2009-02-22 10:43:35 +00:00
{
throw new InvalidOperationException ( "Matrix is singular and cannot be inverted." ) ;
//return mat;
}
// Scale row so it has a unit diagonal
2009-10-13 21:33:59 +00:00
double oneOverPivot = 1.0 / pivot ;
inverse [ icol , icol ] = 1.0 ;
2009-02-22 10:43:35 +00:00
for ( int k = 0 ; k < 4 ; + + k )
inverse [ icol , k ] * = oneOverPivot ;
// Do elimination of non-diagonal elements
for ( int j = 0 ; j < 4 ; + + j )
{
// check this isn't on the diagonal
if ( icol ! = j )
{
double f = inverse [ j , icol ] ;
2009-10-13 21:33:59 +00:00
inverse [ j , icol ] = 0.0 ;
2009-02-22 10:43:35 +00:00
for ( int k = 0 ; k < 4 ; + + k )
inverse [ j , k ] - = inverse [ icol , k ] * f ;
}
}
}
for ( int j = 3 ; j > = 0 ; - - j )
{
int ir = rowIdx [ j ] ;
int ic = colIdx [ j ] ;
for ( int k = 0 ; k < 4 ; + + k )
{
double f = inverse [ k , ir ] ;
inverse [ k , ir ] = inverse [ k , ic ] ;
inverse [ k , ic ] = f ;
}
}
mat . Row0 = new Vector4d ( inverse [ 0 , 0 ] , inverse [ 0 , 1 ] , inverse [ 0 , 2 ] , inverse [ 0 , 3 ] ) ;
mat . Row1 = new Vector4d ( inverse [ 1 , 0 ] , inverse [ 1 , 1 ] , inverse [ 1 , 2 ] , inverse [ 1 , 3 ] ) ;
mat . Row2 = new Vector4d ( inverse [ 2 , 0 ] , inverse [ 2 , 1 ] , inverse [ 2 , 2 ] , inverse [ 2 , 3 ] ) ;
mat . Row3 = new Vector4d ( inverse [ 3 , 0 ] , inverse [ 3 , 1 ] , inverse [ 3 , 2 ] , inverse [ 3 , 3 ] ) ;
return mat ;
}
#endregion
#region Transpose
/// <summary>
/// Calculate the transpose of the given matrix
/// </summary>
/// <param name="mat">The matrix to transpose</param>
/// <returns>The transpose of the given matrix</returns>
public static Matrix4d Transpose ( Matrix4d mat )
{
return new Matrix4d ( mat . Column0 , mat . Column1 , mat . Column2 , mat . Column3 ) ;
}
/// <summary>
/// Calculate the transpose of the given matrix
/// </summary>
/// <param name="mat">The matrix to transpose</param>
2009-03-25 21:53:12 +00:00
/// <param name="result">The result of the calculation</param>
2009-02-22 10:43:35 +00:00
public static void Transpose ( ref Matrix4d mat , out Matrix4d result )
{
result . Row0 = mat . Column0 ;
result . Row1 = mat . Column1 ;
result . Row2 = mat . Column2 ;
result . Row3 = mat . Column3 ;
}
#endregion
#endregion
#region Operators
/// <summary>
/// Matrix multiplication
/// </summary>
/// <param name="left">left-hand operand</param>
/// <param name="right">right-hand operand</param>
2013-01-24 00:28:53 +00:00
/// <returns>A new Matrix4d which holds the result of the multiplication</returns>
2009-02-22 10:43:35 +00:00
public static Matrix4d operator * ( Matrix4d left , Matrix4d right )
{
return Matrix4d . Mult ( left , right ) ;
}
2013-07-18 19:52:28 +00:00
/// <summary>
/// Matrix-scalar multiplication
/// </summary>
/// <param name="left">left-hand operand</param>
/// <param name="right">right-hand operand</param>
/// <returns>A new Matrix4d which holds the result of the multiplication</returns>
public static Matrix4d operator * ( Matrix4d left , float right )
{
return Matrix4d . Mult ( left , right ) ;
}
/// <summary>
/// Matrix addition
/// </summary>
/// <param name="left">left-hand operand</param>
/// <param name="right">right-hand operand</param>
/// <returns>A new Matrix4d which holds the result of the addition</returns>
public static Matrix4d operator + ( Matrix4d left , Matrix4d right )
{
return Matrix4d . Add ( left , right ) ;
}
/// <summary>
/// Matrix subtraction
/// </summary>
/// <param name="left">left-hand operand</param>
/// <param name="right">right-hand operand</param>
/// <returns>A new Matrix4d which holds the result of the subtraction</returns>
public static Matrix4d operator - ( Matrix4d left , Matrix4d right )
{
return Matrix4d . Subtract ( left , right ) ;
}
2009-09-04 23:11:20 +00:00
/// <summary>
/// Compares two instances for equality.
/// </summary>
/// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param>
/// <returns>True, if left equals right; false otherwise.</returns>
2009-02-22 10:43:35 +00:00
public static bool operator = = ( Matrix4d left , Matrix4d right )
{
return left . Equals ( right ) ;
}
2009-09-04 23:11:20 +00:00
/// <summary>
/// Compares two instances for inequality.
/// </summary>
/// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param>
/// <returns>True, if left does not equal right; false otherwise.</returns>
2009-02-22 10:43:35 +00:00
public static bool operator ! = ( Matrix4d left , Matrix4d right )
{
return ! left . Equals ( right ) ;
}
#endregion
#region Overrides
#region public override string ToString ( )
/// <summary>
/// Returns a System.String that represents the current Matrix44.
/// </summary>
/// <returns></returns>
public override string ToString ( )
{
return String . Format ( "{0}\n{1}\n{2}\n{3}" , Row0 , Row1 , Row2 , Row3 ) ;
}
#endregion
#region public override int GetHashCode ( )
/// <summary>
/// Returns the hashcode for this instance.
/// </summary>
/// <returns>A System.Int32 containing the unique hashcode for this instance.</returns>
public override int GetHashCode ( )
{
return Row0 . GetHashCode ( ) ^ Row1 . GetHashCode ( ) ^ Row2 . GetHashCode ( ) ^ Row3 . GetHashCode ( ) ;
}
#endregion
#region public override bool Equals ( object obj )
/// <summary>
/// Indicates whether this instance and a specified object are equal.
/// </summary>
/// <param name="obj">The object to compare to.</param>
/// <returns>True if the instances are equal; false otherwise.</returns>
public override bool Equals ( object obj )
{
if ( ! ( obj is Matrix4d ) )
return false ;
return this . Equals ( ( Matrix4d ) obj ) ;
}
#endregion
#endregion
#endregion
#region IEquatable < Matrix4d > Members
/// <summary>Indicates whether the current matrix is equal to another matrix.</summary>
2013-01-24 00:28:53 +00:00
/// <param name="other">A matrix to compare with this matrix.</param>
2009-02-22 10:43:35 +00:00
/// <returns>true if the current matrix is equal to the matrix parameter; otherwise, false.</returns>
public bool Equals ( Matrix4d other )
{
return
Row0 = = other . Row0 & &
Row1 = = other . Row1 & &
Row2 = = other . Row2 & &
Row3 = = other . Row3 ;
}
#endregion
}
2008-12-02 16:02:08 +00:00
}