3483 lines
158 KiB
C#
3483 lines
158 KiB
C#
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
|
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
|
//
|
|
// -----------------------------------------------------------------------------
|
|
// Original code from SlimMath project. http://code.google.com/p/slimmath/
|
|
// Greetings to SlimDX Group. Original code published with the following license:
|
|
// -----------------------------------------------------------------------------
|
|
/*
|
|
* Copyright (c) 2007-2011 SlimDX Group
|
|
*
|
|
* 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.
|
|
*/
|
|
#pragma warning disable SA1107 // Code must not contain multiple statements on one line
|
|
#pragma warning disable SA1117 // Parameters must be on same line or separate lines
|
|
#pragma warning disable SA1313 // Parameter names must begin with lower-case letter
|
|
using System;
|
|
using System.Globalization;
|
|
using System.Runtime.InteropServices;
|
|
using System.Runtime.Serialization;
|
|
|
|
namespace math
|
|
{
|
|
/// <summary>
|
|
/// Represents a 4x4 mathematical matrix.
|
|
/// </summary>
|
|
[DataContract( Name = "float4x4")]
|
|
[DataStyle(DataStyle.Compact)]
|
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
|
public struct Matrix : IEquatable<Matrix>, IFormattable
|
|
{
|
|
/// <summary>
|
|
/// The size of the <see cref="math.Matrix"/> type, in bytes.
|
|
/// </summary>
|
|
public static readonly int SizeInBytes = lib.Util.SizeOf<Matrix>();
|
|
|
|
/// <summary>
|
|
/// A <see cref="math.Matrix"/> with all of its components set to zero.
|
|
/// </summary>
|
|
public static readonly Matrix Zero = new Matrix();
|
|
|
|
/// <summary>
|
|
/// The identity <see cref="math.Matrix"/>.
|
|
/// </summary>
|
|
public static readonly Matrix Identity = new Matrix() { M11 = 1.0f, M22 = 1.0f, M33 = 1.0f, M44 = 1.0f };
|
|
|
|
/// <summary>
|
|
/// Value at row 1 column 1 of the matrix.
|
|
/// </summary>
|
|
public float M11;
|
|
|
|
/// <summary>
|
|
/// Value at row 2 column 1 of the matrix.
|
|
/// </summary>
|
|
public float M21;
|
|
|
|
/// <summary>
|
|
/// Value at row 3 column 1 of the matrix.
|
|
/// </summary>
|
|
public float M31;
|
|
|
|
/// <summary>
|
|
/// Value at row 4 column 1 of the matrix.
|
|
/// </summary>
|
|
public float M41;
|
|
|
|
/// <summary>
|
|
/// Value at row 1 column 2 of the matrix.
|
|
/// </summary>
|
|
public float M12;
|
|
|
|
/// <summary>
|
|
/// Value at row 2 column 2 of the matrix.
|
|
/// </summary>
|
|
public float M22;
|
|
|
|
/// <summary>
|
|
/// Value at row 3 column 2 of the matrix.
|
|
/// </summary>
|
|
public float M32;
|
|
|
|
/// <summary>
|
|
/// Value at row 4 column 2 of the matrix.
|
|
/// </summary>
|
|
public float M42;
|
|
|
|
/// <summary>
|
|
/// Value at row 1 column 3 of the matrix.
|
|
/// </summary>
|
|
public float M13;
|
|
|
|
/// <summary>
|
|
/// Value at row 2 column 3 of the matrix.
|
|
/// </summary>
|
|
public float M23;
|
|
|
|
/// <summary>
|
|
/// Value at row 3 column 3 of the matrix.
|
|
/// </summary>
|
|
public float M33;
|
|
|
|
/// <summary>
|
|
/// Value at row 4 column 3 of the matrix.
|
|
/// </summary>
|
|
public float M43;
|
|
|
|
/// <summary>
|
|
/// Value at row 1 column 4 of the matrix.
|
|
/// </summary>
|
|
public float M14;
|
|
|
|
/// <summary>
|
|
/// Value at row 2 column 4 of the matrix.
|
|
/// </summary>
|
|
public float M24;
|
|
|
|
/// <summary>
|
|
/// Value at row 3 column 4 of the matrix.
|
|
/// </summary>
|
|
public float M34;
|
|
|
|
/// <summary>
|
|
/// Value at row 4 column 4 of the matrix.
|
|
/// </summary>
|
|
public float M44;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="math.Matrix"/> struct.
|
|
/// </summary>
|
|
/// <param name="value">The value that will be assigned to all components.</param>
|
|
public Matrix(float value)
|
|
{
|
|
M11 = M21 = M31 = M41 =
|
|
M12 = M22 = M32 = M42 =
|
|
M13 = M23 = M33 = M43 =
|
|
M14 = M24 = M34 = M44 = value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="math.Matrix"/> struct.
|
|
/// </summary>
|
|
/// <param name="M11">The value to assign at row 1 column 1 of the matrix.</param>
|
|
/// <param name="M12">The value to assign at row 1 column 2 of the matrix.</param>
|
|
/// <param name="M13">The value to assign at row 1 column 3 of the matrix.</param>
|
|
/// <param name="M14">The value to assign at row 1 column 4 of the matrix.</param>
|
|
/// <param name="M21">The value to assign at row 2 column 1 of the matrix.</param>
|
|
/// <param name="M22">The value to assign at row 2 column 2 of the matrix.</param>
|
|
/// <param name="M23">The value to assign at row 2 column 3 of the matrix.</param>
|
|
/// <param name="M24">The value to assign at row 2 column 4 of the matrix.</param>
|
|
/// <param name="M31">The value to assign at row 3 column 1 of the matrix.</param>
|
|
/// <param name="M32">The value to assign at row 3 column 2 of the matrix.</param>
|
|
/// <param name="M33">The value to assign at row 3 column 3 of the matrix.</param>
|
|
/// <param name="M34">The value to assign at row 3 column 4 of the matrix.</param>
|
|
/// <param name="M41">The value to assign at row 4 column 1 of the matrix.</param>
|
|
/// <param name="M42">The value to assign at row 4 column 2 of the matrix.</param>
|
|
/// <param name="M43">The value to assign at row 4 column 3 of the matrix.</param>
|
|
/// <param name="M44">The value to assign at row 4 column 4 of the matrix.</param>
|
|
public Matrix(float M11, float M12, float M13, float M14,
|
|
float M21, float M22, float M23, float M24,
|
|
float M31, float M32, float M33, float M34,
|
|
float M41, float M42, float M43, float M44)
|
|
{
|
|
this.M11 = M11; this.M12 = M12; this.M13 = M13; this.M14 = M14;
|
|
this.M21 = M21; this.M22 = M22; this.M23 = M23; this.M24 = M24;
|
|
this.M31 = M31; this.M32 = M32; this.M33 = M33; this.M34 = M34;
|
|
this.M41 = M41; this.M42 = M42; this.M43 = M43; this.M44 = M44;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="math.Matrix"/> struct.
|
|
/// </summary>
|
|
/// <param name="values">The values to assign to the components of the matrix. This must be an array with sixteen elements.</param>
|
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="values"/> is <c>null</c>.</exception>
|
|
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="values"/> contains more or less than sixteen elements.</exception>
|
|
public Matrix(float[] values)
|
|
{
|
|
if (values == null)
|
|
throw new ArgumentNullException("values");
|
|
if (values.Length != 16)
|
|
throw new ArgumentOutOfRangeException("values", "There must be sixteen and only sixteen input values for Matrix.");
|
|
|
|
M11 = values[0];
|
|
M12 = values[1];
|
|
M13 = values[2];
|
|
M14 = values[3];
|
|
|
|
M21 = values[4];
|
|
M22 = values[5];
|
|
M23 = values[6];
|
|
M24 = values[7];
|
|
|
|
M31 = values[8];
|
|
M32 = values[9];
|
|
M33 = values[10];
|
|
M34 = values[11];
|
|
|
|
M41 = values[12];
|
|
M42 = values[13];
|
|
M43 = values[14];
|
|
M44 = values[15];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the first row in the matrix; that is M11, M12, M13, and M14.
|
|
/// </summary>
|
|
[DataMemberIgnore]
|
|
public Vec4 Row1
|
|
{
|
|
get { return new Vec4(M11, M12, M13, M14); }
|
|
set { M11 = value.X; M12 = value.Y; M13 = value.Z; M14 = value.W; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the second row in the matrix; that is M21, M22, M23, and M24.
|
|
/// </summary>
|
|
[DataMemberIgnore]
|
|
public Vec4 Row2
|
|
{
|
|
get { return new Vec4(M21, M22, M23, M24); }
|
|
set { M21 = value.X; M22 = value.Y; M23 = value.Z; M24 = value.W; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the third row in the matrix; that is M31, M32, M33, and M34.
|
|
/// </summary>
|
|
[DataMemberIgnore]
|
|
public Vec4 Row3
|
|
{
|
|
get { return new Vec4(M31, M32, M33, M34); }
|
|
set { M31 = value.X; M32 = value.Y; M33 = value.Z; M34 = value.W; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the fourth row in the matrix; that is M41, M42, M43, and M44.
|
|
/// </summary>
|
|
[DataMemberIgnore]
|
|
public Vec4 Row4
|
|
{
|
|
get { return new Vec4(M41, M42, M43, M44); }
|
|
set { M41 = value.X; M42 = value.Y; M43 = value.Z; M44 = value.W; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the first column in the matrix; that is M11, M21, M31, and M41.
|
|
/// </summary>
|
|
[DataMemberIgnore]
|
|
public Vec4 Column1
|
|
{
|
|
get { return new Vec4(M11, M21, M31, M41); }
|
|
set { M11 = value.X; M21 = value.Y; M31 = value.Z; M41 = value.W; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the second column in the matrix; that is M12, M22, M32, and M42.
|
|
/// </summary>
|
|
[DataMemberIgnore]
|
|
public Vec4 Column2
|
|
{
|
|
get { return new Vec4(M12, M22, M32, M42); }
|
|
set { M12 = value.X; M22 = value.Y; M32 = value.Z; M42 = value.W; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the third column in the matrix; that is M13, M23, M33, and M43.
|
|
/// </summary>
|
|
[DataMemberIgnore]
|
|
public Vec4 Column3
|
|
{
|
|
get { return new Vec4(M13, M23, M33, M43); }
|
|
set { M13 = value.X; M23 = value.Y; M33 = value.Z; M43 = value.W; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the fourth column in the matrix; that is M14, M24, M34, and M44.
|
|
/// </summary>
|
|
[DataMemberIgnore]
|
|
public Vec4 Column4
|
|
{
|
|
get { return new Vec4(M14, M24, M34, M44); }
|
|
set { M14 = value.X; M24 = value.Y; M34 = value.Z; M44 = value.W; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the translation of the matrix; that is M41, M42, and M43.
|
|
/// </summary>
|
|
[DataMemberIgnore]
|
|
public Vec3 TranslationVector
|
|
{
|
|
get { return new Vec3(M41, M42, M43); }
|
|
set { M41 = value.X; M42 = value.Y; M43 = value.Z; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the scale of the matrix; that is M11, M22, and M33.
|
|
/// </summary>
|
|
/// <remarks>This property does not do any computation and will return a correct scale vector only if the matrix is a scale matrix.</remarks>
|
|
[DataMemberIgnore]
|
|
public Vec3 ScaleVector
|
|
{
|
|
get { return new Vec3(M11, M22, M33); }
|
|
set { M11 = value.X; M22 = value.Y; M33 = value.Z; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the up <see cref="Vec3"/> of the matrix; that is M21, M22, and M23.
|
|
/// </summary>
|
|
[DataMemberIgnore]
|
|
public Vec3 Up
|
|
{
|
|
get { return new Vec3(M21, M22, M23); }
|
|
set { M21 = value.X; M22 = value.Y; M23 = value.Z; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the down <see cref="Vec3"/> of the matrix; that is -M21, -M22, and -M23.
|
|
/// </summary>
|
|
[DataMemberIgnore]
|
|
public Vec3 Down
|
|
{
|
|
get { return new Vec3(-M21, -M22, -M23); }
|
|
set { M21 = -value.X; M22 = -value.Y; M23 = -value.Z; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the right <see cref="Vec3"/> of the matrix; that is M11, M12, and M13.
|
|
/// </summary>
|
|
[DataMemberIgnore]
|
|
public Vec3 Right
|
|
{
|
|
get { return new Vec3(M11, M12, M13); }
|
|
set { M11 = value.X; M12 = value.Y; M13 = value.Z; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the left <see cref="Vec3"/> of the matrix; that is -M11, -M12, and -M13.
|
|
/// </summary>
|
|
[DataMemberIgnore]
|
|
public Vec3 Left
|
|
{
|
|
get { return new Vec3(-M11, -M12, -M13); }
|
|
set { M11 = -value.X; M12 = -value.Y; M13 = -value.Z; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the forward <see cref="Vec3"/> of the matrix; that is -M31, -M32, and -M33.
|
|
/// </summary>
|
|
[DataMemberIgnore]
|
|
public Vec3 Forward
|
|
{
|
|
get { return new Vec3(-M31, -M32, -M33); }
|
|
set { M31 = -value.X; M32 = -value.Y; M33 = -value.Z; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the backward <see cref="Vec3"/> of the matrix; that is M31, M32, and M33.
|
|
/// </summary>
|
|
[DataMemberIgnore]
|
|
public Vec3 Backward
|
|
{
|
|
get { return new Vec3(M31, M32, M33); }
|
|
set { M31 = value.X; M32 = value.Y; M33 = value.Z; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether this instance is an identity matrix.
|
|
/// </summary>
|
|
/// <value>
|
|
/// <c>true</c> if this instance is an identity matrix; otherwise, <c>false</c>.
|
|
/// </value>
|
|
public bool IsIdentity
|
|
{
|
|
get { return this.Equals(Identity); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the component at the specified index.
|
|
/// </summary>
|
|
/// <value>The value of the matrix component, depending on the index.</value>
|
|
/// <param name="index">The zero-based index of the component to access.</param>
|
|
/// <returns>The value of the component at the specified index.</returns>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">Thrown when the <paramref name="index"/> is out of the range [0, 15].</exception>
|
|
public float this[int index]
|
|
{
|
|
get
|
|
{
|
|
switch (index)
|
|
{
|
|
case 0: return M11;
|
|
case 1: return M12;
|
|
case 2: return M13;
|
|
case 3: return M14;
|
|
case 4: return M21;
|
|
case 5: return M22;
|
|
case 6: return M23;
|
|
case 7: return M24;
|
|
case 8: return M31;
|
|
case 9: return M32;
|
|
case 10: return M33;
|
|
case 11: return M34;
|
|
case 12: return M41;
|
|
case 13: return M42;
|
|
case 14: return M43;
|
|
case 15: return M44;
|
|
}
|
|
|
|
throw new ArgumentOutOfRangeException("index", "Indices for Matrix run from 0 to 15, inclusive.");
|
|
}
|
|
|
|
set
|
|
{
|
|
switch (index)
|
|
{
|
|
case 0: M11 = value; break;
|
|
case 1: M12 = value; break;
|
|
case 2: M13 = value; break;
|
|
case 3: M14 = value; break;
|
|
case 4: M21 = value; break;
|
|
case 5: M22 = value; break;
|
|
case 6: M23 = value; break;
|
|
case 7: M24 = value; break;
|
|
case 8: M31 = value; break;
|
|
case 9: M32 = value; break;
|
|
case 10: M33 = value; break;
|
|
case 11: M34 = value; break;
|
|
case 12: M41 = value; break;
|
|
case 13: M42 = value; break;
|
|
case 14: M43 = value; break;
|
|
case 15: M44 = value; break;
|
|
default: throw new ArgumentOutOfRangeException("index", "Indices for Matrix run from 0 to 15, inclusive.");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the component at the specified index.
|
|
/// </summary>
|
|
/// <value>The value of the matrix component, depending on the index.</value>
|
|
/// <param name="row">The row of the matrix to access.</param>
|
|
/// <param name="column">The column of the matrix to access.</param>
|
|
/// <returns>The value of the component at the specified index.</returns>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">Thrown when the <paramref name="row"/> or <paramref name="column"/>is out of the range [0, 3].</exception>
|
|
public float this[int row, int column]
|
|
{
|
|
get
|
|
{
|
|
if (row < 0 || row > 3)
|
|
throw new ArgumentOutOfRangeException("row", "Rows and columns for matrices run from 0 to 3, inclusive.");
|
|
if (column < 0 || column > 3)
|
|
throw new ArgumentOutOfRangeException("column", "Rows and columns for matrices run from 0 to 3, inclusive.");
|
|
|
|
return this[(row * 4) + column];
|
|
}
|
|
|
|
set
|
|
{
|
|
if (row < 0 || row > 3)
|
|
throw new ArgumentOutOfRangeException("row", "Rows and columns for matrices run from 0 to 3, inclusive.");
|
|
if (column < 0 || column > 3)
|
|
throw new ArgumentOutOfRangeException("column", "Rows and columns for matrices run from 0 to 3, inclusive.");
|
|
|
|
this[(row * 4) + column] = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the determinant of the matrix.
|
|
/// </summary>
|
|
/// <returns>The determinant of the matrix.</returns>
|
|
public float Determinant()
|
|
{
|
|
float temp1 = (M33 * M44) - (M34 * M43);
|
|
float temp2 = (M32 * M44) - (M34 * M42);
|
|
float temp3 = (M32 * M43) - (M33 * M42);
|
|
float temp4 = (M31 * M44) - (M34 * M41);
|
|
float temp5 = (M31 * M43) - (M33 * M41);
|
|
float temp6 = (M31 * M42) - (M32 * M41);
|
|
|
|
return ((((M11 * (((M22 * temp1) - (M23 * temp2)) + (M24 * temp3))) - (M12 * (((M21 * temp1) -
|
|
(M23 * temp4)) + (M24 * temp5)))) + (M13 * (((M21 * temp2) - (M22 * temp4)) + (M24 * temp6)))) -
|
|
(M14 * (((M21 * temp3) - (M22 * temp5)) + (M23 * temp6))));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Inverts the matrix.
|
|
/// </summary>
|
|
public void Invert()
|
|
{
|
|
Invert(ref this, out this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Transposes the matrix.
|
|
/// </summary>
|
|
public void Transpose()
|
|
{
|
|
float temp;
|
|
|
|
temp = M21; M21 = M12; M12 = temp;
|
|
temp = M31; M31 = M13; M13 = temp;
|
|
temp = M41; M41 = M14; M14 = temp;
|
|
|
|
temp = M32; M32 = M23; M23 = temp;
|
|
temp = M42; M42 = M24; M24 = temp;
|
|
|
|
temp = M43; M43 = M34; M34 = temp;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Orthogonalizes the specified matrix.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Orthogonalization is the process of making all rows orthogonal to each other. This
|
|
/// means that any given row in the matrix will be orthogonal to any other given row in the
|
|
/// matrix.</para>
|
|
/// <para>Because this method uses the modified Gram-Schmidt process, the resulting matrix
|
|
/// tends to be numerically unstable. The numeric stability decreases according to the rows
|
|
/// so that the first row is the most stable and the last row is the least stable.</para>
|
|
/// <para>This operation is performed on the rows of the matrix rather than the columns.
|
|
/// If you wish for this operation to be performed on the columns, first transpose the
|
|
/// input and than transpose the output.</para>
|
|
/// </remarks>
|
|
public void Orthogonalize()
|
|
{
|
|
Orthogonalize(ref this, out this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Orthonormalizes the specified matrix.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Orthonormalization is the process of making all rows and columns orthogonal to each
|
|
/// other and making all rows and columns of unit length. This means that any given row will
|
|
/// be orthogonal to any other given row and any given column will be orthogonal to any other
|
|
/// given column. Any given row will not be orthogonal to any given column. Every row and every
|
|
/// column will be of unit length.</para>
|
|
/// <para>Because this method uses the modified Gram-Schmidt process, the resulting matrix
|
|
/// tends to be numerically unstable. The numeric stability decreases according to the rows
|
|
/// so that the first row is the most stable and the last row is the least stable.</para>
|
|
/// <para>This operation is performed on the rows of the matrix rather than the columns.
|
|
/// If you wish for this operation to be performed on the columns, first transpose the
|
|
/// input and than transpose the output.</para>
|
|
/// </remarks>
|
|
public void Orthonormalize()
|
|
{
|
|
Orthonormalize(ref this, out this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Decomposes a matrix into an orthonormalized matrix Q and a right traingular matrix R.
|
|
/// </summary>
|
|
/// <param name="Q">When the method completes, contains the orthonormalized matrix of the decomposition.</param>
|
|
/// <param name="R">When the method completes, contains the right triangular matrix of the decomposition.</param>
|
|
public void DecomposeQR(out Matrix Q, out Matrix R)
|
|
{
|
|
Matrix temp = this;
|
|
temp.Transpose();
|
|
Orthonormalize(ref temp, out Q);
|
|
Q.Transpose();
|
|
|
|
R = new Matrix();
|
|
R.M11 = Vec4.Dot(Q.Column1, Column1);
|
|
R.M12 = Vec4.Dot(Q.Column1, Column2);
|
|
R.M13 = Vec4.Dot(Q.Column1, Column3);
|
|
R.M14 = Vec4.Dot(Q.Column1, Column4);
|
|
|
|
R.M22 = Vec4.Dot(Q.Column2, Column2);
|
|
R.M23 = Vec4.Dot(Q.Column2, Column3);
|
|
R.M24 = Vec4.Dot(Q.Column2, Column4);
|
|
|
|
R.M33 = Vec4.Dot(Q.Column3, Column3);
|
|
R.M34 = Vec4.Dot(Q.Column3, Column4);
|
|
|
|
R.M44 = Vec4.Dot(Q.Column4, Column4);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Decomposes a matrix into a lower triangular matrix L and an orthonormalized matrix Q.
|
|
/// </summary>
|
|
/// <param name="L">When the method completes, contains the lower triangular matrix of the decomposition.</param>
|
|
/// <param name="Q">When the method completes, contains the orthonormalized matrix of the decomposition.</param>
|
|
public void DecomposeLQ(out Matrix L, out Matrix Q)
|
|
{
|
|
Orthonormalize(ref this, out Q);
|
|
|
|
L = new Matrix();
|
|
L.M11 = Vec4.Dot(Q.Row1, Row1);
|
|
|
|
L.M21 = Vec4.Dot(Q.Row1, Row2);
|
|
L.M22 = Vec4.Dot(Q.Row2, Row2);
|
|
|
|
L.M31 = Vec4.Dot(Q.Row1, Row3);
|
|
L.M32 = Vec4.Dot(Q.Row2, Row3);
|
|
L.M33 = Vec4.Dot(Q.Row3, Row3);
|
|
|
|
L.M41 = Vec4.Dot(Q.Row1, Row4);
|
|
L.M42 = Vec4.Dot(Q.Row2, Row4);
|
|
L.M43 = Vec4.Dot(Q.Row3, Row4);
|
|
L.M44 = Vec4.Dot(Q.Row4, Row4);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Decomposes a rotation matrix with the specified yaw, pitch, roll
|
|
/// </summary>
|
|
/// <param name="yaw">The yaw.</param>
|
|
/// <param name="pitch">The pitch.</param>
|
|
/// <param name="roll">The roll.</param>
|
|
public void Decompose(out float yaw, out float pitch, out float roll)
|
|
{
|
|
pitch = (float)Math.Asin(-M32);
|
|
// Hardcoded constant - burn him, he's a witch
|
|
// double threshold = 0.001;
|
|
double test = Math.Cos(pitch);
|
|
if (test > MathUtil.ZeroTolerance)
|
|
{
|
|
roll = (float)Math.Atan2(M12, M22);
|
|
yaw = (float)Math.Atan2(M31, M33);
|
|
}
|
|
else
|
|
{
|
|
roll = (float)Math.Atan2(-M21, M11);
|
|
yaw = 0.0f;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Decomposes a rotation matrix with the specified X, Y and Z euler angles.
|
|
/// Matrix.RotationX(rotation.X) * Matrix.RotationY(rotation.Y) * Matrix.RotationZ(rotation.Z) should represent the same rotation.
|
|
/// </summary>
|
|
/// <param name="rotation">The vector containing the 3 rotations angles to be applied in order.</param>
|
|
public void DecomposeXYZ(out Vec3 rotation)
|
|
{
|
|
rotation.Y = (float)Math.Asin(-M13);
|
|
double test = Math.Cos(rotation.Y);
|
|
if (test > 1e-6f)
|
|
{
|
|
rotation.Z = (float)Math.Atan2(M12, M11);
|
|
rotation.X = (float)Math.Atan2(M23, M33);
|
|
}
|
|
else
|
|
{
|
|
rotation.Z = (float)Math.Atan2(-M21, M31);
|
|
rotation.X = 0.0f;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Decomposes a matrix into a scale, rotation, and translation.
|
|
/// </summary>
|
|
/// <param name="scale">When the method completes, contains the scaling component of the decomposed matrix.</param>
|
|
/// <param name="translation">When the method completes, contains the translation component of the decomposed matrix.</param>
|
|
/// <returns><c>true</c> if a rotation exist for this matrix, <c>false</c> otherwise.</returns>
|
|
/// <remarks>This method is designed to decompose an SRT transformation matrix only.</remarks>
|
|
public bool Decompose(out Vec3 scale, out Vec3 translation)
|
|
{
|
|
//Source: Unknown
|
|
//References: http://www.gamedev.net/community/forums/topic.asp?topic_id=441695
|
|
|
|
//Get the translation.
|
|
translation.X = this.M41;
|
|
translation.Y = this.M42;
|
|
translation.Z = this.M43;
|
|
|
|
//Scaling is the length of the rows.
|
|
scale.X = (float)Math.Sqrt((M11 * M11) + (M12 * M12) + (M13 * M13));
|
|
scale.Y = (float)Math.Sqrt((M21 * M21) + (M22 * M22) + (M23 * M23));
|
|
scale.Z = (float)Math.Sqrt((M31 * M31) + (M32 * M32) + (M33 * M33));
|
|
|
|
//If any of the scaling factors are zero, than the rotation matrix can not exist.
|
|
if (Math.Abs(scale.X) < MathUtil.ZeroTolerance ||
|
|
Math.Abs(scale.Y) < MathUtil.ZeroTolerance ||
|
|
Math.Abs(scale.Z) < MathUtil.ZeroTolerance)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Decomposes a matrix into a scale, rotation, and translation.
|
|
/// </summary>
|
|
/// <param name="scale">When the method completes, contains the scaling component of the decomposed matrix.</param>
|
|
/// <param name="rotation">When the method completes, contains the rtoation component of the decomposed matrix.</param>
|
|
/// <param name="translation">When the method completes, contains the translation component of the decomposed matrix.</param>
|
|
/// <remarks>
|
|
/// This method is designed to decompose an SRT transformation matrix only.
|
|
/// </remarks>
|
|
public bool Decompose(out Vec3 scale, out Quaternion rotation, out Vec3 translation)
|
|
{
|
|
Matrix rotationMatrix;
|
|
Decompose(out scale, out rotationMatrix, out translation);
|
|
Quaternion.RotationMatrix(ref rotationMatrix, out rotation);
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Decomposes a matrix into a scale, rotation, and translation.
|
|
/// </summary>
|
|
/// <param name="scale">When the method completes, contains the scaling component of the decomposed matrix.</param>
|
|
/// <param name="rotation">When the method completes, contains the rtoation component of the decomposed matrix.</param>
|
|
/// <param name="translation">When the method completes, contains the translation component of the decomposed matrix.</param>
|
|
/// <remarks>
|
|
/// This method is designed to decompose an SRT transformation matrix only.
|
|
/// </remarks>
|
|
public bool Decompose(out Vec3 scale, out Matrix rotation, out Vec3 translation)
|
|
{
|
|
//Source: Unknown
|
|
//References: http://www.gamedev.net/community/forums/topic.asp?topic_id=441695
|
|
|
|
//Get the translation.
|
|
translation.X = this.M41;
|
|
translation.Y = this.M42;
|
|
translation.Z = this.M43;
|
|
|
|
//Scaling is the length of the rows.
|
|
scale.X = (float)Math.Sqrt((M11 * M11) + (M12 * M12) + (M13 * M13));
|
|
scale.Y = (float)Math.Sqrt((M21 * M21) + (M22 * M22) + (M23 * M23));
|
|
scale.Z = (float)Math.Sqrt((M31 * M31) + (M32 * M32) + (M33 * M33));
|
|
|
|
//If any of the scaling factors are zero, than the rotation matrix can not exist.
|
|
if (Math.Abs(scale.X) < MathUtil.ZeroTolerance ||
|
|
Math.Abs(scale.Y) < MathUtil.ZeroTolerance ||
|
|
Math.Abs(scale.Z) < MathUtil.ZeroTolerance)
|
|
{
|
|
rotation = Matrix.Identity;
|
|
return false;
|
|
}
|
|
|
|
// Calculate an perfect orthonormal matrix (no reflections)
|
|
var at = new Vec3(M31 / scale.Z, M32 / scale.Z, M33 / scale.Z);
|
|
var up = Vec3.Cross(at, new Vec3(M11 / scale.X, M12 / scale.X, M13 / scale.X));
|
|
var right = Vec3.Cross(up, at);
|
|
|
|
rotation = Identity;
|
|
rotation.Right = right;
|
|
rotation.Up = up;
|
|
rotation.Backward = at;
|
|
|
|
// In case of reflexions
|
|
scale.X = Vec3.Dot(right, Right) > 0.0f ? scale.X : -scale.X;
|
|
scale.Y = Vec3.Dot(up, Up) > 0.0f ? scale.Y : -scale.Y;
|
|
scale.Z = Vec3.Dot(at, Backward) > 0.0f ? scale.Z : -scale.Z;
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Exchanges two rows in the matrix.
|
|
/// </summary>
|
|
/// <param name="firstRow">The first row to exchange. This is an index of the row starting at zero.</param>
|
|
/// <param name="secondRow">The second row to exchange. This is an index of the row starting at zero.</param>
|
|
public void ExchangeRows(int firstRow, int secondRow)
|
|
{
|
|
if (firstRow < 0)
|
|
throw new ArgumentOutOfRangeException("firstRow", "The parameter firstRow must be greater than or equal to zero.");
|
|
if (firstRow > 3)
|
|
throw new ArgumentOutOfRangeException("firstRow", "The parameter firstRow must be less than or equal to three.");
|
|
if (secondRow < 0)
|
|
throw new ArgumentOutOfRangeException("secondRow", "The parameter secondRow must be greater than or equal to zero.");
|
|
if (secondRow > 3)
|
|
throw new ArgumentOutOfRangeException("secondRow", "The parameter secondRow must be less than or equal to three.");
|
|
|
|
if (firstRow == secondRow)
|
|
return;
|
|
|
|
float temp0 = this[secondRow, 0];
|
|
float temp1 = this[secondRow, 1];
|
|
float temp2 = this[secondRow, 2];
|
|
float temp3 = this[secondRow, 3];
|
|
|
|
this[secondRow, 0] = this[firstRow, 0];
|
|
this[secondRow, 1] = this[firstRow, 1];
|
|
this[secondRow, 2] = this[firstRow, 2];
|
|
this[secondRow, 3] = this[firstRow, 3];
|
|
|
|
this[firstRow, 0] = temp0;
|
|
this[firstRow, 1] = temp1;
|
|
this[firstRow, 2] = temp2;
|
|
this[firstRow, 3] = temp3;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Exchange columns.
|
|
/// </summary>
|
|
/// <param name="firstColumn">The first column to exchange.</param>
|
|
/// <param name="secondColumn">The second column to exchange.</param>
|
|
public void ExchangeColumns(int firstColumn, int secondColumn)
|
|
{
|
|
if (firstColumn < 0)
|
|
throw new ArgumentOutOfRangeException("firstColumn", "The parameter firstColumn must be greater than or equal to zero.");
|
|
if (firstColumn > 3)
|
|
throw new ArgumentOutOfRangeException("firstColumn", "The parameter firstColumn must be less than or equal to three.");
|
|
if (secondColumn < 0)
|
|
throw new ArgumentOutOfRangeException("secondColumn", "The parameter secondColumn must be greater than or equal to zero.");
|
|
if (secondColumn > 3)
|
|
throw new ArgumentOutOfRangeException("secondColumn", "The parameter secondColumn must be less than or equal to three.");
|
|
|
|
if (firstColumn == secondColumn)
|
|
return;
|
|
|
|
float temp0 = this[0, secondColumn];
|
|
float temp1 = this[1, secondColumn];
|
|
float temp2 = this[2, secondColumn];
|
|
float temp3 = this[3, secondColumn];
|
|
|
|
this[0, secondColumn] = this[0, firstColumn];
|
|
this[1, secondColumn] = this[1, firstColumn];
|
|
this[2, secondColumn] = this[2, firstColumn];
|
|
this[3, secondColumn] = this[3, firstColumn];
|
|
|
|
this[0, firstColumn] = temp0;
|
|
this[1, firstColumn] = temp1;
|
|
this[2, firstColumn] = temp2;
|
|
this[3, firstColumn] = temp3;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates an array containing the elements of the matrix.
|
|
/// </summary>
|
|
/// <returns>A sixteen-element array containing the components of the matrix.</returns>
|
|
public float[] ToArray()
|
|
{
|
|
return new[] { M11, M12, M13, M14, M21, M22, M23, M24, M31, M32, M33, M34, M41, M42, M43, M44 };
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines the sum of two matrices.
|
|
/// </summary>
|
|
/// <param name="left">The first matrix to add.</param>
|
|
/// <param name="right">The second matrix to add.</param>
|
|
/// <param name="result">When the method completes, contains the sum of the two matrices.</param>
|
|
public static void Add(ref Matrix left, ref Matrix right, out Matrix result)
|
|
{
|
|
result.M11 = left.M11 + right.M11;
|
|
result.M21 = left.M21 + right.M21;
|
|
result.M31 = left.M31 + right.M31;
|
|
result.M41 = left.M41 + right.M41;
|
|
result.M12 = left.M12 + right.M12;
|
|
result.M22 = left.M22 + right.M22;
|
|
result.M32 = left.M32 + right.M32;
|
|
result.M42 = left.M42 + right.M42;
|
|
result.M13 = left.M13 + right.M13;
|
|
result.M23 = left.M23 + right.M23;
|
|
result.M33 = left.M33 + right.M33;
|
|
result.M43 = left.M43 + right.M43;
|
|
result.M14 = left.M14 + right.M14;
|
|
result.M24 = left.M24 + right.M24;
|
|
result.M34 = left.M34 + right.M34;
|
|
result.M44 = left.M44 + right.M44;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines the sum of two matrices.
|
|
/// </summary>
|
|
/// <param name="left">The first matrix to add.</param>
|
|
/// <param name="right">The second matrix to add.</param>
|
|
/// <returns>The sum of the two matrices.</returns>
|
|
public static Matrix Add(Matrix left, Matrix right)
|
|
{
|
|
Matrix result;
|
|
Add(ref left, ref right, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines the difference between two matrices.
|
|
/// </summary>
|
|
/// <param name="left">The first matrix to subtract.</param>
|
|
/// <param name="right">The second matrix to subtract.</param>
|
|
/// <param name="result">When the method completes, contains the difference between the two matrices.</param>
|
|
public static void Subtract(ref Matrix left, ref Matrix right, out Matrix result)
|
|
{
|
|
result.M11 = left.M11 - right.M11;
|
|
result.M21 = left.M21 - right.M21;
|
|
result.M31 = left.M31 - right.M31;
|
|
result.M41 = left.M41 - right.M41;
|
|
result.M12 = left.M12 - right.M12;
|
|
result.M22 = left.M22 - right.M22;
|
|
result.M32 = left.M32 - right.M32;
|
|
result.M42 = left.M42 - right.M42;
|
|
result.M13 = left.M13 - right.M13;
|
|
result.M23 = left.M23 - right.M23;
|
|
result.M33 = left.M33 - right.M33;
|
|
result.M43 = left.M43 - right.M43;
|
|
result.M14 = left.M14 - right.M14;
|
|
result.M24 = left.M24 - right.M24;
|
|
result.M34 = left.M34 - right.M34;
|
|
result.M44 = left.M44 - right.M44;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines the difference between two matrices.
|
|
/// </summary>
|
|
/// <param name="left">The first matrix to subtract.</param>
|
|
/// <param name="right">The second matrix to subtract.</param>
|
|
/// <returns>The difference between the two matrices.</returns>
|
|
public static Matrix Subtract(Matrix left, Matrix right)
|
|
{
|
|
Matrix result;
|
|
Subtract(ref left, ref right, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scales a matrix by the given value.
|
|
/// </summary>
|
|
/// <param name="left">The matrix to scale.</param>
|
|
/// <param name="right">The amount by which to scale.</param>
|
|
/// <param name="result">When the method completes, contains the scaled matrix.</param>
|
|
public static void Multiply(ref Matrix left, float right, out Matrix result)
|
|
{
|
|
result.M11 = left.M11 * right;
|
|
result.M21 = left.M21 * right;
|
|
result.M31 = left.M31 * right;
|
|
result.M41 = left.M41 * right;
|
|
result.M12 = left.M12 * right;
|
|
result.M22 = left.M22 * right;
|
|
result.M32 = left.M32 * right;
|
|
result.M42 = left.M42 * right;
|
|
result.M13 = left.M13 * right;
|
|
result.M23 = left.M23 * right;
|
|
result.M33 = left.M33 * right;
|
|
result.M43 = left.M43 * right;
|
|
result.M14 = left.M14 * right;
|
|
result.M24 = left.M24 * right;
|
|
result.M34 = left.M34 * right;
|
|
result.M44 = left.M44 * right;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scales a matrix by the given value.
|
|
/// </summary>
|
|
/// <param name="left">The matrix to scale.</param>
|
|
/// <param name="right">The amount by which to scale.</param>
|
|
/// <returns>The scaled matrix.</returns>
|
|
public static Matrix Multiply(Matrix left, float right)
|
|
{
|
|
Matrix result;
|
|
Multiply(ref left, right, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines the product of two matrices.
|
|
/// </summary>
|
|
/// <param name="left">The first matrix to multiply.</param>
|
|
/// <param name="right">The second matrix to multiply.</param>
|
|
/// <param name="result">The product of the two matrices.</param>
|
|
public static void MultiplyTo(ref Matrix left, ref Matrix right, out Matrix result)
|
|
{
|
|
result.M11 = (left.M11 * right.M11) + (left.M12 * right.M21) + (left.M13 * right.M31) + (left.M14 * right.M41);
|
|
result.M21 = (left.M21 * right.M11) + (left.M22 * right.M21) + (left.M23 * right.M31) + (left.M24 * right.M41);
|
|
result.M31 = (left.M31 * right.M11) + (left.M32 * right.M21) + (left.M33 * right.M31) + (left.M34 * right.M41);
|
|
result.M41 = (left.M41 * right.M11) + (left.M42 * right.M21) + (left.M43 * right.M31) + (left.M44 * right.M41);
|
|
result.M12 = (left.M11 * right.M12) + (left.M12 * right.M22) + (left.M13 * right.M32) + (left.M14 * right.M42);
|
|
result.M22 = (left.M21 * right.M12) + (left.M22 * right.M22) + (left.M23 * right.M32) + (left.M24 * right.M42);
|
|
result.M32 = (left.M31 * right.M12) + (left.M32 * right.M22) + (left.M33 * right.M32) + (left.M34 * right.M42);
|
|
result.M42 = (left.M41 * right.M12) + (left.M42 * right.M22) + (left.M43 * right.M32) + (left.M44 * right.M42);
|
|
result.M13 = (left.M11 * right.M13) + (left.M12 * right.M23) + (left.M13 * right.M33) + (left.M14 * right.M43);
|
|
result.M23 = (left.M21 * right.M13) + (left.M22 * right.M23) + (left.M23 * right.M33) + (left.M24 * right.M43);
|
|
result.M33 = (left.M31 * right.M13) + (left.M32 * right.M23) + (left.M33 * right.M33) + (left.M34 * right.M43);
|
|
result.M43 = (left.M41 * right.M13) + (left.M42 * right.M23) + (left.M43 * right.M33) + (left.M44 * right.M43);
|
|
result.M14 = (left.M11 * right.M14) + (left.M12 * right.M24) + (left.M13 * right.M34) + (left.M14 * right.M44);
|
|
result.M24 = (left.M21 * right.M14) + (left.M22 * right.M24) + (left.M23 * right.M34) + (left.M24 * right.M44);
|
|
result.M34 = (left.M31 * right.M14) + (left.M32 * right.M24) + (left.M33 * right.M34) + (left.M34 * right.M44);
|
|
result.M44 = (left.M41 * right.M14) + (left.M42 * right.M24) + (left.M43 * right.M34) + (left.M44 * right.M44);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines the product of two matrices.
|
|
/// </summary>
|
|
/// <param name="left">The first matrix to multiply.</param>
|
|
/// <param name="right">The second matrix to multiply.</param>
|
|
/// <param name="result">The product of the two matrices.</param>
|
|
public static void Multiply(ref Matrix left, ref Matrix right, out Matrix result)
|
|
{
|
|
result.M11 = (left.M11 * right.M11) + (left.M12 * right.M21) + (left.M13 * right.M31) + (left.M14 * right.M41);
|
|
result.M21 = (left.M21 * right.M11) + (left.M22 * right.M21) + (left.M23 * right.M31) + (left.M24 * right.M41);
|
|
result.M31 = (left.M31 * right.M11) + (left.M32 * right.M21) + (left.M33 * right.M31) + (left.M34 * right.M41);
|
|
result.M41 = (left.M41 * right.M11) + (left.M42 * right.M21) + (left.M43 * right.M31) + (left.M44 * right.M41);
|
|
result.M12 = (left.M11 * right.M12) + (left.M12 * right.M22) + (left.M13 * right.M32) + (left.M14 * right.M42);
|
|
result.M22 = (left.M21 * right.M12) + (left.M22 * right.M22) + (left.M23 * right.M32) + (left.M24 * right.M42);
|
|
result.M32 = (left.M31 * right.M12) + (left.M32 * right.M22) + (left.M33 * right.M32) + (left.M34 * right.M42);
|
|
result.M42 = (left.M41 * right.M12) + (left.M42 * right.M22) + (left.M43 * right.M32) + (left.M44 * right.M42);
|
|
result.M13 = (left.M11 * right.M13) + (left.M12 * right.M23) + (left.M13 * right.M33) + (left.M14 * right.M43);
|
|
result.M23 = (left.M21 * right.M13) + (left.M22 * right.M23) + (left.M23 * right.M33) + (left.M24 * right.M43);
|
|
result.M33 = (left.M31 * right.M13) + (left.M32 * right.M23) + (left.M33 * right.M33) + (left.M34 * right.M43);
|
|
result.M43 = (left.M41 * right.M13) + (left.M42 * right.M23) + (left.M43 * right.M33) + (left.M44 * right.M43);
|
|
result.M14 = (left.M11 * right.M14) + (left.M12 * right.M24) + (left.M13 * right.M34) + (left.M14 * right.M44);
|
|
result.M24 = (left.M21 * right.M14) + (left.M22 * right.M24) + (left.M23 * right.M34) + (left.M24 * right.M44);
|
|
result.M34 = (left.M31 * right.M14) + (left.M32 * right.M24) + (left.M33 * right.M34) + (left.M34 * right.M44);
|
|
result.M44 = (left.M41 * right.M14) + (left.M42 * right.M24) + (left.M43 * right.M34) + (left.M44 * right.M44);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines the product of two matrices.
|
|
/// </summary>
|
|
/// <param name="left">The first matrix to multiply.</param>
|
|
/// <param name="right">The second matrix to multiply.</param>
|
|
/// <param name="result">The product of the two matrices.</param>
|
|
public static void MultiplyRef(ref Matrix left, ref Matrix right, ref Matrix result)
|
|
{
|
|
result.M11 = (left.M11 * right.M11) + (left.M12 * right.M21) + (left.M13 * right.M31) + (left.M14 * right.M41);
|
|
result.M21 = (left.M21 * right.M11) + (left.M22 * right.M21) + (left.M23 * right.M31) + (left.M24 * right.M41);
|
|
result.M31 = (left.M31 * right.M11) + (left.M32 * right.M21) + (left.M33 * right.M31) + (left.M34 * right.M41);
|
|
result.M41 = (left.M41 * right.M11) + (left.M42 * right.M21) + (left.M43 * right.M31) + (left.M44 * right.M41);
|
|
result.M12 = (left.M11 * right.M12) + (left.M12 * right.M22) + (left.M13 * right.M32) + (left.M14 * right.M42);
|
|
result.M22 = (left.M21 * right.M12) + (left.M22 * right.M22) + (left.M23 * right.M32) + (left.M24 * right.M42);
|
|
result.M32 = (left.M31 * right.M12) + (left.M32 * right.M22) + (left.M33 * right.M32) + (left.M34 * right.M42);
|
|
result.M42 = (left.M41 * right.M12) + (left.M42 * right.M22) + (left.M43 * right.M32) + (left.M44 * right.M42);
|
|
result.M13 = (left.M11 * right.M13) + (left.M12 * right.M23) + (left.M13 * right.M33) + (left.M14 * right.M43);
|
|
result.M23 = (left.M21 * right.M13) + (left.M22 * right.M23) + (left.M23 * right.M33) + (left.M24 * right.M43);
|
|
result.M33 = (left.M31 * right.M13) + (left.M32 * right.M23) + (left.M33 * right.M33) + (left.M34 * right.M43);
|
|
result.M43 = (left.M41 * right.M13) + (left.M42 * right.M23) + (left.M43 * right.M33) + (left.M44 * right.M43);
|
|
result.M14 = (left.M11 * right.M14) + (left.M12 * right.M24) + (left.M13 * right.M34) + (left.M14 * right.M44);
|
|
result.M24 = (left.M21 * right.M14) + (left.M22 * right.M24) + (left.M23 * right.M34) + (left.M24 * right.M44);
|
|
result.M34 = (left.M31 * right.M14) + (left.M32 * right.M24) + (left.M33 * right.M34) + (left.M34 * right.M44);
|
|
result.M44 = (left.M41 * right.M14) + (left.M42 * right.M24) + (left.M43 * right.M34) + (left.M44 * right.M44);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines the product of two matrices.
|
|
/// </summary>
|
|
/// <param name="left">The first matrix to multiply.</param>
|
|
/// <param name="right">The second matrix to multiply.</param>
|
|
/// <returns>The product of the two matrices.</returns>
|
|
public static Matrix Multiply(Matrix left, Matrix right)
|
|
{
|
|
Matrix result;
|
|
Multiply(ref left, ref right, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scales a matrix by the given value.
|
|
/// </summary>
|
|
/// <param name="left">The matrix to scale.</param>
|
|
/// <param name="right">The amount by which to scale.</param>
|
|
/// <param name="result">When the method completes, contains the scaled matrix.</param>
|
|
public static void Divide(ref Matrix left, float right, out Matrix result)
|
|
{
|
|
float inv = 1.0f / right;
|
|
|
|
result.M11 = left.M11 * inv;
|
|
result.M21 = left.M21 * inv;
|
|
result.M31 = left.M31 * inv;
|
|
result.M41 = left.M41 * inv;
|
|
result.M12 = left.M12 * inv;
|
|
result.M22 = left.M22 * inv;
|
|
result.M32 = left.M32 * inv;
|
|
result.M42 = left.M42 * inv;
|
|
result.M13 = left.M13 * inv;
|
|
result.M23 = left.M23 * inv;
|
|
result.M33 = left.M33 * inv;
|
|
result.M43 = left.M43 * inv;
|
|
result.M14 = left.M14 * inv;
|
|
result.M24 = left.M24 * inv;
|
|
result.M34 = left.M34 * inv;
|
|
result.M44 = left.M44 * inv;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scales a matrix by the given value.
|
|
/// </summary>
|
|
/// <param name="left">The matrix to scale.</param>
|
|
/// <param name="right">The amount by which to scale.</param>
|
|
/// <returns>The scaled matrix.</returns>
|
|
public static Matrix Divide(Matrix left, float right)
|
|
{
|
|
Matrix result;
|
|
Divide(ref left, right, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines the quotient of two matrices.
|
|
/// </summary>
|
|
/// <param name="left">The first matrix to divide.</param>
|
|
/// <param name="right">The second matrix to divide.</param>
|
|
/// <param name="result">When the method completes, contains the quotient of the two matrices.</param>
|
|
public static void Divide(ref Matrix left, ref Matrix right, out Matrix result)
|
|
{
|
|
result.M11 = left.M11 / right.M11;
|
|
result.M21 = left.M21 / right.M21;
|
|
result.M31 = left.M31 / right.M31;
|
|
result.M41 = left.M41 / right.M41;
|
|
result.M12 = left.M12 / right.M12;
|
|
result.M22 = left.M22 / right.M22;
|
|
result.M32 = left.M32 / right.M32;
|
|
result.M42 = left.M42 / right.M42;
|
|
result.M13 = left.M13 / right.M13;
|
|
result.M23 = left.M23 / right.M23;
|
|
result.M33 = left.M33 / right.M33;
|
|
result.M43 = left.M43 / right.M43;
|
|
result.M14 = left.M14 / right.M14;
|
|
result.M24 = left.M24 / right.M24;
|
|
result.M34 = left.M34 / right.M34;
|
|
result.M44 = left.M44 / right.M44;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines the quotient of two matrices.
|
|
/// </summary>
|
|
/// <param name="left">The first matrix to divide.</param>
|
|
/// <param name="right">The second matrix to divide.</param>
|
|
/// <returns>The quotient of the two matrices.</returns>
|
|
public static Matrix Divide(Matrix left, Matrix right)
|
|
{
|
|
Matrix result;
|
|
Divide(ref left, ref right, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs the exponential operation on a matrix.
|
|
/// </summary>
|
|
/// <param name="value">The matrix to perform the operation on.</param>
|
|
/// <param name="exponent">The exponent to raise the matrix to.</param>
|
|
/// <param name="result">When the method completes, contains the exponential matrix.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">Thrown when the <paramref name="exponent"/> is negative.</exception>
|
|
public static void Exponent(ref Matrix value, int exponent, out Matrix result)
|
|
{
|
|
//Source: http://rosettacode.org
|
|
//Refrence: http://rosettacode.org/wiki/Matrix-exponentiation_operator
|
|
|
|
if (exponent < 0)
|
|
throw new ArgumentOutOfRangeException("exponent", "The exponent can not be negative.");
|
|
|
|
if (exponent == 0)
|
|
{
|
|
result = Matrix.Identity;
|
|
return;
|
|
}
|
|
|
|
if (exponent == 1)
|
|
{
|
|
result = value;
|
|
return;
|
|
}
|
|
|
|
Matrix identity = Matrix.Identity;
|
|
Matrix temp = value;
|
|
|
|
while (true)
|
|
{
|
|
if ((exponent & 1) != 0)
|
|
identity = identity * temp;
|
|
|
|
exponent /= 2;
|
|
|
|
if (exponent > 0)
|
|
temp *= temp;
|
|
else
|
|
break;
|
|
}
|
|
|
|
result = identity;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs the exponential operation on a matrix.
|
|
/// </summary>
|
|
/// <param name="value">The matrix to perform the operation on.</param>
|
|
/// <param name="exponent">The exponent to raise the matrix to.</param>
|
|
/// <returns>The exponential matrix.</returns>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">Thrown when the <paramref name="exponent"/> is negative.</exception>
|
|
public static Matrix Exponent(Matrix value, int exponent)
|
|
{
|
|
Matrix result;
|
|
Exponent(ref value, exponent, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Negates a matrix.
|
|
/// </summary>
|
|
/// <param name="value">The matrix to be negated.</param>
|
|
/// <param name="result">When the method completes, contains the negated matrix.</param>
|
|
public static void Negate(ref Matrix value, out Matrix result)
|
|
{
|
|
result.M11 = -value.M11;
|
|
result.M21 = -value.M21;
|
|
result.M31 = -value.M31;
|
|
result.M41 = -value.M41;
|
|
result.M12 = -value.M12;
|
|
result.M22 = -value.M22;
|
|
result.M32 = -value.M32;
|
|
result.M42 = -value.M42;
|
|
result.M13 = -value.M13;
|
|
result.M23 = -value.M23;
|
|
result.M33 = -value.M33;
|
|
result.M43 = -value.M43;
|
|
result.M14 = -value.M14;
|
|
result.M24 = -value.M24;
|
|
result.M34 = -value.M34;
|
|
result.M44 = -value.M44;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Negates a matrix.
|
|
/// </summary>
|
|
/// <param name="value">The matrix to be negated.</param>
|
|
/// <returns>The negated matrix.</returns>
|
|
public static Matrix Negate(Matrix value)
|
|
{
|
|
Matrix result;
|
|
Negate(ref value, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs a linear interpolation between two matricies.
|
|
/// </summary>
|
|
/// <param name="start">Start matrix.</param>
|
|
/// <param name="end">End matrix.</param>
|
|
/// <param name="amount">Value between 0 and 1 indicating the weight of <paramref name="end"/>.</param>
|
|
/// <param name="result">When the method completes, contains the linear interpolation of the two matricies.</param>
|
|
/// <remarks>
|
|
/// This method performs the linear interpolation based on the following formula.
|
|
/// <code>start + (end - start) * amount</code>
|
|
/// Passing <paramref name="amount"/> a value of 0 will cause <paramref name="start"/> to be returned; a value of 1 will cause <paramref name="end"/> to be returned.
|
|
/// </remarks>
|
|
public static void Lerp(ref Matrix start, ref Matrix end, float amount, out Matrix result)
|
|
{
|
|
result.M11 = start.M11 + ((end.M11 - start.M11) * amount);
|
|
result.M21 = start.M21 + ((end.M21 - start.M21) * amount);
|
|
result.M31 = start.M31 + ((end.M31 - start.M31) * amount);
|
|
result.M41 = start.M41 + ((end.M41 - start.M41) * amount);
|
|
result.M12 = start.M12 + ((end.M12 - start.M12) * amount);
|
|
result.M22 = start.M22 + ((end.M22 - start.M22) * amount);
|
|
result.M32 = start.M32 + ((end.M32 - start.M32) * amount);
|
|
result.M42 = start.M42 + ((end.M42 - start.M42) * amount);
|
|
result.M13 = start.M13 + ((end.M13 - start.M13) * amount);
|
|
result.M23 = start.M23 + ((end.M23 - start.M23) * amount);
|
|
result.M33 = start.M33 + ((end.M33 - start.M33) * amount);
|
|
result.M43 = start.M43 + ((end.M43 - start.M43) * amount);
|
|
result.M14 = start.M14 + ((end.M14 - start.M14) * amount);
|
|
result.M24 = start.M24 + ((end.M24 - start.M24) * amount);
|
|
result.M34 = start.M34 + ((end.M34 - start.M34) * amount);
|
|
result.M44 = start.M44 + ((end.M44 - start.M44) * amount);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs a linear interpolation between two matricies.
|
|
/// </summary>
|
|
/// <param name="start">Start matrix.</param>
|
|
/// <param name="end">End matrix.</param>
|
|
/// <param name="amount">Value between 0 and 1 indicating the weight of <paramref name="end"/>.</param>
|
|
/// <returns>The linear interpolation of the two matrices.</returns>
|
|
/// <remarks>
|
|
/// This method performs the linear interpolation based on the following formula.
|
|
/// <code>start + (end - start) * amount</code>
|
|
/// Passing <paramref name="amount"/> a value of 0 will cause <paramref name="start"/> to be returned; a value of 1 will cause <paramref name="end"/> to be returned.
|
|
/// </remarks>
|
|
public static Matrix Lerp(Matrix start, Matrix end, float amount)
|
|
{
|
|
Matrix result;
|
|
Lerp(ref start, ref end, amount, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs a cubic interpolation between two matricies.
|
|
/// </summary>
|
|
/// <param name="start">Start matrix.</param>
|
|
/// <param name="end">End matrix.</param>
|
|
/// <param name="amount">Value between 0 and 1 indicating the weight of <paramref name="end"/>.</param>
|
|
/// <param name="result">When the method completes, contains the cubic interpolation of the two matrices.</param>
|
|
public static void SmoothStep(ref Matrix start, ref Matrix end, float amount, out Matrix result)
|
|
{
|
|
amount = (amount > 1.0f) ? 1.0f : ((amount < 0.0f) ? 0.0f : amount);
|
|
amount = (amount * amount) * (3.0f - (2.0f * amount));
|
|
|
|
result.M11 = start.M11 + ((end.M11 - start.M11) * amount);
|
|
result.M21 = start.M21 + ((end.M21 - start.M21) * amount);
|
|
result.M31 = start.M31 + ((end.M31 - start.M31) * amount);
|
|
result.M41 = start.M41 + ((end.M41 - start.M41) * amount);
|
|
result.M12 = start.M12 + ((end.M12 - start.M12) * amount);
|
|
result.M22 = start.M22 + ((end.M22 - start.M22) * amount);
|
|
result.M32 = start.M32 + ((end.M32 - start.M32) * amount);
|
|
result.M42 = start.M42 + ((end.M42 - start.M42) * amount);
|
|
result.M13 = start.M13 + ((end.M13 - start.M13) * amount);
|
|
result.M23 = start.M23 + ((end.M23 - start.M23) * amount);
|
|
result.M33 = start.M33 + ((end.M33 - start.M33) * amount);
|
|
result.M43 = start.M43 + ((end.M43 - start.M43) * amount);
|
|
result.M14 = start.M14 + ((end.M14 - start.M14) * amount);
|
|
result.M24 = start.M24 + ((end.M24 - start.M24) * amount);
|
|
result.M34 = start.M34 + ((end.M34 - start.M34) * amount);
|
|
result.M44 = start.M44 + ((end.M44 - start.M44) * amount);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs a cubic interpolation between two matrices.
|
|
/// </summary>
|
|
/// <param name="start">Start matrix.</param>
|
|
/// <param name="end">End matrix.</param>
|
|
/// <param name="amount">Value between 0 and 1 indicating the weight of <paramref name="end"/>.</param>
|
|
/// <returns>The cubic interpolation of the two matrices.</returns>
|
|
public static Matrix SmoothStep(Matrix start, Matrix end, float amount)
|
|
{
|
|
Matrix result;
|
|
SmoothStep(ref start, ref end, amount, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the transpose of the specified matrix.
|
|
/// </summary>
|
|
/// <param name="value">The matrix whose transpose is to be calculated.</param>
|
|
/// <param name="result">When the method completes, contains the transpose of the specified matrix.</param>
|
|
public static void Transpose(ref Matrix value, out Matrix result)
|
|
{
|
|
result = new Matrix(
|
|
value.M11,
|
|
value.M21,
|
|
value.M31,
|
|
value.M41,
|
|
value.M12,
|
|
value.M22,
|
|
value.M32,
|
|
value.M42,
|
|
value.M13,
|
|
value.M23,
|
|
value.M33,
|
|
value.M43,
|
|
value.M14,
|
|
value.M24,
|
|
value.M34,
|
|
value.M44);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the transpose of the specified matrix.
|
|
/// </summary>
|
|
/// <param name="value">The matrix whose transpose is to be calculated.</param>
|
|
/// <returns>The transpose of the specified matrix.</returns>
|
|
public static Matrix Transpose(Matrix value)
|
|
{
|
|
value.Transpose();
|
|
return value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the inverse of the specified matrix.
|
|
/// </summary>
|
|
/// <param name="value">The matrix whose inverse is to be calculated.</param>
|
|
/// <param name="result">When the method completes, contains the inverse of the specified matrix.</param>
|
|
public static void Invert(ref Matrix value, out Matrix result)
|
|
{
|
|
float b0 = (value.M31 * value.M42) - (value.M32 * value.M41);
|
|
float b1 = (value.M31 * value.M43) - (value.M33 * value.M41);
|
|
float b2 = (value.M34 * value.M41) - (value.M31 * value.M44);
|
|
float b3 = (value.M32 * value.M43) - (value.M33 * value.M42);
|
|
float b4 = (value.M34 * value.M42) - (value.M32 * value.M44);
|
|
float b5 = (value.M33 * value.M44) - (value.M34 * value.M43);
|
|
|
|
float d11 = value.M22 * b5 + value.M23 * b4 + value.M24 * b3;
|
|
float d12 = value.M21 * b5 + value.M23 * b2 + value.M24 * b1;
|
|
float d13 = value.M21 * -b4 + value.M22 * b2 + value.M24 * b0;
|
|
float d14 = value.M21 * b3 + value.M22 * -b1 + value.M23 * b0;
|
|
|
|
float det = value.M11 * d11 - value.M12 * d12 + value.M13 * d13 - value.M14 * d14;
|
|
if (Math.Abs(det) == 0.0f)
|
|
{
|
|
result = Matrix.Zero;
|
|
return;
|
|
}
|
|
|
|
det = 1f / det;
|
|
|
|
float a0 = (value.M11 * value.M22) - (value.M12 * value.M21);
|
|
float a1 = (value.M11 * value.M23) - (value.M13 * value.M21);
|
|
float a2 = (value.M14 * value.M21) - (value.M11 * value.M24);
|
|
float a3 = (value.M12 * value.M23) - (value.M13 * value.M22);
|
|
float a4 = (value.M14 * value.M22) - (value.M12 * value.M24);
|
|
float a5 = (value.M13 * value.M24) - (value.M14 * value.M23);
|
|
|
|
float d21 = value.M12 * b5 + value.M13 * b4 + value.M14 * b3;
|
|
float d22 = value.M11 * b5 + value.M13 * b2 + value.M14 * b1;
|
|
float d23 = value.M11 * -b4 + value.M12 * b2 + value.M14 * b0;
|
|
float d24 = value.M11 * b3 + value.M12 * -b1 + value.M13 * b0;
|
|
|
|
float d31 = value.M42 * a5 + value.M43 * a4 + value.M44 * a3;
|
|
float d32 = value.M41 * a5 + value.M43 * a2 + value.M44 * a1;
|
|
float d33 = value.M41 * -a4 + value.M42 * a2 + value.M44 * a0;
|
|
float d34 = value.M41 * a3 + value.M42 * -a1 + value.M43 * a0;
|
|
|
|
float d41 = value.M32 * a5 + value.M33 * a4 + value.M34 * a3;
|
|
float d42 = value.M31 * a5 + value.M33 * a2 + value.M34 * a1;
|
|
float d43 = value.M31 * -a4 + value.M32 * a2 + value.M34 * a0;
|
|
float d44 = value.M31 * a3 + value.M32 * -a1 + value.M33 * a0;
|
|
|
|
result.M11 = +d11 * det; result.M12 = -d21 * det; result.M13 = +d31 * det; result.M14 = -d41 * det;
|
|
result.M21 = -d12 * det; result.M22 = +d22 * det; result.M23 = -d32 * det; result.M24 = +d42 * det;
|
|
result.M31 = +d13 * det; result.M32 = -d23 * det; result.M33 = +d33 * det; result.M34 = -d43 * det;
|
|
result.M41 = -d14 * det; result.M42 = +d24 * det; result.M43 = -d34 * det; result.M44 = +d44 * det;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the inverse of the specified matrix.
|
|
/// </summary>
|
|
/// <param name="value">The matrix whose inverse is to be calculated.</param>
|
|
/// <returns>The inverse of the specified matrix.</returns>
|
|
public static Matrix Invert(Matrix value)
|
|
{
|
|
value.Invert();
|
|
return value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Orthogonalizes the specified matrix.
|
|
/// </summary>
|
|
/// <param name="value">The matrix to orthogonalize.</param>
|
|
/// <param name="result">When the method completes, contains the orthogonalized matrix.</param>
|
|
/// <remarks>
|
|
/// <para>Orthogonalization is the process of making all rows orthogonal to each other. This
|
|
/// means that any given row in the matrix will be orthogonal to any other given row in the
|
|
/// matrix.</para>
|
|
/// <para>Because this method uses the modified Gram-Schmidt process, the resulting matrix
|
|
/// tends to be numerically unstable. The numeric stability decreases according to the rows
|
|
/// so that the first row is the most stable and the last row is the least stable.</para>
|
|
/// <para>This operation is performed on the rows of the matrix rather than the columns.
|
|
/// If you wish for this operation to be performed on the columns, first transpose the
|
|
/// input and than transpose the output.</para>
|
|
/// </remarks>
|
|
public static void Orthogonalize(ref Matrix value, out Matrix result)
|
|
{
|
|
//Uses the modified Gram-Schmidt process.
|
|
//q1 = m1
|
|
//q2 = m2 - ((q1 ⋅ m2) / (q1 ⋅ q1)) * q1
|
|
//q3 = m3 - ((q1 ⋅ m3) / (q1 ⋅ q1)) * q1 - ((q2 ⋅ m3) / (q2 ⋅ q2)) * q2
|
|
//q4 = m4 - ((q1 ⋅ m4) / (q1 ⋅ q1)) * q1 - ((q2 ⋅ m4) / (q2 ⋅ q2)) * q2 - ((q3 ⋅ m4) / (q3 ⋅ q3)) * q3
|
|
|
|
//By separating the above algorithm into multiple lines, we actually increase accuracy.
|
|
result = value;
|
|
|
|
result.Row2 = result.Row2 - (Vec4.Dot(result.Row1, result.Row2) / Vec4.Dot(result.Row1, result.Row1)) * result.Row1;
|
|
|
|
result.Row3 = result.Row3 - (Vec4.Dot(result.Row1, result.Row3) / Vec4.Dot(result.Row1, result.Row1)) * result.Row1;
|
|
result.Row3 = result.Row3 - (Vec4.Dot(result.Row2, result.Row3) / Vec4.Dot(result.Row2, result.Row2)) * result.Row2;
|
|
|
|
result.Row4 = result.Row4 - (Vec4.Dot(result.Row1, result.Row4) / Vec4.Dot(result.Row1, result.Row1)) * result.Row1;
|
|
result.Row4 = result.Row4 - (Vec4.Dot(result.Row2, result.Row4) / Vec4.Dot(result.Row2, result.Row2)) * result.Row2;
|
|
result.Row4 = result.Row4 - (Vec4.Dot(result.Row3, result.Row4) / Vec4.Dot(result.Row3, result.Row3)) * result.Row3;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Orthogonalizes the specified matrix.
|
|
/// </summary>
|
|
/// <param name="value">The matrix to orthogonalize.</param>
|
|
/// <returns>The orthogonalized matrix.</returns>
|
|
/// <remarks>
|
|
/// <para>Orthogonalization is the process of making all rows orthogonal to each other. This
|
|
/// means that any given row in the matrix will be orthogonal to any other given row in the
|
|
/// matrix.</para>
|
|
/// <para>Because this method uses the modified Gram-Schmidt process, the resulting matrix
|
|
/// tends to be numerically unstable. The numeric stability decreases according to the rows
|
|
/// so that the first row is the most stable and the last row is the least stable.</para>
|
|
/// <para>This operation is performed on the rows of the matrix rather than the columns.
|
|
/// If you wish for this operation to be performed on the columns, first transpose the
|
|
/// input and than transpose the output.</para>
|
|
/// </remarks>
|
|
public static Matrix Orthogonalize(Matrix value)
|
|
{
|
|
Matrix result;
|
|
Orthogonalize(ref value, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Orthonormalizes the specified matrix.
|
|
/// </summary>
|
|
/// <param name="value">The matrix to orthonormalize.</param>
|
|
/// <param name="result">When the method completes, contains the orthonormalized matrix.</param>
|
|
/// <remarks>
|
|
/// <para>Orthonormalization is the process of making all rows and columns orthogonal to each
|
|
/// other and making all rows and columns of unit length. This means that any given row will
|
|
/// be orthogonal to any other given row and any given column will be orthogonal to any other
|
|
/// given column. Any given row will not be orthogonal to any given column. Every row and every
|
|
/// column will be of unit length.</para>
|
|
/// <para>Because this method uses the modified Gram-Schmidt process, the resulting matrix
|
|
/// tends to be numerically unstable. The numeric stability decreases according to the rows
|
|
/// so that the first row is the most stable and the last row is the least stable.</para>
|
|
/// <para>This operation is performed on the rows of the matrix rather than the columns.
|
|
/// If you wish for this operation to be performed on the columns, first transpose the
|
|
/// input and than transpose the output.</para>
|
|
/// </remarks>
|
|
public static void Orthonormalize(ref Matrix value, out Matrix result)
|
|
{
|
|
//Uses the modified Gram-Schmidt process.
|
|
//Because we are making unit vectors, we can optimize the math for orthogonalization
|
|
//and simplify the projection operation to remove the division.
|
|
//q1 = m1 / |m1|
|
|
//q2 = (m2 - (q1 ⋅ m2) * q1) / |m2 - (q1 ⋅ m2) * q1|
|
|
//q3 = (m3 - (q1 ⋅ m3) * q1 - (q2 ⋅ m3) * q2) / |m3 - (q1 ⋅ m3) * q1 - (q2 ⋅ m3) * q2|
|
|
//q4 = (m4 - (q1 ⋅ m4) * q1 - (q2 ⋅ m4) * q2 - (q3 ⋅ m4) * q3) / |m4 - (q1 ⋅ m4) * q1 - (q2 ⋅ m4) * q2 - (q3 ⋅ m4) * q3|
|
|
|
|
//By separating the above algorithm into multiple lines, we actually increase accuracy.
|
|
result = value;
|
|
|
|
result.Row1 = Vec4.Normalize(result.Row1);
|
|
|
|
result.Row2 = result.Row2 - Vec4.Dot(result.Row1, result.Row2) * result.Row1;
|
|
result.Row2 = Vec4.Normalize(result.Row2);
|
|
|
|
result.Row3 = result.Row3 - Vec4.Dot(result.Row1, result.Row3) * result.Row1;
|
|
result.Row3 = result.Row3 - Vec4.Dot(result.Row2, result.Row3) * result.Row2;
|
|
result.Row3 = Vec4.Normalize(result.Row3);
|
|
|
|
result.Row4 = result.Row4 - Vec4.Dot(result.Row1, result.Row4) * result.Row1;
|
|
result.Row4 = result.Row4 - Vec4.Dot(result.Row2, result.Row4) * result.Row2;
|
|
result.Row4 = result.Row4 - Vec4.Dot(result.Row3, result.Row4) * result.Row3;
|
|
result.Row4 = Vec4.Normalize(result.Row4);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Orthonormalizes the specified matrix.
|
|
/// </summary>
|
|
/// <param name="value">The matrix to orthonormalize.</param>
|
|
/// <returns>The orthonormalized matrix.</returns>
|
|
/// <remarks>
|
|
/// <para>Orthonormalization is the process of making all rows and columns orthogonal to each
|
|
/// other and making all rows and columns of unit length. This means that any given row will
|
|
/// be orthogonal to any other given row and any given column will be orthogonal to any other
|
|
/// given column. Any given row will not be orthogonal to any given column. Every row and every
|
|
/// column will be of unit length.</para>
|
|
/// <para>Because this method uses the modified Gram-Schmidt process, the resulting matrix
|
|
/// tends to be numerically unstable. The numeric stability decreases according to the rows
|
|
/// so that the first row is the most stable and the last row is the least stable.</para>
|
|
/// <para>This operation is performed on the rows of the matrix rather than the columns.
|
|
/// If you wish for this operation to be performed on the columns, first transpose the
|
|
/// input and than transpose the output.</para>
|
|
/// </remarks>
|
|
public static Matrix Orthonormalize(Matrix value)
|
|
{
|
|
Matrix result;
|
|
Orthonormalize(ref value, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Brings the matrix into upper triangular form using elementry row operations.
|
|
/// </summary>
|
|
/// <param name="value">The matrix to put into upper triangular form.</param>
|
|
/// <param name="result">When the method completes, contains the upper triangular matrix.</param>
|
|
/// <remarks>
|
|
/// If the matrix is not invertable (i.e. its determinant is zero) than the result of this
|
|
/// method may produce Single.Nan and Single.Inf values. When the matrix represents a system
|
|
/// of linear equations, than this often means that either no solution exists or an infinite
|
|
/// number of solutions exist.
|
|
/// </remarks>
|
|
public static void UpperTriangularForm(ref Matrix value, out Matrix result)
|
|
{
|
|
//Adapted from the row echelon code.
|
|
result = value;
|
|
int lead = 0;
|
|
int rowcount = 4;
|
|
int columncount = 4;
|
|
|
|
for (int r = 0; r < rowcount; ++r)
|
|
{
|
|
if (columncount <= lead)
|
|
return;
|
|
|
|
int i = r;
|
|
|
|
while (Math.Abs(result[i, lead]) < MathUtil.ZeroTolerance)
|
|
{
|
|
i++;
|
|
|
|
if (i == rowcount)
|
|
{
|
|
i = r;
|
|
lead++;
|
|
|
|
if (lead == columncount)
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (i != r)
|
|
{
|
|
result.ExchangeRows(i, r);
|
|
}
|
|
|
|
float multiplier = 1f / result[r, lead];
|
|
|
|
for (; i < rowcount; ++i)
|
|
{
|
|
if (i != r)
|
|
{
|
|
result[i, 0] -= result[r, 0] * multiplier * result[i, lead];
|
|
result[i, 1] -= result[r, 1] * multiplier * result[i, lead];
|
|
result[i, 2] -= result[r, 2] * multiplier * result[i, lead];
|
|
result[i, 3] -= result[r, 3] * multiplier * result[i, lead];
|
|
}
|
|
}
|
|
|
|
lead++;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Brings the matrix into upper triangular form using elementry row operations.
|
|
/// </summary>
|
|
/// <param name="value">The matrix to put into upper triangular form.</param>
|
|
/// <returns>The upper triangular matrix.</returns>
|
|
/// <remarks>
|
|
/// If the matrix is not invertable (i.e. its determinant is zero) than the result of this
|
|
/// method may produce Single.Nan and Single.Inf values. When the matrix represents a system
|
|
/// of linear equations, than this often means that either no solution exists or an infinite
|
|
/// number of solutions exist.
|
|
/// </remarks>
|
|
public static Matrix UpperTriangularForm(Matrix value)
|
|
{
|
|
Matrix result;
|
|
UpperTriangularForm(ref value, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Brings the matrix into lower triangular form using elementry row operations.
|
|
/// </summary>
|
|
/// <param name="value">The matrix to put into lower triangular form.</param>
|
|
/// <param name="result">When the method completes, contains the lower triangular matrix.</param>
|
|
/// <remarks>
|
|
/// If the matrix is not invertable (i.e. its determinant is zero) than the result of this
|
|
/// method may produce Single.Nan and Single.Inf values. When the matrix represents a system
|
|
/// of linear equations, than this often means that either no solution exists or an infinite
|
|
/// number of solutions exist.
|
|
/// </remarks>
|
|
public static void LowerTriangularForm(ref Matrix value, out Matrix result)
|
|
{
|
|
//Adapted from the row echelon code.
|
|
Matrix temp = value;
|
|
Matrix.Transpose(ref temp, out result);
|
|
|
|
int lead = 0;
|
|
int rowcount = 4;
|
|
int columncount = 4;
|
|
|
|
for (int r = 0; r < rowcount; ++r)
|
|
{
|
|
if (columncount <= lead)
|
|
return;
|
|
|
|
int i = r;
|
|
|
|
while (Math.Abs(result[i, lead]) < MathUtil.ZeroTolerance)
|
|
{
|
|
i++;
|
|
|
|
if (i == rowcount)
|
|
{
|
|
i = r;
|
|
lead++;
|
|
|
|
if (lead == columncount)
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (i != r)
|
|
{
|
|
result.ExchangeRows(i, r);
|
|
}
|
|
|
|
float multiplier = 1f / result[r, lead];
|
|
|
|
for (; i < rowcount; ++i)
|
|
{
|
|
if (i != r)
|
|
{
|
|
result[i, 0] -= result[r, 0] * multiplier * result[i, lead];
|
|
result[i, 1] -= result[r, 1] * multiplier * result[i, lead];
|
|
result[i, 2] -= result[r, 2] * multiplier * result[i, lead];
|
|
result[i, 3] -= result[r, 3] * multiplier * result[i, lead];
|
|
}
|
|
}
|
|
|
|
lead++;
|
|
}
|
|
|
|
Matrix.Transpose(ref result, out result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Brings the matrix into lower triangular form using elementry row operations.
|
|
/// </summary>
|
|
/// <param name="value">The matrix to put into lower triangular form.</param>
|
|
/// <returns>The lower triangular matrix.</returns>
|
|
/// <remarks>
|
|
/// If the matrix is not invertable (i.e. its determinant is zero) than the result of this
|
|
/// method may produce Single.Nan and Single.Inf values. When the matrix represents a system
|
|
/// of linear equations, than this often means that either no solution exists or an infinite
|
|
/// number of solutions exist.
|
|
/// </remarks>
|
|
public static Matrix LowerTriangularForm(Matrix value)
|
|
{
|
|
Matrix result;
|
|
LowerTriangularForm(ref value, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Brings the matrix into row echelon form using elementry row operations;
|
|
/// </summary>
|
|
/// <param name="value">The matrix to put into row echelon form.</param>
|
|
/// <param name="result">When the method completes, contains the row echelon form of the matrix.</param>
|
|
public static void RowEchelonForm(ref Matrix value, out Matrix result)
|
|
{
|
|
//Source: Wikipedia psuedo code
|
|
//Reference: http://en.wikipedia.org/wiki/Row_echelon_form#Pseudocode
|
|
|
|
result = value;
|
|
int lead = 0;
|
|
int rowcount = 4;
|
|
int columncount = 4;
|
|
|
|
for (int r = 0; r < rowcount; ++r)
|
|
{
|
|
if (columncount <= lead)
|
|
return;
|
|
|
|
int i = r;
|
|
|
|
while (Math.Abs(result[i, lead]) < MathUtil.ZeroTolerance)
|
|
{
|
|
i++;
|
|
|
|
if (i == rowcount)
|
|
{
|
|
i = r;
|
|
lead++;
|
|
|
|
if (lead == columncount)
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (i != r)
|
|
{
|
|
result.ExchangeRows(i, r);
|
|
}
|
|
|
|
float multiplier = 1f / result[r, lead];
|
|
result[r, 0] *= multiplier;
|
|
result[r, 1] *= multiplier;
|
|
result[r, 2] *= multiplier;
|
|
result[r, 3] *= multiplier;
|
|
|
|
for (; i < rowcount; ++i)
|
|
{
|
|
if (i != r)
|
|
{
|
|
result[i, 0] -= result[r, 0] * result[i, lead];
|
|
result[i, 1] -= result[r, 1] * result[i, lead];
|
|
result[i, 2] -= result[r, 2] * result[i, lead];
|
|
result[i, 3] -= result[r, 3] * result[i, lead];
|
|
}
|
|
}
|
|
|
|
lead++;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Brings the matrix into row echelon form using elementry row operations;
|
|
/// </summary>
|
|
/// <param name="value">The matrix to put into row echelon form.</param>
|
|
/// <returns>When the method completes, contains the row echelon form of the matrix.</returns>
|
|
public static Matrix RowEchelonForm(Matrix value)
|
|
{
|
|
Matrix result;
|
|
RowEchelonForm(ref value, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Brings the matrix into reduced row echelon form using elementry row operations.
|
|
/// </summary>
|
|
/// <param name="value">The matrix to put into reduced row echelon form.</param>
|
|
/// <param name="augment">The fifth column of the matrix.</param>
|
|
/// <param name="result">When the method completes, contains the resultant matrix after the operation.</param>
|
|
/// <param name="augmentResult">When the method completes, contains the resultant fifth column of the matrix.</param>
|
|
/// <remarks>
|
|
/// <para>The fifth column is often called the agumented part of the matrix. This is because the fifth
|
|
/// column is really just an extension of the matrix so that there is a place to put all of the
|
|
/// non-zero components after the operation is complete.</para>
|
|
/// <para>Often times the resultant matrix will the identity matrix or a matrix similar to the identity
|
|
/// matrix. Sometimes, however, that is not possible and numbers other than zero and one may appear.</para>
|
|
/// <para>This method can be used to solve systems of linear equations. Upon completion of this method,
|
|
/// the <paramref name="augmentResult"/> will contain the solution for the system. It is up to the user
|
|
/// to analyze both the input and the result to determine if a solution really exists.</para>
|
|
/// </remarks>
|
|
public static void ReducedRowEchelonForm(ref Matrix value, ref Vec4 augment, out Matrix result, out Vec4 augmentResult)
|
|
{
|
|
//Source: http://rosettacode.org
|
|
//Reference: http://rosettacode.org/wiki/Reduced_row_echelon_form
|
|
|
|
float[,] matrix = new float[4, 5];
|
|
|
|
matrix[0, 0] = value[0, 0];
|
|
matrix[0, 1] = value[0, 1];
|
|
matrix[0, 2] = value[0, 2];
|
|
matrix[0, 3] = value[0, 3];
|
|
matrix[0, 4] = augment[0];
|
|
|
|
matrix[1, 0] = value[1, 0];
|
|
matrix[1, 1] = value[1, 1];
|
|
matrix[1, 2] = value[1, 2];
|
|
matrix[1, 3] = value[1, 3];
|
|
matrix[1, 4] = augment[1];
|
|
|
|
matrix[2, 0] = value[2, 0];
|
|
matrix[2, 1] = value[2, 1];
|
|
matrix[2, 2] = value[2, 2];
|
|
matrix[2, 3] = value[2, 3];
|
|
matrix[2, 4] = augment[2];
|
|
|
|
matrix[3, 0] = value[3, 0];
|
|
matrix[3, 1] = value[3, 1];
|
|
matrix[3, 2] = value[3, 2];
|
|
matrix[3, 3] = value[3, 3];
|
|
matrix[3, 4] = augment[3];
|
|
|
|
int lead = 0;
|
|
int rowcount = 4;
|
|
int columncount = 5;
|
|
|
|
for (int r = 0; r < rowcount; r++)
|
|
{
|
|
if (columncount <= lead)
|
|
break;
|
|
|
|
int i = r;
|
|
|
|
while (matrix[i, lead] == 0)
|
|
{
|
|
i++;
|
|
|
|
if (i == rowcount)
|
|
{
|
|
i = r;
|
|
lead++;
|
|
|
|
if (columncount == lead)
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (int j = 0; j < columncount; j++)
|
|
{
|
|
float temp = matrix[r, j];
|
|
matrix[r, j] = matrix[i, j];
|
|
matrix[i, j] = temp;
|
|
}
|
|
|
|
float div = matrix[r, lead];
|
|
|
|
for (int j = 0; j < columncount; j++)
|
|
{
|
|
matrix[r, j] /= div;
|
|
}
|
|
|
|
for (int j = 0; j < rowcount; j++)
|
|
{
|
|
if (j != r)
|
|
{
|
|
float sub = matrix[j, lead];
|
|
for (int k = 0; k < columncount; k++) matrix[j, k] -= (sub * matrix[r, k]);
|
|
}
|
|
}
|
|
|
|
lead++;
|
|
}
|
|
|
|
result.M11 = matrix[0, 0];
|
|
result.M12 = matrix[0, 1];
|
|
result.M13 = matrix[0, 2];
|
|
result.M14 = matrix[0, 3];
|
|
|
|
result.M21 = matrix[1, 0];
|
|
result.M22 = matrix[1, 1];
|
|
result.M23 = matrix[1, 2];
|
|
result.M24 = matrix[1, 3];
|
|
|
|
result.M31 = matrix[2, 0];
|
|
result.M32 = matrix[2, 1];
|
|
result.M33 = matrix[2, 2];
|
|
result.M34 = matrix[2, 3];
|
|
|
|
result.M41 = matrix[3, 0];
|
|
result.M42 = matrix[3, 1];
|
|
result.M43 = matrix[3, 2];
|
|
result.M44 = matrix[3, 3];
|
|
|
|
augmentResult.X = matrix[0, 4];
|
|
augmentResult.Y = matrix[1, 4];
|
|
augmentResult.Z = matrix[2, 4];
|
|
augmentResult.W = matrix[3, 4];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a spherical billboard that rotates around a specified object position.
|
|
/// </summary>
|
|
/// <param name="objectPosition">The position of the object around which the billboard will rotate.</param>
|
|
/// <param name="cameraPosition">The position of the camera.</param>
|
|
/// <param name="cameraUpVector">The up vector of the camera.</param>
|
|
/// <param name="cameraForwardVector">The forward vector of the camera.</param>
|
|
/// <param name="result">When the method completes, contains the created billboard matrix.</param>
|
|
public static void Billboard(ref Vec3 objectPosition, ref Vec3 cameraPosition, ref Vec3 cameraUpVector, ref Vec3 cameraForwardVector, out Matrix result)
|
|
{
|
|
Vec3 crossed;
|
|
Vec3 final;
|
|
Vec3 difference = objectPosition - cameraPosition;
|
|
|
|
float lengthSq = difference.LengthSquared();
|
|
if (lengthSq < MathUtil.ZeroTolerance)
|
|
difference = -cameraForwardVector;
|
|
else
|
|
difference *= (float)(1.0 / Math.Sqrt(lengthSq));
|
|
|
|
Vec3.Cross(ref cameraUpVector, ref difference, out crossed);
|
|
crossed.Normalize();
|
|
Vec3.Cross(ref difference, ref crossed, out final);
|
|
|
|
result.M11 = crossed.X;
|
|
result.M12 = crossed.Y;
|
|
result.M13 = crossed.Z;
|
|
result.M14 = 0.0f;
|
|
result.M21 = final.X;
|
|
result.M22 = final.Y;
|
|
result.M23 = final.Z;
|
|
result.M24 = 0.0f;
|
|
result.M31 = difference.X;
|
|
result.M32 = difference.Y;
|
|
result.M33 = difference.Z;
|
|
result.M34 = 0.0f;
|
|
result.M41 = objectPosition.X;
|
|
result.M42 = objectPosition.Y;
|
|
result.M43 = objectPosition.Z;
|
|
result.M44 = 1.0f;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a spherical billboard that rotates around a specified object position.
|
|
/// </summary>
|
|
/// <param name="objectPosition">The position of the object around which the billboard will rotate.</param>
|
|
/// <param name="cameraPosition">The position of the camera.</param>
|
|
/// <param name="cameraUpVector">The up vector of the camera.</param>
|
|
/// <param name="cameraForwardVector">The forward vector of the camera.</param>
|
|
/// <returns>The created billboard matrix.</returns>
|
|
public static Matrix Billboard(Vec3 objectPosition, Vec3 cameraPosition, Vec3 cameraUpVector, Vec3 cameraForwardVector)
|
|
{
|
|
Matrix result;
|
|
Billboard(ref objectPosition, ref cameraPosition, ref cameraUpVector, ref cameraForwardVector, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a left-handed, look-at matrix.
|
|
/// </summary>
|
|
/// <param name="eye">The position of the viewer's eye.</param>
|
|
/// <param name="target">The camera look-at target.</param>
|
|
/// <param name="up">The camera's up vector.</param>
|
|
/// <param name="result">When the method completes, contains the created look-at matrix.</param>
|
|
public static void LookAtLH(ref Vec3 eye, ref Vec3 target, ref Vec3 up, out Matrix result)
|
|
{
|
|
Vec3 xaxis, yaxis, zaxis;
|
|
Vec3.Subtract(ref target, ref eye, out zaxis); zaxis.Normalize();
|
|
Vec3.Cross(ref up, ref zaxis, out xaxis); xaxis.Normalize();
|
|
Vec3.Cross(ref zaxis, ref xaxis, out yaxis);
|
|
|
|
result = Matrix.Identity;
|
|
result.M11 = xaxis.X; result.M21 = xaxis.Y; result.M31 = xaxis.Z;
|
|
result.M12 = yaxis.X; result.M22 = yaxis.Y; result.M32 = yaxis.Z;
|
|
result.M13 = zaxis.X; result.M23 = zaxis.Y; result.M33 = zaxis.Z;
|
|
|
|
Vec3.Dot(ref xaxis, ref eye, out result.M41);
|
|
Vec3.Dot(ref yaxis, ref eye, out result.M42);
|
|
Vec3.Dot(ref zaxis, ref eye, out result.M43);
|
|
|
|
result.M41 = -result.M41;
|
|
result.M42 = -result.M42;
|
|
result.M43 = -result.M43;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a left-handed, look-at matrix.
|
|
/// </summary>
|
|
/// <param name="eye">The position of the viewer's eye.</param>
|
|
/// <param name="target">The camera look-at target.</param>
|
|
/// <param name="up">The camera's up vector.</param>
|
|
/// <returns>The created look-at matrix.</returns>
|
|
public static Matrix LookAtLH(Vec3 eye, Vec3 target, Vec3 up)
|
|
{
|
|
Matrix result;
|
|
LookAtLH(ref eye, ref target, ref up, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a right-handed, look-at matrix.
|
|
/// </summary>
|
|
/// <param name="eye">The position of the viewer's eye.</param>
|
|
/// <param name="target">The camera look-at target.</param>
|
|
/// <param name="up">The camera's up vector.</param>
|
|
/// <param name="result">When the method completes, contains the created look-at matrix.</param>
|
|
public static void LookAtRH(ref Vec3 eye, ref Vec3 target, ref Vec3 up, out Matrix result)
|
|
{
|
|
Vec3 xaxis, yaxis, zaxis;
|
|
Vec3.Subtract(ref eye, ref target, out zaxis); zaxis.Normalize();
|
|
Vec3.Cross(ref up, ref zaxis, out xaxis); xaxis.Normalize();
|
|
Vec3.Cross(ref zaxis, ref xaxis, out yaxis);
|
|
|
|
result = Matrix.Identity;
|
|
result.M11 = xaxis.X; result.M21 = xaxis.Y; result.M31 = xaxis.Z;
|
|
result.M12 = yaxis.X; result.M22 = yaxis.Y; result.M32 = yaxis.Z;
|
|
result.M13 = zaxis.X; result.M23 = zaxis.Y; result.M33 = zaxis.Z;
|
|
|
|
Vec3.Dot(ref xaxis, ref eye, out result.M41);
|
|
Vec3.Dot(ref yaxis, ref eye, out result.M42);
|
|
Vec3.Dot(ref zaxis, ref eye, out result.M43);
|
|
|
|
result.M41 = -result.M41;
|
|
result.M42 = -result.M42;
|
|
result.M43 = -result.M43;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a right-handed, look-at matrix.
|
|
/// </summary>
|
|
/// <param name="eye">The position of the viewer's eye.</param>
|
|
/// <param name="target">The camera look-at target.</param>
|
|
/// <param name="up">The camera's up vector.</param>
|
|
/// <returns>The created look-at matrix.</returns>
|
|
public static Matrix LookAtRH(Vec3 eye, Vec3 target, Vec3 up)
|
|
{
|
|
Matrix result;
|
|
LookAtRH(ref eye, ref target, ref up, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a left-handed, orthographic projection matrix.
|
|
/// </summary>
|
|
/// <param name="width">Width of the viewing volume.</param>
|
|
/// <param name="height">Height of the viewing volume.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <param name="result">When the method completes, contains the created projection matrix.</param>
|
|
public static void OrthoLH(float width, float height, float znear, float zfar, out Matrix result)
|
|
{
|
|
float halfWidth = width * 0.5f;
|
|
float halfHeight = height * 0.5f;
|
|
|
|
OrthoOffCenterLH(-halfWidth, halfWidth, -halfHeight, halfHeight, znear, zfar, out result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a left-handed, orthographic projection matrix.
|
|
/// </summary>
|
|
/// <param name="width">Width of the viewing volume.</param>
|
|
/// <param name="height">Height of the viewing volume.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <returns>The created projection matrix.</returns>
|
|
public static Matrix OrthoLH(float width, float height, float znear, float zfar)
|
|
{
|
|
Matrix result;
|
|
OrthoLH(width, height, znear, zfar, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a right-handed, orthographic projection matrix.
|
|
/// </summary>
|
|
/// <param name="width">Width of the viewing volume.</param>
|
|
/// <param name="height">Height of the viewing volume.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <param name="result">When the method completes, contains the created projection matrix.</param>
|
|
public static void OrthoRH(float width, float height, float znear, float zfar, out Matrix result)
|
|
{
|
|
float halfWidth = width * 0.5f;
|
|
float halfHeight = height * 0.5f;
|
|
|
|
OrthoOffCenterRH(-halfWidth, halfWidth, -halfHeight, halfHeight, znear, zfar, out result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a right-handed, orthographic projection matrix.
|
|
/// </summary>
|
|
/// <param name="width">Width of the viewing volume.</param>
|
|
/// <param name="height">Height of the viewing volume.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <returns>The created projection matrix.</returns>
|
|
public static Matrix OrthoRH(float width, float height, float znear, float zfar)
|
|
{
|
|
Matrix result;
|
|
OrthoRH(width, height, znear, zfar, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a left-handed, customized orthographic projection matrix.
|
|
/// </summary>
|
|
/// <param name="left">Minimum x-value of the viewing volume.</param>
|
|
/// <param name="right">Maximum x-value of the viewing volume.</param>
|
|
/// <param name="bottom">Minimum y-value of the viewing volume.</param>
|
|
/// <param name="top">Maximum y-value of the viewing volume.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <param name="result">When the method completes, contains the created projection matrix.</param>
|
|
public static void OrthoOffCenterLH(float left, float right, float bottom, float top, float znear, float zfar, out Matrix result)
|
|
{
|
|
float zRange = 1.0f / (zfar - znear);
|
|
|
|
result = Matrix.Identity;
|
|
result.M11 = 2.0f / (right - left);
|
|
result.M22 = 2.0f / (top - bottom);
|
|
result.M33 = zRange;
|
|
result.M41 = (left + right) / (left - right);
|
|
result.M42 = (top + bottom) / (bottom - top);
|
|
result.M43 = -znear * zRange;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a left-handed, customized orthographic projection matrix.
|
|
/// </summary>
|
|
/// <param name="left">Minimum x-value of the viewing volume.</param>
|
|
/// <param name="right">Maximum x-value of the viewing volume.</param>
|
|
/// <param name="bottom">Minimum y-value of the viewing volume.</param>
|
|
/// <param name="top">Maximum y-value of the viewing volume.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <returns>The created projection matrix.</returns>
|
|
public static Matrix OrthoOffCenterLH(float left, float right, float bottom, float top, float znear, float zfar)
|
|
{
|
|
Matrix result;
|
|
OrthoOffCenterLH(left, right, bottom, top, znear, zfar, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a right-handed, customized orthographic projection matrix.
|
|
/// </summary>
|
|
/// <param name="left">Minimum x-value of the viewing volume.</param>
|
|
/// <param name="right">Maximum x-value of the viewing volume.</param>
|
|
/// <param name="bottom">Minimum y-value of the viewing volume.</param>
|
|
/// <param name="top">Maximum y-value of the viewing volume.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <param name="result">When the method completes, contains the created projection matrix.</param>
|
|
public static void OrthoOffCenterRH(float left, float right, float bottom, float top, float znear, float zfar, out Matrix result)
|
|
{
|
|
OrthoOffCenterLH(left, right, bottom, top, znear, zfar, out result);
|
|
result.M33 *= -1.0f;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a right-handed, customized orthographic projection matrix.
|
|
/// </summary>
|
|
/// <param name="left">Minimum x-value of the viewing volume.</param>
|
|
/// <param name="right">Maximum x-value of the viewing volume.</param>
|
|
/// <param name="bottom">Minimum y-value of the viewing volume.</param>
|
|
/// <param name="top">Maximum y-value of the viewing volume.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <returns>The created projection matrix.</returns>
|
|
public static Matrix OrthoOffCenterRH(float left, float right, float bottom, float top, float znear, float zfar)
|
|
{
|
|
Matrix result;
|
|
OrthoOffCenterRH(left, right, bottom, top, znear, zfar, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a left-handed, perspective projection matrix.
|
|
/// </summary>
|
|
/// <param name="width">Width of the viewing volume.</param>
|
|
/// <param name="height">Height of the viewing volume.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <param name="result">When the method completes, contains the created projection matrix.</param>
|
|
public static void PerspectiveLH(float width, float height, float znear, float zfar, out Matrix result)
|
|
{
|
|
float halfWidth = width * 0.5f;
|
|
float halfHeight = height * 0.5f;
|
|
|
|
PerspectiveOffCenterLH(-halfWidth, halfWidth, -halfHeight, halfHeight, znear, zfar, out result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a left-handed, perspective projection matrix.
|
|
/// </summary>
|
|
/// <param name="width">Width of the viewing volume.</param>
|
|
/// <param name="height">Height of the viewing volume.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <returns>The created projection matrix.</returns>
|
|
public static Matrix PerspectiveLH(float width, float height, float znear, float zfar)
|
|
{
|
|
Matrix result;
|
|
PerspectiveLH(width, height, znear, zfar, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a right-handed, perspective projection matrix.
|
|
/// </summary>
|
|
/// <param name="width">Width of the viewing volume.</param>
|
|
/// <param name="height">Height of the viewing volume.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <param name="result">When the method completes, contains the created projection matrix.</param>
|
|
public static void PerspectiveRH(float width, float height, float znear, float zfar, out Matrix result)
|
|
{
|
|
float halfWidth = width * 0.5f;
|
|
float halfHeight = height * 0.5f;
|
|
|
|
PerspectiveOffCenterRH(-halfWidth, halfWidth, -halfHeight, halfHeight, znear, zfar, out result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a right-handed, perspective projection matrix.
|
|
/// </summary>
|
|
/// <param name="width">Width of the viewing volume.</param>
|
|
/// <param name="height">Height of the viewing volume.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <returns>The created projection matrix.</returns>
|
|
public static Matrix PerspectiveRH(float width, float height, float znear, float zfar)
|
|
{
|
|
Matrix result;
|
|
PerspectiveRH(width, height, znear, zfar, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a left-handed, perspective projection matrix based on a field of view.
|
|
/// </summary>
|
|
/// <param name="fov">Field of view in the y direction, in radians.</param>
|
|
/// <param name="aspect">Aspect ratio, defined as view space width divided by height.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <param name="result">When the method completes, contains the created projection matrix.</param>
|
|
public static void PerspectiveFovLH(float fov, float aspect, float znear, float zfar, out Matrix result)
|
|
{
|
|
float yScale = (float)(1.0 / Math.Tan(fov * 0.5f));
|
|
float xScale = yScale / aspect;
|
|
|
|
float halfWidth = znear / xScale;
|
|
float halfHeight = znear / yScale;
|
|
|
|
PerspectiveOffCenterLH(-halfWidth, halfWidth, -halfHeight, halfHeight, znear, zfar, out result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a left-handed, perspective projection matrix based on a field of view.
|
|
/// </summary>
|
|
/// <param name="fov">Field of view in the y direction, in radians.</param>
|
|
/// <param name="aspect">Aspect ratio, defined as view space width divided by height.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <returns>The created projection matrix.</returns>
|
|
public static Matrix PerspectiveFovLH(float fov, float aspect, float znear, float zfar)
|
|
{
|
|
Matrix result;
|
|
PerspectiveFovLH(fov, aspect, znear, zfar, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a right-handed, perspective projection matrix based on a field of view.
|
|
/// </summary>
|
|
/// <param name="fov">Field of view in the y direction, in radians.</param>
|
|
/// <param name="aspect">Aspect ratio, defined as view space width divided by height.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <param name="result">When the method completes, contains the created projection matrix.</param>
|
|
public static void PerspectiveFovRH(float fov, float aspect, float znear, float zfar, out Matrix result)
|
|
{
|
|
float yScale = (float)(1.0 / Math.Tan(fov * 0.5f));
|
|
float xScale = yScale / aspect;
|
|
|
|
float halfWidth = znear / xScale;
|
|
float halfHeight = znear / yScale;
|
|
|
|
PerspectiveOffCenterRH(-halfWidth, halfWidth, -halfHeight, halfHeight, znear, zfar, out result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a right-handed, perspective projection matrix based on a field of view.
|
|
/// </summary>
|
|
/// <param name="fov">Field of view in the y direction, in radians.</param>
|
|
/// <param name="aspect">Aspect ratio, defined as view space width divided by height.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <returns>The created projection matrix.</returns>
|
|
public static Matrix PerspectiveFovRH(float fov, float aspect, float znear, float zfar)
|
|
{
|
|
Matrix result;
|
|
PerspectiveFovRH(fov, aspect, znear, zfar, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a left-handed, customized perspective projection matrix.
|
|
/// </summary>
|
|
/// <param name="left">Minimum x-value of the viewing volume.</param>
|
|
/// <param name="right">Maximum x-value of the viewing volume.</param>
|
|
/// <param name="bottom">Minimum y-value of the viewing volume.</param>
|
|
/// <param name="top">Maximum y-value of the viewing volume.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <param name="result">When the method completes, contains the created projection matrix.</param>
|
|
public static void PerspectiveOffCenterLH(float left, float right, float bottom, float top, float znear, float zfar, out Matrix result)
|
|
{
|
|
float zRange = zfar / (zfar - znear);
|
|
|
|
result = new Matrix();
|
|
result.M11 = 2.0f * znear / (right - left);
|
|
result.M22 = 2.0f * znear / (top - bottom);
|
|
result.M31 = (left + right) / (left - right);
|
|
result.M32 = (top + bottom) / (bottom - top);
|
|
result.M33 = zRange;
|
|
result.M34 = 1.0f;
|
|
result.M43 = -znear * zRange;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a left-handed, customized perspective projection matrix.
|
|
/// </summary>
|
|
/// <param name="left">Minimum x-value of the viewing volume.</param>
|
|
/// <param name="right">Maximum x-value of the viewing volume.</param>
|
|
/// <param name="bottom">Minimum y-value of the viewing volume.</param>
|
|
/// <param name="top">Maximum y-value of the viewing volume.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <returns>The created projection matrix.</returns>
|
|
public static Matrix PerspectiveOffCenterLH(float left, float right, float bottom, float top, float znear, float zfar)
|
|
{
|
|
Matrix result;
|
|
PerspectiveOffCenterLH(left, right, bottom, top, znear, zfar, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a right-handed, customized perspective projection matrix.
|
|
/// </summary>
|
|
/// <param name="left">Minimum x-value of the viewing volume.</param>
|
|
/// <param name="right">Maximum x-value of the viewing volume.</param>
|
|
/// <param name="bottom">Minimum y-value of the viewing volume.</param>
|
|
/// <param name="top">Maximum y-value of the viewing volume.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <param name="result">When the method completes, contains the created projection matrix.</param>
|
|
public static void PerspectiveOffCenterRH(float left, float right, float bottom, float top, float znear, float zfar, out Matrix result)
|
|
{
|
|
PerspectiveOffCenterLH(left, right, bottom, top, znear, zfar, out result);
|
|
result.M31 *= -1.0f;
|
|
result.M32 *= -1.0f;
|
|
result.M33 *= -1.0f;
|
|
result.M34 *= -1.0f;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a right-handed, customized perspective projection matrix.
|
|
/// </summary>
|
|
/// <param name="left">Minimum x-value of the viewing volume.</param>
|
|
/// <param name="right">Maximum x-value of the viewing volume.</param>
|
|
/// <param name="bottom">Minimum y-value of the viewing volume.</param>
|
|
/// <param name="top">Maximum y-value of the viewing volume.</param>
|
|
/// <param name="znear">Minimum z-value of the viewing volume.</param>
|
|
/// <param name="zfar">Maximum z-value of the viewing volume.</param>
|
|
/// <returns>The created projection matrix.</returns>
|
|
public static Matrix PerspectiveOffCenterRH(float left, float right, float bottom, float top, float znear, float zfar)
|
|
{
|
|
Matrix result;
|
|
PerspectiveOffCenterRH(left, right, bottom, top, znear, zfar, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Builds a matrix that can be used to reflect vectors about a plane.
|
|
/// </summary>
|
|
/// <param name="plane">The plane for which the reflection occurs. This parameter is assumed to be normalized.</param>
|
|
/// <param name="result">When the method completes, contains the reflection matrix.</param>
|
|
public static void Reflection(ref Plane plane, out Matrix result)
|
|
{
|
|
float x = plane.Normal.X;
|
|
float y = plane.Normal.Y;
|
|
float z = plane.Normal.Z;
|
|
float x2 = -2.0f * x;
|
|
float y2 = -2.0f * y;
|
|
float z2 = -2.0f * z;
|
|
|
|
result.M11 = (x2 * x) + 1.0f;
|
|
result.M12 = y2 * x;
|
|
result.M13 = z2 * x;
|
|
result.M14 = 0.0f;
|
|
result.M21 = x2 * y;
|
|
result.M22 = (y2 * y) + 1.0f;
|
|
result.M23 = z2 * y;
|
|
result.M24 = 0.0f;
|
|
result.M31 = x2 * z;
|
|
result.M32 = y2 * z;
|
|
result.M33 = (z2 * z) + 1.0f;
|
|
result.M34 = 0.0f;
|
|
result.M41 = x2 * plane.D;
|
|
result.M42 = y2 * plane.D;
|
|
result.M43 = z2 * plane.D;
|
|
result.M44 = 1.0f;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Builds a matrix that can be used to reflect vectors about a plane.
|
|
/// </summary>
|
|
/// <param name="plane">The plane for which the reflection occurs. This parameter is assumed to be normalized.</param>
|
|
/// <returns>The reflection matrix.</returns>
|
|
public static Matrix Reflection(Plane plane)
|
|
{
|
|
Matrix result;
|
|
Reflection(ref plane, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a matrix that flattens geometry into a shadow.
|
|
/// </summary>
|
|
/// <param name="light">The light direction. If the W component is 0, the light is directional light; if the
|
|
/// W component is 1, the light is a point light.</param>
|
|
/// <param name="plane">The plane onto which to project the geometry as a shadow. This parameter is assumed to be normalized.</param>
|
|
/// <param name="result">When the method completes, contains the shadow matrix.</param>
|
|
public static void Shadow(ref Vec4 light, ref Plane plane, out Matrix result)
|
|
{
|
|
float dot = (plane.Normal.X * light.X) + (plane.Normal.Y * light.Y) + (plane.Normal.Z * light.Z) + (plane.D * light.W);
|
|
float x = -plane.Normal.X;
|
|
float y = -plane.Normal.Y;
|
|
float z = -plane.Normal.Z;
|
|
float d = -plane.D;
|
|
|
|
result.M11 = (x * light.X) + dot;
|
|
result.M21 = y * light.X;
|
|
result.M31 = z * light.X;
|
|
result.M41 = d * light.X;
|
|
result.M12 = x * light.Y;
|
|
result.M22 = (y * light.Y) + dot;
|
|
result.M32 = z * light.Y;
|
|
result.M42 = d * light.Y;
|
|
result.M13 = x * light.Z;
|
|
result.M23 = y * light.Z;
|
|
result.M33 = (z * light.Z) + dot;
|
|
result.M43 = d * light.Z;
|
|
result.M14 = x * light.W;
|
|
result.M24 = y * light.W;
|
|
result.M34 = z * light.W;
|
|
result.M44 = (d * light.W) + dot;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a matrix that flattens geometry into a shadow.
|
|
/// </summary>
|
|
/// <param name="light">The light direction. If the W component is 0, the light is directional light; if the
|
|
/// W component is 1, the light is a point light.</param>
|
|
/// <param name="plane">The plane onto which to project the geometry as a shadow. This parameter is assumed to be normalized.</param>
|
|
/// <returns>The shadow matrix.</returns>
|
|
public static Matrix Shadow(Vec4 light, Plane plane)
|
|
{
|
|
Matrix result;
|
|
Shadow(ref light, ref plane, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a matrix that scales along the x-axis, y-axis, and y-axis.
|
|
/// </summary>
|
|
/// <param name="scale">Scaling factor for all three axes.</param>
|
|
/// <param name="result">When the method completes, contains the created scaling matrix.</param>
|
|
public static void Scaling(ref Vec3 scale, out Matrix result)
|
|
{
|
|
Scaling(scale.X, scale.Y, scale.Z, out result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a matrix that scales along the x-axis, y-axis, and y-axis.
|
|
/// </summary>
|
|
/// <param name="scale">Scaling factor for all three axes.</param>
|
|
/// <returns>The created scaling matrix.</returns>
|
|
public static Matrix Scaling(Vec3 scale)
|
|
{
|
|
Matrix result;
|
|
Scaling(ref scale, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a matrix that scales along the x-axis, y-axis, and y-axis.
|
|
/// </summary>
|
|
/// <param name="x">Scaling factor that is applied along the x-axis.</param>
|
|
/// <param name="y">Scaling factor that is applied along the y-axis.</param>
|
|
/// <param name="z">Scaling factor that is applied along the z-axis.</param>
|
|
/// <param name="result">When the method completes, contains the created scaling matrix.</param>
|
|
public static void Scaling(float x, float y, float z, out Matrix result)
|
|
{
|
|
result = Matrix.Identity;
|
|
result.M11 = x;
|
|
result.M22 = y;
|
|
result.M33 = z;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a matrix that scales along the x-axis, y-axis, and y-axis.
|
|
/// </summary>
|
|
/// <param name="x">Scaling factor that is applied along the x-axis.</param>
|
|
/// <param name="y">Scaling factor that is applied along the y-axis.</param>
|
|
/// <param name="z">Scaling factor that is applied along the z-axis.</param>
|
|
/// <returns>The created scaling matrix.</returns>
|
|
public static Matrix Scaling(float x, float y, float z)
|
|
{
|
|
Matrix result;
|
|
Scaling(x, y, z, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a matrix that uniformally scales along all three axis.
|
|
/// </summary>
|
|
/// <param name="scale">The uniform scale that is applied along all axis.</param>
|
|
/// <param name="result">When the method completes, contains the created scaling matrix.</param>
|
|
public static void Scaling(float scale, out Matrix result)
|
|
{
|
|
result = Matrix.Identity;
|
|
result.M11 = result.M22 = result.M33 = scale;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a matrix that uniformally scales along all three axis.
|
|
/// </summary>
|
|
/// <param name="scale">The uniform scale that is applied along all axis.</param>
|
|
/// <returns>The created scaling matrix.</returns>
|
|
public static Matrix Scaling(float scale)
|
|
{
|
|
Matrix result;
|
|
Scaling(scale, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a matrix that rotates around the x-axis.
|
|
/// </summary>
|
|
/// <param name="angle">Angle of rotation in radians. Angles are measured clockwise when looking along the rotation axis toward the origin.</param>
|
|
/// <param name="result">When the method completes, contains the created rotation matrix.</param>
|
|
public static void RotationX(float angle, out Matrix result)
|
|
{
|
|
float cos = (float)Math.Cos(angle);
|
|
float sin = (float)Math.Sin(angle);
|
|
|
|
result = Matrix.Identity;
|
|
result.M22 = cos;
|
|
result.M23 = sin;
|
|
result.M32 = -sin;
|
|
result.M33 = cos;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a matrix that rotates around the x-axis.
|
|
/// </summary>
|
|
/// <param name="angle">Angle of rotation in radians. Angles are measured clockwise when looking along the rotation axis toward the origin.</param>
|
|
/// <returns>The created rotation matrix.</returns>
|
|
public static Matrix RotationX(float angle)
|
|
{
|
|
Matrix result;
|
|
RotationX(angle, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a matrix that rotates around the y-axis.
|
|
/// </summary>
|
|
/// <param name="angle">Angle of rotation in radians. Angles are measured clockwise when looking along the rotation axis toward the origin.</param>
|
|
/// <param name="result">When the method completes, contains the created rotation matrix.</param>
|
|
public static void RotationY(float angle, out Matrix result)
|
|
{
|
|
float cos = (float)Math.Cos(angle);
|
|
float sin = (float)Math.Sin(angle);
|
|
|
|
result = Matrix.Identity;
|
|
result.M11 = cos;
|
|
result.M13 = -sin;
|
|
result.M31 = sin;
|
|
result.M33 = cos;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a matrix that rotates around the y-axis.
|
|
/// </summary>
|
|
/// <param name="angle">Angle of rotation in radians. Angles are measured clockwise when looking along the rotation axis toward the origin.</param>
|
|
/// <returns>The created rotation matrix.</returns>
|
|
public static Matrix RotationY(float angle)
|
|
{
|
|
Matrix result;
|
|
RotationY(angle, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a matrix that rotates around the z-axis.
|
|
/// </summary>
|
|
/// <param name="angle">Angle of rotation in radians. Angles are measured clockwise when looking along the rotation axis toward the origin.</param>
|
|
/// <param name="result">When the method completes, contains the created rotation matrix.</param>
|
|
public static void RotationZ(float angle, out Matrix result)
|
|
{
|
|
float cos = (float)Math.Cos(angle);
|
|
float sin = (float)Math.Sin(angle);
|
|
|
|
result = Matrix.Identity;
|
|
result.M11 = cos;
|
|
result.M12 = sin;
|
|
result.M21 = -sin;
|
|
result.M22 = cos;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a matrix that rotates around the z-axis.
|
|
/// </summary>
|
|
/// <param name="angle">Angle of rotation in radians. Angles are measured clockwise when looking along the rotation axis toward the origin.</param>
|
|
/// <returns>The created rotation matrix.</returns>
|
|
public static Matrix RotationZ(float angle)
|
|
{
|
|
Matrix result;
|
|
RotationZ(angle, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a matrix that rotates around an arbitary axis.
|
|
/// </summary>
|
|
/// <param name="axis">The axis around which to rotate. This parameter is assumed to be normalized.</param>
|
|
/// <param name="angle">Angle of rotation in radians. Angles are measured clockwise when looking along the rotation axis toward the origin.</param>
|
|
/// <param name="result">When the method completes, contains the created rotation matrix.</param>
|
|
public static void RotationAxis(ref Vec3 axis, float angle, out Matrix result)
|
|
{
|
|
float x = axis.X;
|
|
float y = axis.Y;
|
|
float z = axis.Z;
|
|
float cos = (float)Math.Cos(angle);
|
|
float sin = (float)Math.Sin(angle);
|
|
float xx = x * x;
|
|
float yy = y * y;
|
|
float zz = z * z;
|
|
float xy = x * y;
|
|
float xz = x * z;
|
|
float yz = y * z;
|
|
|
|
result = Matrix.Identity;
|
|
result.M11 = xx + (cos * (1.0f - xx));
|
|
result.M12 = (xy - (cos * xy)) + (sin * z);
|
|
result.M13 = (xz - (cos * xz)) - (sin * y);
|
|
result.M21 = (xy - (cos * xy)) - (sin * z);
|
|
result.M22 = yy + (cos * (1.0f - yy));
|
|
result.M23 = (yz - (cos * yz)) + (sin * x);
|
|
result.M31 = (xz - (cos * xz)) + (sin * y);
|
|
result.M32 = (yz - (cos * yz)) - (sin * x);
|
|
result.M33 = zz + (cos * (1.0f - zz));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a matrix that rotates around an arbitary axis.
|
|
/// </summary>
|
|
/// <param name="axis">The axis around which to rotate. This parameter is assumed to be normalized.</param>
|
|
/// <param name="angle">Angle of rotation in radians. Angles are measured clockwise when looking along the rotation axis toward the origin.</param>
|
|
/// <returns>The created rotation matrix.</returns>
|
|
public static Matrix RotationAxis(Vec3 axis, float angle)
|
|
{
|
|
Matrix result;
|
|
RotationAxis(ref axis, angle, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a rotation matrix from a quaternion.
|
|
/// </summary>
|
|
/// <param name="rotation">The quaternion to use to build the matrix.</param>
|
|
/// <param name="result">The created rotation matrix.</param>
|
|
public static void RotationQuaternion(ref Quaternion rotation, out Matrix result)
|
|
{
|
|
float xx = rotation.X * rotation.X;
|
|
float yy = rotation.Y * rotation.Y;
|
|
float zz = rotation.Z * rotation.Z;
|
|
float xy = rotation.X * rotation.Y;
|
|
float zw = rotation.Z * rotation.W;
|
|
float zx = rotation.Z * rotation.X;
|
|
float yw = rotation.Y * rotation.W;
|
|
float yz = rotation.Y * rotation.Z;
|
|
float xw = rotation.X * rotation.W;
|
|
|
|
result = Matrix.Identity;
|
|
result.M11 = 1.0f - (2.0f * (yy + zz));
|
|
result.M12 = 2.0f * (xy + zw);
|
|
result.M13 = 2.0f * (zx - yw);
|
|
result.M21 = 2.0f * (xy - zw);
|
|
result.M22 = 1.0f - (2.0f * (zz + xx));
|
|
result.M23 = 2.0f * (yz + xw);
|
|
result.M31 = 2.0f * (zx + yw);
|
|
result.M32 = 2.0f * (yz - xw);
|
|
result.M33 = 1.0f - (2.0f * (yy + xx));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a matrix that contains both the X, Y and Z rotation, as well as scaling and translation. Note: This function is NOT thead safe.
|
|
/// </summary>
|
|
/// <param name="scaling">The scaling.</param>
|
|
/// <param name="rotation">Angle of rotation in radians. Angles are measured clockwise when looking along the rotation axis toward the origin.</param>
|
|
/// <param name="translation">The translation.</param>
|
|
/// <param name="result">When the method completes, contains the created rotation matrix.</param>
|
|
public static void Transformation(ref Vec3 scaling, ref Quaternion rotation, ref Vec3 translation, out Matrix result)
|
|
{
|
|
// Equivalent to:
|
|
//result =
|
|
// Matrix.Scaling(scaling)
|
|
// *Matrix.RotationX(rotation.X)
|
|
// *Matrix.RotationY(rotation.Y)
|
|
// *Matrix.RotationZ(rotation.Z)
|
|
// *Matrix.Position(translation);
|
|
|
|
// Rotation
|
|
float xx = rotation.X * rotation.X;
|
|
float yy = rotation.Y * rotation.Y;
|
|
float zz = rotation.Z * rotation.Z;
|
|
float xy = rotation.X * rotation.Y;
|
|
float zw = rotation.Z * rotation.W;
|
|
float zx = rotation.Z * rotation.X;
|
|
float yw = rotation.Y * rotation.W;
|
|
float yz = rotation.Y * rotation.Z;
|
|
float xw = rotation.X * rotation.W;
|
|
|
|
result.M11 = 1.0f - (2.0f * (yy + zz));
|
|
result.M12 = 2.0f * (xy + zw);
|
|
result.M13 = 2.0f * (zx - yw);
|
|
result.M21 = 2.0f * (xy - zw);
|
|
result.M22 = 1.0f - (2.0f * (zz + xx));
|
|
result.M23 = 2.0f * (yz + xw);
|
|
result.M31 = 2.0f * (zx + yw);
|
|
result.M32 = 2.0f * (yz - xw);
|
|
result.M33 = 1.0f - (2.0f * (yy + xx));
|
|
|
|
// Position
|
|
result.M41 = translation.X;
|
|
result.M42 = translation.Y;
|
|
result.M43 = translation.Z;
|
|
|
|
// Scale
|
|
if (scaling.X != 1.0f)
|
|
{
|
|
result.M11 *= scaling.X;
|
|
result.M12 *= scaling.X;
|
|
result.M13 *= scaling.X;
|
|
}
|
|
if (scaling.Y != 1.0f)
|
|
{
|
|
result.M21 *= scaling.Y;
|
|
result.M22 *= scaling.Y;
|
|
result.M23 *= scaling.Y;
|
|
}
|
|
if (scaling.Z != 1.0f)
|
|
{
|
|
result.M31 *= scaling.Z;
|
|
result.M32 *= scaling.Z;
|
|
result.M33 *= scaling.Z;
|
|
}
|
|
|
|
result.M14 = 0.0f;
|
|
result.M24 = 0.0f;
|
|
result.M34 = 0.0f;
|
|
result.M44 = 1.0f;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a rotation matrix from a quaternion.
|
|
/// </summary>
|
|
/// <param name="rotation">The quaternion to use to build the matrix.</param>
|
|
/// <returns>The created rotation matrix.</returns>
|
|
public static Matrix RotationQuaternion(Quaternion rotation)
|
|
{
|
|
Matrix result;
|
|
RotationQuaternion(ref rotation, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a rotation matrix with a specified yaw, pitch, and roll.
|
|
/// </summary>
|
|
/// <param name="yaw">Yaw around the y-axis, in radians.</param>
|
|
/// <param name="pitch">Pitch around the x-axis, in radians.</param>
|
|
/// <param name="roll">Roll around the z-axis, in radians.</param>
|
|
/// <param name="result">When the method completes, contains the created rotation matrix.</param>
|
|
public static void RotationYawPitchRoll(float yaw, float pitch, float roll, out Matrix result)
|
|
{
|
|
Quaternion quaternion = new Quaternion();
|
|
Quaternion.RotationYawPitchRoll(yaw, pitch, roll, out quaternion);
|
|
RotationQuaternion(ref quaternion, out result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a rotation matrix with a specified yaw, pitch, and roll.
|
|
/// </summary>
|
|
/// <param name="yaw">Yaw around the y-axis, in radians.</param>
|
|
/// <param name="pitch">Pitch around the x-axis, in radians.</param>
|
|
/// <param name="roll">Roll around the z-axis, in radians.</param>
|
|
/// <returns>The created rotation matrix.</returns>
|
|
public static Matrix RotationYawPitchRoll(float yaw, float pitch, float roll)
|
|
{
|
|
Matrix result;
|
|
RotationYawPitchRoll(yaw, pitch, roll, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a translation matrix using the specified offsets.
|
|
/// </summary>
|
|
/// <param name="value">The offset for all three coordinate planes.</param>
|
|
/// <param name="result">When the method completes, contains the created translation matrix.</param>
|
|
public static void Translation(ref Vec3 value, out Matrix result)
|
|
{
|
|
Translation(value.X, value.Y, value.Z, out result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a translation matrix using the specified offsets.
|
|
/// </summary>
|
|
/// <param name="value">The offset for all three coordinate planes.</param>
|
|
/// <returns>The created translation matrix.</returns>
|
|
public static Matrix Translation(Vec3 value)
|
|
{
|
|
Matrix result;
|
|
Translation(ref value, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a translation matrix using the specified offsets.
|
|
/// </summary>
|
|
/// <param name="x">X-coordinate offset.</param>
|
|
/// <param name="y">Y-coordinate offset.</param>
|
|
/// <param name="z">Z-coordinate offset.</param>
|
|
/// <param name="result">When the method completes, contains the created translation matrix.</param>
|
|
public static void Translation(float x, float y, float z, out Matrix result)
|
|
{
|
|
result = Matrix.Identity;
|
|
result.M41 = x;
|
|
result.M42 = y;
|
|
result.M43 = z;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a translation matrix using the specified offsets.
|
|
/// </summary>
|
|
/// <param name="x">X-coordinate offset.</param>
|
|
/// <param name="y">Y-coordinate offset.</param>
|
|
/// <param name="z">Z-coordinate offset.</param>
|
|
/// <returns>The created translation matrix.</returns>
|
|
public static Matrix Translation(float x, float y, float z)
|
|
{
|
|
Matrix result;
|
|
Translation(x, y, z, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a 3D affine transformation matrix.
|
|
/// </summary>
|
|
/// <param name="scaling">Scaling factor.</param>
|
|
/// <param name="rotation">The rotation of the transformation.</param>
|
|
/// <param name="translation">The translation factor of the transformation.</param>
|
|
/// <param name="result">When the method completes, contains the created affine transformation matrix.</param>
|
|
public static void AffineTransformation(float scaling, ref Quaternion rotation, ref Vec3 translation, out Matrix result)
|
|
{
|
|
result = Scaling(scaling) * RotationQuaternion(rotation) * Translation(translation);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a 3D affine transformation matrix.
|
|
/// </summary>
|
|
/// <param name="scaling">Scaling factor.</param>
|
|
/// <param name="rotation">The rotation of the transformation.</param>
|
|
/// <param name="translation">The translation factor of the transformation.</param>
|
|
/// <returns>The created affine transformation matrix.</returns>
|
|
public static Matrix AffineTransformation(float scaling, Quaternion rotation, Vec3 translation)
|
|
{
|
|
Matrix result;
|
|
AffineTransformation(scaling, ref rotation, ref translation, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a 3D affine transformation matrix.
|
|
/// </summary>
|
|
/// <param name="scaling">Scaling factor.</param>
|
|
/// <param name="rotationCenter">The center of the rotation.</param>
|
|
/// <param name="rotation">The rotation of the transformation.</param>
|
|
/// <param name="translation">The translation factor of the transformation.</param>
|
|
/// <param name="result">When the method completes, contains the created affine transformation matrix.</param>
|
|
public static void AffineTransformation(float scaling, ref Vec3 rotationCenter, ref Quaternion rotation, ref Vec3 translation, out Matrix result)
|
|
{
|
|
result = Scaling(scaling) * Translation(-rotationCenter) * RotationQuaternion(rotation) *
|
|
Translation(rotationCenter) * Translation(translation);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a 3D affine transformation matrix.
|
|
/// </summary>
|
|
/// <param name="scaling">Scaling factor.</param>
|
|
/// <param name="rotationCenter">The center of the rotation.</param>
|
|
/// <param name="rotation">The rotation of the transformation.</param>
|
|
/// <param name="translation">The translation factor of the transformation.</param>
|
|
/// <returns>The created affine transformation matrix.</returns>
|
|
public static Matrix AffineTransformation(float scaling, Vec3 rotationCenter, Quaternion rotation, Vec3 translation)
|
|
{
|
|
Matrix result;
|
|
AffineTransformation(scaling, ref rotationCenter, ref rotation, ref translation, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a 2D affine transformation matrix.
|
|
/// </summary>
|
|
/// <param name="scaling">Scaling factor.</param>
|
|
/// <param name="rotation">The rotation of the transformation.</param>
|
|
/// <param name="translation">The translation factor of the transformation.</param>
|
|
/// <param name="result">When the method completes, contains the created affine transformation matrix.</param>
|
|
public static void AffineTransformation2D(float scaling, float rotation, ref Vec2 translation, out Matrix result)
|
|
{
|
|
result = Scaling(scaling, scaling, 1.0f) * RotationZ(rotation) * Translation((Vec3)translation);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a 2D affine transformation matrix.
|
|
/// </summary>
|
|
/// <param name="scaling">Scaling factor.</param>
|
|
/// <param name="rotation">The rotation of the transformation.</param>
|
|
/// <param name="translation">The translation factor of the transformation.</param>
|
|
/// <returns>The created affine transformation matrix.</returns>
|
|
public static Matrix AffineTransformation2D(float scaling, float rotation, Vec2 translation)
|
|
{
|
|
Matrix result;
|
|
AffineTransformation2D(scaling, rotation, ref translation, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a 2D affine transformation matrix.
|
|
/// </summary>
|
|
/// <param name="scaling">Scaling factor.</param>
|
|
/// <param name="rotationCenter">The center of the rotation.</param>
|
|
/// <param name="rotation">The rotation of the transformation.</param>
|
|
/// <param name="translation">The translation factor of the transformation.</param>
|
|
/// <param name="result">When the method completes, contains the created affine transformation matrix.</param>
|
|
public static void AffineTransformation2D(float scaling, ref Vec2 rotationCenter, float rotation, ref Vec2 translation, out Matrix result)
|
|
{
|
|
result = Scaling(scaling, scaling, 1.0f) * Translation((Vec3)(-rotationCenter)) * RotationZ(rotation) *
|
|
Translation((Vec3)rotationCenter) * Translation((Vec3)translation);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a 2D affine transformation matrix.
|
|
/// </summary>
|
|
/// <param name="scaling">Scaling factor.</param>
|
|
/// <param name="rotationCenter">The center of the rotation.</param>
|
|
/// <param name="rotation">The rotation of the transformation.</param>
|
|
/// <param name="translation">The translation factor of the transformation.</param>
|
|
/// <returns>The created affine transformation matrix.</returns>
|
|
public static Matrix AffineTransformation2D(float scaling, Vec2 rotationCenter, float rotation, Vec2 translation)
|
|
{
|
|
Matrix result;
|
|
AffineTransformation2D(scaling, ref rotationCenter, rotation, ref translation, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a transformation matrix.
|
|
/// </summary>
|
|
/// <param name="scalingCenter">Center point of the scaling operation.</param>
|
|
/// <param name="scalingRotation">Scaling rotation amount.</param>
|
|
/// <param name="scaling">Scaling factor.</param>
|
|
/// <param name="rotationCenter">The center of the rotation.</param>
|
|
/// <param name="rotation">The rotation of the transformation.</param>
|
|
/// <param name="translation">The translation factor of the transformation.</param>
|
|
/// <param name="result">When the method completes, contains the created transformation matrix.</param>
|
|
public static void Transformation(ref Vec3 scalingCenter, ref Quaternion scalingRotation, ref Vec3 scaling, ref Vec3 rotationCenter, ref Quaternion rotation, ref Vec3 translation, out Matrix result)
|
|
{
|
|
Matrix sr = RotationQuaternion(scalingRotation);
|
|
|
|
result = Translation(-scalingCenter) * Transpose(sr) * Scaling(scaling) * sr * Translation(scalingCenter) * Translation(-rotationCenter) *
|
|
RotationQuaternion(rotation) * Translation(rotationCenter) * Translation(translation);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a transformation matrix.
|
|
/// </summary>
|
|
/// <param name="scalingCenter">Center point of the scaling operation.</param>
|
|
/// <param name="scalingRotation">Scaling rotation amount.</param>
|
|
/// <param name="scaling">Scaling factor.</param>
|
|
/// <param name="rotationCenter">The center of the rotation.</param>
|
|
/// <param name="rotation">The rotation of the transformation.</param>
|
|
/// <param name="translation">The translation factor of the transformation.</param>
|
|
/// <returns>The created transformation matrix.</returns>
|
|
public static Matrix Transformation(Vec3 scalingCenter, Quaternion scalingRotation, Vec3 scaling, Vec3 rotationCenter, Quaternion rotation, Vec3 translation)
|
|
{
|
|
Matrix result;
|
|
Transformation(ref scalingCenter, ref scalingRotation, ref scaling, ref rotationCenter, ref rotation, ref translation, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a 2D transformation matrix.
|
|
/// </summary>
|
|
/// <param name="scalingCenter">Center point of the scaling operation.</param>
|
|
/// <param name="scalingRotation">Scaling rotation amount.</param>
|
|
/// <param name="scaling">Scaling factor.</param>
|
|
/// <param name="rotationCenter">The center of the rotation.</param>
|
|
/// <param name="rotation">The rotation of the transformation.</param>
|
|
/// <param name="translation">The translation factor of the transformation.</param>
|
|
/// <param name="result">When the method completes, contains the created transformation matrix.</param>
|
|
public static void Transformation2D(ref Vec2 scalingCenter, float scalingRotation, ref Vec2 scaling, ref Vec2 rotationCenter, float rotation, ref Vec2 translation, out Matrix result)
|
|
{
|
|
result = Translation((Vec3)(-scalingCenter)) * RotationZ(-scalingRotation) * Scaling((Vec3)scaling) * RotationZ(scalingRotation) * Translation((Vec3)scalingCenter) *
|
|
Translation((Vec3)(-rotationCenter)) * RotationZ(rotation) * Translation((Vec3)rotationCenter) * Translation((Vec3)translation);
|
|
|
|
result.M33 = 1f;
|
|
result.M44 = 1f;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a 2D transformation matrix.
|
|
/// </summary>
|
|
/// <param name="scalingCenter">Center point of the scaling operation.</param>
|
|
/// <param name="scalingRotation">Scaling rotation amount.</param>
|
|
/// <param name="scaling">Scaling factor.</param>
|
|
/// <param name="rotationCenter">The center of the rotation.</param>
|
|
/// <param name="rotation">The rotation of the transformation.</param>
|
|
/// <param name="translation">The translation factor of the transformation.</param>
|
|
/// <returns>The created transformation matrix.</returns>
|
|
public static Matrix Transformation2D(Vec2 scalingCenter, float scalingRotation, Vec2 scaling, Vec2 rotationCenter, float rotation, Vec2 translation)
|
|
{
|
|
Matrix result;
|
|
Transformation2D(ref scalingCenter, scalingRotation, ref scaling, ref rotationCenter, rotation, ref translation, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Copies a nxm matrix to this instance.
|
|
/// </summary>
|
|
/// <param name="src">The source matrix.</param>
|
|
/// <param name="columns">The number of columns.</param>
|
|
/// <param name="rows">The number of rows.</param>
|
|
public unsafe void CopyMatrixFrom(float* src, int columns, int rows)
|
|
{
|
|
fixed (void* pDest = &this)
|
|
{
|
|
var dest = (float*)pDest;
|
|
for (int i = 0; i < rows; ++i)
|
|
{
|
|
for (int j = 0; j < columns; ++j)
|
|
{
|
|
dest[j] = src[j];
|
|
}
|
|
dest += 4;
|
|
src += rows;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Transposes a nmx matrix to this instance.
|
|
/// </summary>
|
|
/// <param name="src">The SRC.</param>
|
|
/// <param name="columns">The columns.</param>
|
|
/// <param name="rows">The rows.</param>
|
|
public unsafe void TransposeMatrixFrom(float* src, int columns, int rows)
|
|
{
|
|
fixed (void* pDest = &this)
|
|
{
|
|
var dest = (float*)pDest;
|
|
for (int i = 0; i < rows; ++i)
|
|
{
|
|
int sourceIndex = i;
|
|
for (int j = 0; j < columns; ++j)
|
|
{
|
|
dest[j] = src[sourceIndex];
|
|
sourceIndex += rows;
|
|
}
|
|
dest += 4;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds two matricies.
|
|
/// </summary>
|
|
/// <param name="left">The first matrix to add.</param>
|
|
/// <param name="right">The second matrix to add.</param>
|
|
/// <returns>The sum of the two matricies.</returns>
|
|
public static Matrix operator +(Matrix left, Matrix right)
|
|
{
|
|
Matrix result;
|
|
Add(ref left, ref right, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Assert a matrix (return it unchanged).
|
|
/// </summary>
|
|
/// <param name="value">The matrix to assert (unchange).</param>
|
|
/// <returns>The asserted (unchanged) matrix.</returns>
|
|
public static Matrix operator +(Matrix value)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Subtracts two matricies.
|
|
/// </summary>
|
|
/// <param name="left">The first matrix to subtract.</param>
|
|
/// <param name="right">The second matrix to subtract.</param>
|
|
/// <returns>The difference between the two matricies.</returns>
|
|
public static Matrix operator -(Matrix left, Matrix right)
|
|
{
|
|
Matrix result;
|
|
Subtract(ref left, ref right, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Negates a matrix.
|
|
/// </summary>
|
|
/// <param name="value">The matrix to negate.</param>
|
|
/// <returns>The negated matrix.</returns>
|
|
public static Matrix operator -(Matrix value)
|
|
{
|
|
Matrix result;
|
|
Negate(ref value, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scales a matrix by a given value.
|
|
/// </summary>
|
|
/// <param name="right">The matrix to scale.</param>
|
|
/// <param name="left">The amount by which to scale.</param>
|
|
/// <returns>The scaled matrix.</returns>
|
|
public static Matrix operator *(float left, Matrix right)
|
|
{
|
|
Matrix result;
|
|
Multiply(ref right, left, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scales a matrix by a given value.
|
|
/// </summary>
|
|
/// <param name="left">The matrix to scale.</param>
|
|
/// <param name="right">The amount by which to scale.</param>
|
|
/// <returns>The scaled matrix.</returns>
|
|
public static Matrix operator *(Matrix left, float right)
|
|
{
|
|
Matrix result;
|
|
Multiply(ref left, right, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Multiplies two matrices.
|
|
/// </summary>
|
|
/// <param name="left">The first matrix to multiply.</param>
|
|
/// <param name="right">The second matrix to multiply.</param>
|
|
/// <returns>The product of the two matricies.</returns>
|
|
public static Matrix operator *(Matrix left, Matrix right)
|
|
{
|
|
Matrix result;
|
|
Multiply(ref left, ref right, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scales a matrix by a given value.
|
|
/// </summary>
|
|
/// <param name="left">The matrix to scale.</param>
|
|
/// <param name="right">The amount by which to scale.</param>
|
|
/// <returns>The scaled matrix.</returns>
|
|
public static Matrix operator /(Matrix left, float right)
|
|
{
|
|
Matrix result;
|
|
Divide(ref left, right, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Divides two matricies.
|
|
/// </summary>
|
|
/// <param name="left">The first matrix to divide.</param>
|
|
/// <param name="right">The second matrix to divide.</param>
|
|
/// <returns>The quotient of the two matricies.</returns>
|
|
public static Matrix operator /(Matrix left, Matrix right)
|
|
{
|
|
Matrix result;
|
|
Divide(ref left, ref right, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests for equality between two objects.
|
|
/// </summary>
|
|
/// <param name="left">The first value to compare.</param>
|
|
/// <param name="right">The second value to compare.</param>
|
|
/// <returns><c>true</c> if <paramref name="left"/> has the same value as <paramref name="right"/>; otherwise, <c>false</c>.</returns>
|
|
public static bool operator ==(Matrix left, Matrix right)
|
|
{
|
|
return left.Equals(right);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tests for inequality between two objects.
|
|
/// </summary>
|
|
/// <param name="left">The first value to compare.</param>
|
|
/// <param name="right">The second value to compare.</param>
|
|
/// <returns><c>true</c> if <paramref name="left"/> has a different value than <paramref name="right"/>; otherwise, <c>false</c>.</returns>
|
|
public static bool operator !=(Matrix left, Matrix right)
|
|
{
|
|
return !left.Equals(right);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a <see cref="string"/> that represents this instance.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A <see cref="string"/> that represents this instance.
|
|
/// </returns>
|
|
public override string ToString()
|
|
{
|
|
return string.Format(CultureInfo.CurrentCulture, "[M11:{0} M12:{1} M13:{2} M14:{3}] [M21:{4} M22:{5} M23:{6} M24:{7}] [M31:{8} M32:{9} M33:{10} M34:{11}] [M41:{12} M42:{13} M43:{14} M44:{15}]",
|
|
M11, M12, M13, M14, M21, M22, M23, M24, M31, M32, M33, M34, M41, M42, M43, M44);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a <see cref="string"/> that represents this instance.
|
|
/// </summary>
|
|
/// <param name="format">The format.</param>
|
|
/// <returns>
|
|
/// A <see cref="string"/> that represents this instance.
|
|
/// </returns>
|
|
public string ToString(string format)
|
|
{
|
|
if (format == null)
|
|
return ToString();
|
|
|
|
return string.Format(format, CultureInfo.CurrentCulture, "[M11:{0} M12:{1} M13:{2} M14:{3}] [M21:{4} M22:{5} M23:{6} M24:{7}] [M31:{8} M32:{9} M33:{10} M34:{11}] [M41:{12} M42:{13} M43:{14} M44:{15}]",
|
|
M11.ToString(format, CultureInfo.CurrentCulture), M12.ToString(format, CultureInfo.CurrentCulture), M13.ToString(format, CultureInfo.CurrentCulture), M14.ToString(format, CultureInfo.CurrentCulture),
|
|
M21.ToString(format, CultureInfo.CurrentCulture), M22.ToString(format, CultureInfo.CurrentCulture), M23.ToString(format, CultureInfo.CurrentCulture), M24.ToString(format, CultureInfo.CurrentCulture),
|
|
M31.ToString(format, CultureInfo.CurrentCulture), M32.ToString(format, CultureInfo.CurrentCulture), M33.ToString(format, CultureInfo.CurrentCulture), M34.ToString(format, CultureInfo.CurrentCulture),
|
|
M41.ToString(format, CultureInfo.CurrentCulture), M42.ToString(format, CultureInfo.CurrentCulture), M43.ToString(format, CultureInfo.CurrentCulture), M44.ToString(format, CultureInfo.CurrentCulture));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a <see cref="string"/> that represents this instance.
|
|
/// </summary>
|
|
/// <param name="formatProvider">The format provider.</param>
|
|
/// <returns>
|
|
/// A <see cref="string"/> that represents this instance.
|
|
/// </returns>
|
|
public string ToString(IFormatProvider formatProvider)
|
|
{
|
|
return string.Format(formatProvider, "[M11:{0} M12:{1} M13:{2} M14:{3}] [M21:{4} M22:{5} M23:{6} M24:{7}] [M31:{8} M32:{9} M33:{10} M34:{11}] [M41:{12} M42:{13} M43:{14} M44:{15}]",
|
|
M11.ToString(formatProvider), M12.ToString(formatProvider), M13.ToString(formatProvider), M14.ToString(formatProvider),
|
|
M21.ToString(formatProvider), M22.ToString(formatProvider), M23.ToString(formatProvider), M24.ToString(formatProvider),
|
|
M31.ToString(formatProvider), M32.ToString(formatProvider), M33.ToString(formatProvider), M34.ToString(formatProvider),
|
|
M41.ToString(formatProvider), M42.ToString(formatProvider), M43.ToString(formatProvider), M44.ToString(formatProvider));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a <see cref="string"/> that represents this instance.
|
|
/// </summary>
|
|
/// <param name="format">The format.</param>
|
|
/// <param name="formatProvider">The format provider.</param>
|
|
/// <returns>
|
|
/// A <see cref="string"/> that represents this instance.
|
|
/// </returns>
|
|
public string ToString(string format, IFormatProvider formatProvider)
|
|
{
|
|
if (format == null)
|
|
return ToString(formatProvider);
|
|
|
|
return string.Format(format, formatProvider, "[M11:{0} M12:{1} M13:{2} M14:{3}] [M21:{4} M22:{5} M23:{6} M24:{7}] [M31:{8} M32:{9} M33:{10} M34:{11}] [M41:{12} M42:{13} M43:{14} M44:{15}]",
|
|
M11.ToString(format, formatProvider), M12.ToString(format, formatProvider), M13.ToString(format, formatProvider), M14.ToString(format, formatProvider),
|
|
M21.ToString(format, formatProvider), M22.ToString(format, formatProvider), M23.ToString(format, formatProvider), M24.ToString(format, formatProvider),
|
|
M31.ToString(format, formatProvider), M32.ToString(format, formatProvider), M33.ToString(format, formatProvider), M34.ToString(format, formatProvider),
|
|
M41.ToString(format, formatProvider), M42.ToString(format, formatProvider), M43.ToString(format, formatProvider), M44.ToString(format, formatProvider));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a hash code for this instance.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
|
|
/// </returns>
|
|
public override int GetHashCode()
|
|
{
|
|
return M11.GetHashCode() + M12.GetHashCode() + M13.GetHashCode() + M14.GetHashCode() +
|
|
M21.GetHashCode() + M22.GetHashCode() + M23.GetHashCode() + M24.GetHashCode() +
|
|
M31.GetHashCode() + M32.GetHashCode() + M33.GetHashCode() + M34.GetHashCode() +
|
|
M41.GetHashCode() + M42.GetHashCode() + M43.GetHashCode() + M44.GetHashCode();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified <see cref="math.Matrix"/> is equal to this instance.
|
|
/// </summary>
|
|
/// <param name="other">The <see cref="math.Matrix"/> to compare with this instance.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if the specified <see cref="math.Matrix"/> is equal to this instance; otherwise, <c>false</c>.
|
|
/// </returns>
|
|
public bool Equals(Matrix other)
|
|
{
|
|
return (Math.Abs(other.M11 - M11) < MathUtil.ZeroTolerance &&
|
|
Math.Abs(other.M12 - M12) < MathUtil.ZeroTolerance &&
|
|
Math.Abs(other.M13 - M13) < MathUtil.ZeroTolerance &&
|
|
Math.Abs(other.M14 - M14) < MathUtil.ZeroTolerance &&
|
|
|
|
Math.Abs(other.M21 - M21) < MathUtil.ZeroTolerance &&
|
|
Math.Abs(other.M22 - M22) < MathUtil.ZeroTolerance &&
|
|
Math.Abs(other.M23 - M23) < MathUtil.ZeroTolerance &&
|
|
Math.Abs(other.M24 - M24) < MathUtil.ZeroTolerance &&
|
|
|
|
Math.Abs(other.M31 - M31) < MathUtil.ZeroTolerance &&
|
|
Math.Abs(other.M32 - M32) < MathUtil.ZeroTolerance &&
|
|
Math.Abs(other.M33 - M33) < MathUtil.ZeroTolerance &&
|
|
Math.Abs(other.M34 - M34) < MathUtil.ZeroTolerance &&
|
|
|
|
Math.Abs(other.M41 - M41) < MathUtil.ZeroTolerance &&
|
|
Math.Abs(other.M42 - M42) < MathUtil.ZeroTolerance &&
|
|
Math.Abs(other.M43 - M43) < MathUtil.ZeroTolerance &&
|
|
Math.Abs(other.M44 - M44) < MathUtil.ZeroTolerance);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified <see cref="object"/> is equal to this instance.
|
|
/// </summary>
|
|
/// <param name="value">The <see cref="object"/> to compare with this instance.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if the specified <see cref="object"/> is equal to this instance; otherwise, <c>false</c>.
|
|
/// </returns>
|
|
public override bool Equals(object value)
|
|
{
|
|
if (value == null)
|
|
return false;
|
|
|
|
if (value.GetType() != GetType())
|
|
return false;
|
|
|
|
return Equals((Matrix)value);
|
|
}
|
|
|
|
#if SlimDX1xInterop
|
|
/// <summary>
|
|
/// Performs an implicit conversion from <see cref="math.Matrix"/> to <see cref="SlimDX.Matrix"/>.
|
|
/// </summary>
|
|
/// <param name="value">The value.</param>
|
|
/// <returns>The result of the conversion.</returns>
|
|
public static implicit operator SlimDX.Matrix(Matrix value)
|
|
{
|
|
return new SlimDX.Matrix()
|
|
{
|
|
M11 = value.M11, M12 = value.M12, M13 = value.M13, M14 = value.M14,
|
|
M21 = value.M21, M22 = value.M22, M23 = value.M23, M24 = value.M24,
|
|
M31 = value.M31, M32 = value.M32, M33 = value.M33, M34 = value.M34,
|
|
M41 = value.M41, M42 = value.M42, M43 = value.M43, M44 = value.M44
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs an implicit conversion from <see cref="SlimDX.Matrix"/> to <see cref="math.Matrix"/>.
|
|
/// </summary>
|
|
/// <param name="value">The value.</param>
|
|
/// <returns>The result of the conversion.</returns>
|
|
public static implicit operator Matrix(SlimDX.Matrix value)
|
|
{
|
|
return new Matrix()
|
|
{
|
|
M11 = value.M11, M12 = value.M12, M13 = value.M13, M14 = value.M14,
|
|
M21 = value.M21, M22 = value.M22, M23 = value.M23, M24 = value.M24,
|
|
M31 = value.M31, M32 = value.M32, M33 = value.M33, M34 = value.M34,
|
|
M41 = value.M41, M42 = value.M42, M43 = value.M43, M44 = value.M44
|
|
};
|
|
}
|
|
#endif
|
|
|
|
#if WPFInterop
|
|
/// <summary>
|
|
/// Performs an implicit conversion from <see cref="math.Matrix"/> to <see cref="System.Windows.Media.Media3D.Matrix3D"/>.
|
|
/// </summary>
|
|
/// <param name="value">The value.</param>
|
|
/// <returns>The result of the conversion.</returns>
|
|
public static implicit operator System.Windows.Media.Media3D.Matrix3D(Matrix value)
|
|
{
|
|
return new System.Windows.Media.Media3D.Matrix3D()
|
|
{
|
|
M11 = value.M11, M12 = value.M12, M13 = value.M13, M14 = value.M14,
|
|
M21 = value.M21, M22 = value.M22, M23 = value.M23, M24 = value.M24,
|
|
M31 = value.M31, M32 = value.M32, M33 = value.M33, M34 = value.M34,
|
|
OffsetX = value.M41, OffsetY = value.M42, OffsetZ = value.M43, M44 = value.M44
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs an explicit conversion from <see cref="System.Windows.Media.Media3D.Matrix3D"/> to <see cref="math.Matrix"/>.
|
|
/// </summary>
|
|
/// <param name="value">The value.</param>
|
|
/// <returns>The result of the conversion.</returns>
|
|
public static explicit operator Matrix(System.Windows.Media.Media3D.Matrix3D value)
|
|
{
|
|
return new Matrix()
|
|
{
|
|
M11 = (float)value.M11, M12 = (float)value.M12, M13 = (float)value.M13, M14 = (float)value.M14,
|
|
M21 = (float)value.M21, M22 = (float)value.M22, M23 = (float)value.M23, M24 = (float)value.M24,
|
|
M31 = (float)value.M31, M32 = (float)value.M32, M33 = (float)value.M33, M34 = (float)value.M34,
|
|
M41 = (float)value.OffsetX, M42 = (float)value.OffsetY, M43 = (float)value.OffsetZ, M44 = (float)value.M44
|
|
};
|
|
}
|
|
#endif
|
|
|
|
#if XnaInterop
|
|
/// <summary>
|
|
/// Performs an implicit conversion from <see cref="math.Matrix"/> to <see cref="Microsoft.Xna.Framework.Matrix"/>.
|
|
/// </summary>
|
|
/// <param name="value">The value.</param>
|
|
/// <returns>The result of the conversion.</returns>
|
|
public static implicit operator Microsoft.Xna.Framework.Matrix(Matrix value)
|
|
{
|
|
return new Microsoft.Xna.Framework.Matrix()
|
|
{
|
|
M11 = value.M11, M12 = value.M12, M13 = value.M13, M14 = value.M14,
|
|
M21 = value.M21, M22 = value.M22, M23 = value.M23, M24 = value.M24,
|
|
M31 = value.M31, M32 = value.M32, M33 = value.M33, M34 = value.M34,
|
|
M41 = value.M41, M42 = value.M42, M43 = value.M43, M44 = value.M44
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs an implicit conversion from <see cref="Microsoft.Xna.Framework.Matrix"/> to <see cref="math.Matrix"/>.
|
|
/// </summary>
|
|
/// <param name="value">The value.</param>
|
|
/// <returns>The result of the conversion.</returns>
|
|
public static implicit operator Matrix(Microsoft.Xna.Framework.Matrix value)
|
|
{
|
|
return new Matrix()
|
|
{
|
|
M11 = value.M11, M12 = value.M12, M13 = value.M13, M14 = value.M14,
|
|
M21 = value.M21, M22 = value.M22, M23 = value.M23, M24 = value.M24,
|
|
M31 = value.M31, M32 = value.M32, M33 = value.M33, M34 = value.M34,
|
|
M41 = value.M41, M42 = value.M42, M43 = value.M43, M44 = value.M44
|
|
};
|
|
}
|
|
#endif
|
|
}
|
|
}
|