-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathMatrix4x4.cs
291 lines (237 loc) · 13 KB
/
Matrix4x4.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using SNMatrix4x4 = System.Numerics.Matrix4x4;
using static System.Runtime.CompilerServices.MethodImplOptions;
namespace Plato
{
[DataContract]
public partial struct Matrix4x4
{
[DataMember] public readonly SNMatrix4x4 Value;
// --------------------------------------------------------------------------------
// Constructor
// --------------------------------------------------------------------------------
[MethodImpl(AggressiveInlining)]
public Matrix4x4(SNMatrix4x4 matrix) => Value = matrix;
[MethodImpl(AggressiveInlining)]
public Matrix4x4(Vector4 row1, Vector4 row2, Vector4 row3, Vector4 row4)
: this(row1.X, row1.Y, row1.Z, row1.W,
row2.X, row2.Y, row2.Z, row2.W,
row3.X, row3.Y, row3.Z, row3.W,
row4.X, row4.Y, row4.Z, row4.W)
{ }
[MethodImpl(AggressiveInlining)]
public Matrix4x4(
Number m11, Number m12, Number m13, Number m14,
Number m21, Number m22, Number m23, Number m24,
Number m31, Number m32, Number m33, Number m34,
Number m41, Number m42, Number m43, Number m44)
=> Value = new SNMatrix4x4(m11, m12, m13, m14,
m21, m22, m23, m24,
m31, m32, m33, m34,
m41, m42, m43, m44);
// --------------------------------------------------------------------------------
// Convert to/from System.Numerics.Matrix4x4
// --------------------------------------------------------------------------------
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 FromSystem(SNMatrix4x4 sysMat)
=> Unsafe.As<SNMatrix4x4, Matrix4x4>(ref sysMat);
[MethodImpl(AggressiveInlining)]
public static implicit operator Matrix4x4(SNMatrix4x4 m)
=> FromSystem(m);
[MethodImpl(AggressiveInlining)]
public static implicit operator SNMatrix4x4(Matrix4x4 m)
=> m.Value;
//-------------------------------------------------------------------------------------
// Properties
//-------------------------------------------------------------------------------------
public Vector4 Row1 { [MethodImpl(AggressiveInlining)] get => new(Value.M11, Value.M12, Value.M13, Value.M14); }
public Vector4 Row2 { [MethodImpl(AggressiveInlining)] get => new(Value.M21, Value.M22, Value.M23, Value.M24); }
public Vector4 Row3 { [MethodImpl(AggressiveInlining)] get => new(Value.M31, Value.M32, Value.M33, Value.M34); }
public Vector4 Row4 { [MethodImpl(AggressiveInlining)] get => new(Value.M41, Value.M42, Value.M43, Value.M44); }
//-------------------------------------------------------------------------------------
// Immutable "setters"
//-------------------------------------------------------------------------------------
[MethodImpl(AggressiveInlining)]
public Matrix4x4 WithRow1(Vector4 v) => new(v, Row2, Row3, Row4);
[MethodImpl(AggressiveInlining)]
public Matrix4x4 WithRow2(Vector4 v) => new(Row1, v, Row3, Row4);
[MethodImpl(AggressiveInlining)]
public Matrix4x4 WithRow3(Vector4 v) => new(Row1, Row2, v, Row4);
[MethodImpl(AggressiveInlining)]
public Matrix4x4 WithRow4(Vector4 v) => new(Row1, Row2, Row3, v);
// --------------------------------------------------------------------------------
// Operators (forward to System.Numerics)
// --------------------------------------------------------------------------------
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 operator +(Matrix4x4 value1, Matrix4x4 value2)
=> value1.Value + value2.Value;
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 operator -(Matrix4x4 value1, Matrix4x4 value2)
=> value1.Value - value2.Value;
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 operator *(Matrix4x4 value1, Matrix4x4 value2)
=> value1.Value * value2.Value;
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 operator *(Matrix4x4 value1, Number f)
=> value1.Value * f;
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 operator *(Number f, Matrix4x4 value1)
=> value1.Value * f;
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 operator /(Matrix4x4 value1, Number f)
=> value1.Value * f.ReciprocalEstimate;
// --------------------------------------------------------------------------------
// One-to-one static methods (Add, Multiply, Subtract, etc.)
// --------------------------------------------------------------------------------
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 Add(Matrix4x4 value1, Matrix4x4 value2)
=> SNMatrix4x4.Add(value1.Value, value2.Value);
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 Subtract(Matrix4x4 value1, Matrix4x4 value2)
=> SNMatrix4x4.Subtract(value1.Value, value2.Value);
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 Multiply(Matrix4x4 value1, Matrix4x4 value2)
=> SNMatrix4x4.Multiply(value1.Value, value2.Value);
// --------------------------------------------------------------------------------
// Example "Create*" static methods (forwarded)
// --------------------------------------------------------------------------------
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreateTranslation(Vector3 position)
=> SNMatrix4x4.CreateTranslation(position);
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreateScale(Number scale)
=> SNMatrix4x4.CreateScale(scale);
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreateScale(Number xScale, Number yScale, Number zScale)
=> SNMatrix4x4.CreateScale(xScale, yScale, zScale);
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreateRotationX(Angle angle)
=> SNMatrix4x4.CreateRotationX(angle);
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreateRotationY(Angle angle)
=> SNMatrix4x4.CreateRotationY(angle);
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreateRotationZ(Angle angle)
=> SNMatrix4x4.CreateRotationZ(angle);
// --------------------------------------------------------------------------------
// Decompose, Determinant, Transpose, etc. (common instance methods)
// --------------------------------------------------------------------------------
/// <summary>
/// Attempts to extract scale, rotation (as a <see cref="Quaternion"/>),
/// and translation from Value matrix.
/// </summary>
public (Vector3, Quaternion, Vector3, Boolean) Decompose
{
[MethodImpl(AggressiveInlining)]
get
{
var success = SNMatrix4x4.Decompose(Value, out var scl, out var rot, out var trans);
return (trans, rot, scl, success);
}
}
public Number Determinant
{
[MethodImpl(AggressiveInlining)] get => Value.GetDeterminant();
}
public Matrix4x4 Transpose
{
[MethodImpl(AggressiveInlining)] get => SNMatrix4x4.Transpose(Value);
}
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 Lerp(Matrix4x4 matrix1, Matrix4x4 matrix2, Number amount)
=> SNMatrix4x4.Lerp(matrix1.Value, matrix2.Value, amount);
public Matrix4x4 Invert
{
[MethodImpl(AggressiveInlining)]
get
{
var success = SNMatrix4x4.Invert(Value, out var result);
if (!success) throw new InvalidOperationException("Non-invertible matrix ");
return result;
}
}
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreatePerspectiveFieldOfView(Number fieldOfView, Number aspectRatio, Number nearPlane, Number farPlane)
=> SNMatrix4x4.CreatePerspectiveFieldOfView(fieldOfView, aspectRatio, nearPlane, farPlane);
/// <summary>
/// Creates a spherical billboard that rotates around a specified object position.
/// </summary>
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreateBillboard(Vector3 objectPosition, Vector3 cameraPosition, Vector3 cameraUpVector, Vector3 cameraForwardVector)
=> SNMatrix4x4.CreateBillboard(
objectPosition, cameraPosition, cameraUpVector, cameraForwardVector);
/// <summary>
/// Creates a cylindrical billboard that rotates around a specified axis.
/// </summary>
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreateConstrainedBillboard(Vector3 objectPosition, Vector3 cameraPosition, Vector3 rotateAxis, Vector3 cameraForwardVector, Vector3 objectForwardVector)
=> SNMatrix4x4.CreateConstrainedBillboard(objectPosition, cameraPosition, rotateAxis, cameraForwardVector, objectForwardVector);
/// <summary>
/// Creates a rotation matrix from a specified axis and angle.
/// </summary>
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreateFromAxisAngle(Vector3 axis, Angle angle)
=> SNMatrix4x4.CreateFromAxisAngle(axis, angle);
/// <summary>
/// Creates a rotation matrix from a quaternion.
/// </summary>
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreateFromQuaternion(Quaternion quaternion)
=> SNMatrix4x4.CreateFromQuaternion(quaternion);
/// <summary>
/// Creates a rotation matrix from yaw, pitch, and roll values (in radians).
/// </summary>
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreateFromYawPitchRoll(Angle yaw, Angle pitch, Angle roll)
=> SNMatrix4x4.CreateFromYawPitchRoll(yaw, pitch, roll);
/// <summary>
/// Creates a view matrix for a camera looking at a target.
/// </summary>
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreateLookAt(Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector)
=> SNMatrix4x4.CreateLookAt(cameraPosition, cameraTarget, cameraUpVector);
/// <summary>
/// Creates an orthographic projection matrix.
/// </summary>
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreateOrthographic(Number width, Number height, Number zNearPlane, Number zFarPlane)
=> SNMatrix4x4.CreateOrthographic(width, height, zNearPlane, zFarPlane);
/// <summary>
/// Creates a customized orthographic projection matrix.
/// </summary>
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreateOrthographicOffCenter(Number left, Number right, Number bottom, Number top, Number zNearPlane, Number zFarPlane)
=> SNMatrix4x4.CreateOrthographicOffCenter(left, right, bottom, top, zNearPlane, zFarPlane);
/// <summary>
/// Creates a perspective projection matrix based on a width and height.
/// </summary>
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreatePerspective(Number width, Number height, Number nearPlaneDistance, Number farPlaneDistance)
=> SNMatrix4x4.CreatePerspective(width, height, nearPlaneDistance, farPlaneDistance);
/// <summary>
/// Creates a customized perspective projection matrix.
/// </summary>
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreatePerspectiveOffCenter(Number left, Number right, Number bottom, Number top, Number nearPlaneDistance, Number farPlaneDistance)
=> SNMatrix4x4.CreatePerspectiveOffCenter(left, right, bottom, top, nearPlaneDistance, farPlaneDistance);
/// <summary>
/// Creates a matrix that reflects coordinates about a specified plane.
/// </summary>
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreateReflection(Plane value)
=> SNMatrix4x4.CreateReflection(value);
/// <summary>
/// Creates a matrix that flattens geometry into a specified plane as if casting a shadow from a light source.
/// </summary>
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreateShadow(Vector3 lightDirection, Plane plane)
=> SNMatrix4x4.CreateShadow(lightDirection, plane);
/// <summary>
/// Creates a world matrix with the specified parameters.
/// </summary>
[MethodImpl(AggressiveInlining)]
public static Matrix4x4 CreateWorld(Vector3 position, Vector3 forward, Vector3 up)
=> SNMatrix4x4.CreateWorld(position, forward, up);
}
}