A game about forced loneliness, made by TACStudios
1using System.Runtime.CompilerServices;
2using static Unity.Mathematics.math;
3
4namespace Unity.Mathematics
5{
6 public partial struct float2x2
7 {
8 /// <summary>
9 /// Computes a float2x2 matrix representing a counter-clockwise rotation by an angle in radians.
10 /// </summary>
11 /// <remarks>
12 /// A positive rotation angle will produce a counter-clockwise rotation and a negative rotation angle will
13 /// produce a clockwise rotation.
14 /// </remarks>
15 /// <param name="angle">Rotation angle in radians.</param>
16 /// <returns>Returns the 2x2 rotation matrix.</returns>
17 [MethodImpl(MethodImplOptions.AggressiveInlining)]
18 public static float2x2 Rotate(float angle)
19 {
20 float s, c;
21 sincos(angle, out s, out c);
22 return float2x2(c, -s,
23 s, c);
24 }
25
26 /// <summary>Returns a float2x2 matrix representing a uniform scaling of both axes by s.</summary>
27 /// <param name="s">The scaling factor.</param>
28 /// <returns>The float2x2 matrix representing uniform scale by s.</returns>
29 [MethodImpl(MethodImplOptions.AggressiveInlining)]
30 public static float2x2 Scale(float s)
31 {
32 return float2x2(s, 0.0f,
33 0.0f, s);
34 }
35
36 /// <summary>Returns a float2x2 matrix representing a non-uniform axis scaling by x and y.</summary>
37 /// <param name="x">The x-axis scaling factor.</param>
38 /// <param name="y">The y-axis scaling factor.</param>
39 /// <returns>The float2x2 matrix representing a non-uniform scale.</returns>
40 [MethodImpl(MethodImplOptions.AggressiveInlining)]
41 public static float2x2 Scale(float x, float y)
42 {
43 return float2x2(x, 0.0f,
44 0.0f, y);
45 }
46
47 /// <summary>Returns a float2x2 matrix representing a non-uniform axis scaling by the components of the float2 vector v.</summary>
48 /// <param name="v">The float2 containing the x and y axis scaling factors.</param>
49 /// <returns>The float2x2 matrix representing a non-uniform scale.</returns>
50 [MethodImpl(MethodImplOptions.AggressiveInlining)]
51 public static float2x2 Scale(float2 v)
52 {
53 return Scale(v.x, v.y);
54 }
55 }
56
57 public partial struct float3x3
58 {
59 /// <summary>
60 /// Constructs a float3x3 from the upper left 3x3 of a float4x4.
61 /// </summary>
62 /// <param name="f4x4"><see cref="float4x4"/> to extract a float3x3 from.</param>
63 public float3x3(float4x4 f4x4)
64 {
65 c0 = f4x4.c0.xyz;
66 c1 = f4x4.c1.xyz;
67 c2 = f4x4.c2.xyz;
68 }
69
70 /// <summary>Constructs a float3x3 matrix from a unit quaternion.</summary>
71 /// <param name="q">The quaternion rotation.</param>
72 public float3x3(quaternion q)
73 {
74 float4 v = q.value;
75 float4 v2 = v + v;
76
77 uint3 npn = uint3(0x80000000, 0x00000000, 0x80000000);
78 uint3 nnp = uint3(0x80000000, 0x80000000, 0x00000000);
79 uint3 pnn = uint3(0x00000000, 0x80000000, 0x80000000);
80 c0 = v2.y * asfloat(asuint(v.yxw) ^ npn) - v2.z * asfloat(asuint(v.zwx) ^ pnn) + float3(1, 0, 0);
81 c1 = v2.z * asfloat(asuint(v.wzy) ^ nnp) - v2.x * asfloat(asuint(v.yxw) ^ npn) + float3(0, 1, 0);
82 c2 = v2.x * asfloat(asuint(v.zwx) ^ pnn) - v2.y * asfloat(asuint(v.wzy) ^ nnp) + float3(0, 0, 1);
83 }
84
85 /// <summary>
86 /// Returns a float3x3 matrix representing a rotation around a unit axis by an angle in radians.
87 /// The rotation direction is clockwise when looking along the rotation axis towards the origin.
88 /// </summary>
89 /// <param name="axis">The rotation axis.</param>
90 /// <param name="angle">The angle of rotation in radians.</param>
91 /// <returns>The float3x3 matrix representing the rotation around an axis.</returns>
92 [MethodImpl(MethodImplOptions.AggressiveInlining)]
93 public static float3x3 AxisAngle(float3 axis, float angle)
94 {
95 float sina, cosa;
96 math.sincos(angle, out sina, out cosa);
97
98 float3 u = axis;
99 float3 u_yzx = u.yzx;
100 float3 u_zxy = u.zxy;
101 float3 u_inv_cosa = u - u * cosa; // u * (1.0f - cosa);
102 float4 t = float4(u * sina, cosa);
103
104 uint3 ppn = uint3(0x00000000, 0x00000000, 0x80000000);
105 uint3 npp = uint3(0x80000000, 0x00000000, 0x00000000);
106 uint3 pnp = uint3(0x00000000, 0x80000000, 0x00000000);
107
108 return float3x3(
109 u.x * u_inv_cosa + asfloat(asuint(t.wzy) ^ ppn),
110 u.y * u_inv_cosa + asfloat(asuint(t.zwx) ^ npp),
111 u.z * u_inv_cosa + asfloat(asuint(t.yxw) ^ pnp)
112 );
113 /*
114 return float3x3(
115 cosa + u.x * u.x * (1.0f - cosa), u.y * u.x * (1.0f - cosa) - u.z * sina, u.z * u.x * (1.0f - cosa) + u.y * sina,
116 u.x * u.y * (1.0f - cosa) + u.z * sina, cosa + u.y * u.y * (1.0f - cosa), u.y * u.z * (1.0f - cosa) - u.x * sina,
117 u.x * u.z * (1.0f - cosa) - u.y * sina, u.y * u.z * (1.0f - cosa) + u.x * sina, cosa + u.z * u.z * (1.0f - cosa)
118 );
119 */
120 }
121
122 /// <summary>
123 /// Returns a float3x3 rotation matrix constructed by first performing a rotation around the x-axis, then the y-axis and finally the z-axis.
124 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
125 /// </summary>
126 /// <param name="xyz">A float3 vector containing the rotation angles around the x-, y- and z-axis measures in radians.</param>
127 /// <returns>The float3x3 rotation matrix representing the rotation by Euler angles in x-y-z order.</returns>
128 [MethodImpl(MethodImplOptions.AggressiveInlining)]
129 public static float3x3 EulerXYZ(float3 xyz)
130 {
131 // return mul(rotateZ(xyz.z), mul(rotateY(xyz.y), rotateX(xyz.x)));
132 float3 s, c;
133 sincos(xyz, out s, out c);
134 return float3x3(
135 c.y * c.z, c.z * s.x * s.y - c.x * s.z, c.x * c.z * s.y + s.x * s.z,
136 c.y * s.z, c.x * c.z + s.x * s.y * s.z, c.x * s.y * s.z - c.z * s.x,
137 -s.y, c.y * s.x, c.x * c.y
138 );
139 }
140
141 /// <summary>
142 /// Returns a float3x3 rotation matrix constructed by first performing a rotation around the x-axis, then the z-axis and finally the y-axis.
143 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
144 /// </summary>
145 /// <param name="xyz">A float3 vector containing the rotation angles around the x-, y- and z-axis measures in radians.</param>
146 /// <returns>The float3x3 rotation matrix representing the rotation by Euler angles in x-z-y order.</returns>
147 [MethodImpl(MethodImplOptions.AggressiveInlining)]
148 public static float3x3 EulerXZY(float3 xyz)
149 {
150 // return mul(rotateY(xyz.y), mul(rotateZ(xyz.z), rotateX(xyz.x))); }
151 float3 s, c;
152 sincos(xyz, out s, out c);
153 return float3x3(
154 c.y * c.z, s.x * s.y - c.x * c.y * s.z, c.x * s.y + c.y * s.x * s.z,
155 s.z, c.x * c.z, -c.z * s.x,
156 -c.z * s.y, c.y * s.x + c.x * s.y * s.z, c.x * c.y - s.x * s.y * s.z
157 );
158 }
159
160 /// <summary>
161 /// Returns a float3x3 rotation matrix constructed by first performing a rotation around the y-axis, then the x-axis and finally the z-axis.
162 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
163 /// </summary>
164 /// <param name="xyz">A float3 vector containing the rotation angles around the x-, y- and z-axis measures in radians.</param>
165 /// <returns>The float3x3 rotation matrix representing the rotation by Euler angles in y-x-z order.</returns>
166 [MethodImpl(MethodImplOptions.AggressiveInlining)]
167 public static float3x3 EulerYXZ(float3 xyz)
168 {
169 // return mul(rotateZ(xyz.z), mul(rotateX(xyz.x), rotateY(xyz.y)));
170 float3 s, c;
171 sincos(xyz, out s, out c);
172 return float3x3(
173 c.y * c.z - s.x * s.y * s.z, -c.x * s.z, c.z * s.y + c.y * s.x * s.z,
174 c.z * s.x * s.y + c.y * s.z, c.x * c.z, s.y * s.z - c.y * c.z * s.x,
175 -c.x * s.y, s.x, c.x * c.y
176 );
177 }
178
179 /// <summary>
180 /// Returns a float3x3 rotation matrix constructed by first performing a rotation around the y-axis, then the z-axis and finally the x-axis.
181 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
182 /// </summary>
183 /// <param name="xyz">A float3 vector containing the rotation angles around the x-, y- and z-axis measures in radians.</param>
184 /// <returns>The float3x3 rotation matrix representing the rotation by Euler angles in y-z-x order.</returns>
185 [MethodImpl(MethodImplOptions.AggressiveInlining)]
186 public static float3x3 EulerYZX(float3 xyz)
187 {
188 // return mul(rotateX(xyz.x), mul(rotateZ(xyz.z), rotateY(xyz.y)));
189 float3 s, c;
190 sincos(xyz, out s, out c);
191 return float3x3(
192 c.y * c.z, -s.z, c.z * s.y,
193 s.x * s.y + c.x * c.y * s.z, c.x * c.z, c.x * s.y * s.z - c.y * s.x,
194 c.y * s.x * s.z - c.x * s.y, c.z * s.x, c.x * c.y + s.x * s.y * s.z
195 );
196 }
197
198 /// <summary>
199 /// Returns a float3x3 rotation matrix constructed by first performing a rotation around the z-axis, then the x-axis and finally the y-axis.
200 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
201 /// This is the default order rotation order in Unity.
202 /// </summary>
203 /// <param name="xyz">A float3 vector containing the rotation angles around the x-, y- and z-axis measures in radians.</param>
204 /// <returns>The float3x3 rotation matrix representing the rotation by Euler angles in z-x-y order.</returns>
205 [MethodImpl(MethodImplOptions.AggressiveInlining)]
206 public static float3x3 EulerZXY(float3 xyz)
207 {
208 // return mul(rotateY(xyz.y), mul(rotateX(xyz.x), rotateZ(xyz.z)));
209 float3 s, c;
210 sincos(xyz, out s, out c);
211 return float3x3(
212 c.y * c.z + s.x * s.y * s.z, c.z * s.x * s.y - c.y * s.z, c.x * s.y,
213 c.x * s.z, c.x * c.z, -s.x,
214 c.y * s.x * s.z - c.z * s.y, c.y * c.z * s.x + s.y * s.z, c.x * c.y
215 );
216 }
217
218 /// <summary>
219 /// Returns a float3x3 rotation matrix constructed by first performing a rotation around the z-axis, then the y-axis and finally the x-axis.
220 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
221 /// </summary>
222 /// <param name="xyz">A float3 vector containing the rotation angles around the x-, y- and z-axis measures in radians.</param>
223 /// <returns>The float3x3 rotation matrix representing the rotation by Euler angles in z-y-x order.</returns>
224 [MethodImpl(MethodImplOptions.AggressiveInlining)]
225 public static float3x3 EulerZYX(float3 xyz)
226 {
227 // return mul(rotateX(xyz.x), mul(rotateY(xyz.y), rotateZ(xyz.z)));
228 float3 s, c;
229 sincos(xyz, out s, out c);
230 return float3x3(
231 c.y * c.z, -c.y * s.z, s.y,
232 c.z * s.x * s.y + c.x * s.z, c.x * c.z - s.x * s.y * s.z, -c.y * s.x,
233 s.x * s.z - c.x * c.z * s.y, c.z * s.x + c.x * s.y * s.z, c.x * c.y
234 );
235 }
236
237 /// <summary>
238 /// Returns a float3x3 rotation matrix constructed by first performing a rotation around the x-axis, then the y-axis and finally the z-axis.
239 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
240 /// </summary>
241 /// <param name="x">The rotation angle around the x-axis in radians.</param>
242 /// <param name="y">The rotation angle around the y-axis in radians.</param>
243 /// <param name="z">The rotation angle around the z-axis in radians.</param>
244 /// <returns>The float3x3 rotation matrix representing the rotation by Euler angles in x-y-z order.</returns>
245 [MethodImpl(MethodImplOptions.AggressiveInlining)]
246 public static float3x3 EulerXYZ(float x, float y, float z) { return EulerXYZ(float3(x, y, z)); }
247
248 /// <summary>
249 /// Returns a float3x3 rotation matrix constructed by first performing a rotation around the x-axis, then the z-axis and finally the y-axis.
250 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
251 /// </summary>
252 /// <param name="x">The rotation angle around the x-axis in radians.</param>
253 /// <param name="y">The rotation angle around the y-axis in radians.</param>
254 /// <param name="z">The rotation angle around the z-axis in radians.</param>
255 /// <returns>The float3x3 rotation matrix representing the rotation by Euler angles in x-z-y order.</returns>
256 [MethodImpl(MethodImplOptions.AggressiveInlining)]
257 public static float3x3 EulerXZY(float x, float y, float z) { return EulerXZY(float3(x, y, z)); }
258
259 /// <summary>
260 /// Returns a float3x3 rotation matrix constructed by first performing a rotation around the y-axis, then the x-axis and finally the z-axis.
261 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
262 /// </summary>
263 /// <param name="x">The rotation angle around the x-axis in radians.</param>
264 /// <param name="y">The rotation angle around the y-axis in radians.</param>
265 /// <param name="z">The rotation angle around the z-axis in radians.</param>
266 /// <returns>The float3x3 rotation matrix representing the rotation by Euler angles in y-x-z order.</returns>
267 [MethodImpl(MethodImplOptions.AggressiveInlining)]
268 public static float3x3 EulerYXZ(float x, float y, float z) { return EulerYXZ(float3(x, y, z)); }
269
270 /// <summary>
271 /// Returns a float3x3 rotation matrix constructed by first performing a rotation around the y-axis, then the z-axis and finally the x-axis.
272 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
273 /// </summary>
274 /// <param name="x">The rotation angle around the x-axis in radians.</param>
275 /// <param name="y">The rotation angle around the y-axis in radians.</param>
276 /// <param name="z">The rotation angle around the z-axis in radians.</param>
277 /// <returns>The float3x3 rotation matrix representing the rotation by Euler angles in y-z-x order.</returns>
278 [MethodImpl(MethodImplOptions.AggressiveInlining)]
279 public static float3x3 EulerYZX(float x, float y, float z) { return EulerYZX(float3(x, y, z)); }
280
281 /// <summary>
282 /// Returns a float3x3 rotation matrix constructed by first performing a rotation around the z-axis, then the x-axis and finally the y-axis.
283 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
284 /// This is the default order rotation order in Unity.
285 /// </summary>
286 /// <param name="x">The rotation angle around the x-axis in radians.</param>
287 /// <param name="y">The rotation angle around the y-axis in radians.</param>
288 /// <param name="z">The rotation angle around the z-axis in radians.</param>
289 /// <returns>The float3x3 rotation matrix representing the rotation by Euler angles in z-x-y order.</returns>
290 [MethodImpl(MethodImplOptions.AggressiveInlining)]
291 public static float3x3 EulerZXY(float x, float y, float z) { return EulerZXY(float3(x, y, z)); }
292
293 /// <summary>
294 /// Returns a float3x3 rotation matrix constructed by first performing a rotation around the z-axis, then the y-axis and finally the x-axis.
295 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
296 /// </summary>
297 /// <param name="x">The rotation angle around the x-axis in radians.</param>
298 /// <param name="y">The rotation angle around the y-axis in radians.</param>
299 /// <param name="z">The rotation angle around the z-axis in radians.</param>
300 /// <returns>The float3x3 rotation matrix representing the rotation by Euler angles in z-y-x order.</returns>
301 [MethodImpl(MethodImplOptions.AggressiveInlining)]
302 public static float3x3 EulerZYX(float x, float y, float z) { return EulerZYX(float3(x, y, z)); }
303
304 /// <summary>
305 /// Returns a float3x3 rotation matrix constructed by first performing 3 rotations around the principal axes in a given order.
306 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
307 /// When the rotation order is known at compile time, it is recommended for performance reasons to use specific
308 /// Euler rotation constructors such as EulerZXY(...).
309 /// </summary>
310 /// <param name="xyz">A float3 vector containing the rotation angles around the x-, y- and z-axis measures in radians.</param>
311 /// <param name="order">The order in which the rotations are applied.</param>
312 /// <returns>The float3x3 rotation matrix representing the rotation by Euler angles in the given order.</returns>
313 [MethodImpl(MethodImplOptions.AggressiveInlining)]
314 public static float3x3 Euler(float3 xyz, RotationOrder order = RotationOrder.Default)
315 {
316 switch (order)
317 {
318 case RotationOrder.XYZ:
319 return EulerXYZ(xyz);
320 case RotationOrder.XZY:
321 return EulerXZY(xyz);
322 case RotationOrder.YXZ:
323 return EulerYXZ(xyz);
324 case RotationOrder.YZX:
325 return EulerYZX(xyz);
326 case RotationOrder.ZXY:
327 return EulerZXY(xyz);
328 case RotationOrder.ZYX:
329 return EulerZYX(xyz);
330 default:
331 return float3x3.identity;
332 }
333 }
334
335 /// <summary>
336 /// Returns a float3x3 rotation matrix constructed by first performing 3 rotations around the principal axes in a given order.
337 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
338 /// When the rotation order is known at compile time, it is recommended for performance reasons to use specific
339 /// Euler rotation constructors such as EulerZXY(...).
340 /// </summary>
341 /// <param name="x">The rotation angle around the x-axis in radians.</param>
342 /// <param name="y">The rotation angle around the y-axis in radians.</param>
343 /// <param name="z">The rotation angle around the z-axis in radians.</param>
344 /// <param name="order">The order in which the rotations are applied.</param>
345 /// <returns>The float3x3 rotation matrix representing the rotation by Euler angles in the given order.</returns>
346 [MethodImpl(MethodImplOptions.AggressiveInlining)]
347 public static float3x3 Euler(float x, float y, float z, RotationOrder order = RotationOrder.Default)
348 {
349 return Euler(float3(x, y, z), order);
350 }
351
352 /// <summary>Returns a float3x3 matrix that rotates around the x-axis by a given number of radians.</summary>
353 /// <param name="angle">The clockwise rotation angle when looking along the x-axis towards the origin in radians.</param>
354 /// <returns>The float3x3 rotation matrix representing a rotation around the x-axis.</returns>
355 [MethodImpl(MethodImplOptions.AggressiveInlining)]
356 public static float3x3 RotateX(float angle)
357 {
358 // {{1, 0, 0}, {0, c_0, -s_0}, {0, s_0, c_0}}
359 float s, c;
360 sincos(angle, out s, out c);
361 return float3x3(1.0f, 0.0f, 0.0f,
362 0.0f, c, -s,
363 0.0f, s, c);
364 }
365
366 /// <summary>Returns a float3x3 matrix that rotates around the y-axis by a given number of radians.</summary>
367 /// <param name="angle">The clockwise rotation angle when looking along the y-axis towards the origin in radians.</param>
368 /// <returns>The float3x3 rotation matrix representing a rotation around the y-axis.</returns>
369 [MethodImpl(MethodImplOptions.AggressiveInlining)]
370 public static float3x3 RotateY(float angle)
371 {
372 // {{c_1, 0, s_1}, {0, 1, 0}, {-s_1, 0, c_1}}
373 float s, c;
374 sincos(angle, out s, out c);
375 return float3x3(c, 0.0f, s,
376 0.0f, 1.0f, 0.0f,
377 -s, 0.0f, c);
378 }
379
380 /// <summary>Returns a float3x3 matrix that rotates around the z-axis by a given number of radians.</summary>
381 /// <param name="angle">The clockwise rotation angle when looking along the z-axis towards the origin in radians.</param>
382 /// <returns>The float3x3 rotation matrix representing a rotation around the z-axis.</returns>
383 [MethodImpl(MethodImplOptions.AggressiveInlining)]
384 public static float3x3 RotateZ(float angle)
385 {
386 // {{c_2, -s_2, 0}, {s_2, c_2, 0}, {0, 0, 1}}
387 float s, c;
388 sincos(angle, out s, out c);
389 return float3x3(c, -s, 0.0f,
390 s, c, 0.0f,
391 0.0f, 0.0f, 1.0f);
392 }
393
394 /// <summary>Returns a float3x3 matrix representing a uniform scaling of all axes by s.</summary>
395 /// <param name="s">The uniform scaling factor.</param>
396 /// <returns>The float3x3 matrix representing a uniform scale.</returns>
397 [MethodImpl(MethodImplOptions.AggressiveInlining)]
398 public static float3x3 Scale(float s)
399 {
400 return float3x3(s, 0.0f, 0.0f,
401 0.0f, s, 0.0f,
402 0.0f, 0.0f, s);
403 }
404
405 /// <summary>Returns a float3x3 matrix representing a non-uniform axis scaling by x, y and z.</summary>
406 /// <param name="x">The x-axis scaling factor.</param>
407 /// <param name="y">The y-axis scaling factor.</param>
408 /// <param name="z">The z-axis scaling factor.</param>
409 /// <returns>The float3x3 rotation matrix representing a non-uniform scale.</returns>
410 [MethodImpl(MethodImplOptions.AggressiveInlining)]
411 public static float3x3 Scale(float x, float y, float z)
412 {
413 return float3x3(x, 0.0f, 0.0f,
414 0.0f, y, 0.0f,
415 0.0f, 0.0f, z);
416 }
417
418 /// <summary>Returns a float3x3 matrix representing a non-uniform axis scaling by the components of the float3 vector v.</summary>
419 /// <param name="v">The vector containing non-uniform scaling factors.</param>
420 /// <returns>The float3x3 rotation matrix representing a non-uniform scale.</returns>
421 [MethodImpl(MethodImplOptions.AggressiveInlining)]
422 public static float3x3 Scale(float3 v)
423 {
424 return Scale(v.x, v.y, v.z);
425 }
426
427 /// <summary>
428 /// Returns a float3x3 view rotation matrix given a unit length forward vector and a unit length up vector.
429 /// The two input vectors are assumed to be unit length and not collinear.
430 /// If these assumptions are not met use float3x3.LookRotationSafe instead.
431 /// </summary>
432 /// <param name="forward">The forward vector to align the center of view with.</param>
433 /// <param name="up">The up vector to point top of view toward.</param>
434 /// <returns>The float3x3 view rotation matrix.</returns>
435 [MethodImpl(MethodImplOptions.AggressiveInlining)]
436 public static float3x3 LookRotation(float3 forward, float3 up)
437 {
438 float3 t = normalize(cross(up, forward));
439 return float3x3(t, cross(forward, t), forward);
440 }
441
442 /// <summary>
443 /// Returns a float3x3 view rotation matrix given a forward vector and an up vector.
444 /// The two input vectors are not assumed to be unit length.
445 /// If the magnitude of either of the vectors is so extreme that the calculation cannot be carried out reliably or the vectors are collinear,
446 /// the identity will be returned instead.
447 /// </summary>
448 /// <param name="forward">The forward vector to align the center of view with.</param>
449 /// <param name="up">The up vector to point top of view toward.</param>
450 /// <returns>The float3x3 view rotation matrix or the identity matrix.</returns>
451 [MethodImpl(MethodImplOptions.AggressiveInlining)]
452 public static float3x3 LookRotationSafe(float3 forward, float3 up)
453 {
454 float forwardLengthSq = dot(forward, forward);
455 float upLengthSq = dot(up, up);
456
457 forward *= rsqrt(forwardLengthSq);
458 up *= rsqrt(upLengthSq);
459
460 float3 t = cross(up, forward);
461 float tLengthSq = dot(t, t);
462 t *= rsqrt(tLengthSq);
463
464 float mn = min(min(forwardLengthSq, upLengthSq), tLengthSq);
465 float mx = max(max(forwardLengthSq, upLengthSq), tLengthSq);
466
467 bool accept = mn > 1e-35f && mx < 1e35f && isfinite(forwardLengthSq) && isfinite(upLengthSq) && isfinite(tLengthSq);
468 return float3x3(
469 select(float3(1,0,0), t, accept),
470 select(float3(0,1,0), cross(forward, t), accept),
471 select(float3(0,0,1), forward, accept));
472 }
473
474 /// <summary>
475 /// Converts a float4x4 to a float3x3.
476 /// </summary>
477 /// <param name="f4x4">The float4x4 to convert to a float3x3.</param>
478 /// <returns>The float3x3 constructed from the upper left 3x3 of the input float4x4 matrix.</returns>
479 public static explicit operator float3x3(float4x4 f4x4) => new float3x3(f4x4);
480 }
481
482 public partial struct float4x4
483 {
484 /// <summary>Constructs a float4x4 from a float3x3 rotation matrix and a float3 translation vector.</summary>
485 /// <param name="rotation">The float3x3 rotation matrix.</param>
486 /// <param name="translation">The translation vector.</param>
487 public float4x4(float3x3 rotation, float3 translation)
488 {
489 c0 = float4(rotation.c0, 0.0f);
490 c1 = float4(rotation.c1, 0.0f);
491 c2 = float4(rotation.c2, 0.0f);
492 c3 = float4(translation, 1.0f);
493 }
494
495 /// <summary>Constructs a float4x4 from a quaternion and a float3 translation vector.</summary>
496 /// <param name="rotation">The quaternion rotation.</param>
497 /// <param name="translation">The translation vector.</param>
498 public float4x4(quaternion rotation, float3 translation)
499 {
500 float3x3 rot = float3x3(rotation);
501 c0 = float4(rot.c0, 0.0f);
502 c1 = float4(rot.c1, 0.0f);
503 c2 = float4(rot.c2, 0.0f);
504 c3 = float4(translation, 1.0f);
505 }
506
507 /// <summary>Constructs a float4x4 from a RigidTransform.</summary>
508 /// <param name="transform">The RigidTransform.</param>
509 public float4x4(RigidTransform transform)
510 {
511 float3x3 rot = float3x3(transform.rot);
512 c0 = float4(rot.c0, 0.0f);
513 c1 = float4(rot.c1, 0.0f);
514 c2 = float4(rot.c2, 0.0f);
515 c3 = float4(transform.pos, 1.0f);
516 }
517
518 /// <summary>
519 /// Returns a float4x4 matrix representing a rotation around a unit axis by an angle in radians.
520 /// The rotation direction is clockwise when looking along the rotation axis towards the origin.
521 /// </summary>
522 /// <param name="axis">The axis of rotation.</param>
523 /// <param name="angle">The angle of rotation in radians.</param>
524 /// <returns>The float4x4 matrix representing the rotation about an axis.</returns>
525 [MethodImpl(MethodImplOptions.AggressiveInlining)]
526 public static float4x4 AxisAngle(float3 axis, float angle)
527 {
528 float sina, cosa;
529 math.sincos(angle, out sina, out cosa);
530
531 float4 u = float4(axis, 0.0f);
532 float4 u_yzx = u.yzxx;
533 float4 u_zxy = u.zxyx;
534 float4 u_inv_cosa = u - u * cosa; // u * (1.0f - cosa);
535 float4 t = float4(u.xyz * sina, cosa);
536
537 uint4 ppnp = uint4(0x00000000, 0x00000000, 0x80000000, 0x00000000);
538 uint4 nppp = uint4(0x80000000, 0x00000000, 0x00000000, 0x00000000);
539 uint4 pnpp = uint4(0x00000000, 0x80000000, 0x00000000, 0x00000000);
540 uint4 mask = uint4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000);
541
542 return float4x4(
543 u.x * u_inv_cosa + asfloat((asuint(t.wzyx) ^ ppnp) & mask),
544 u.y * u_inv_cosa + asfloat((asuint(t.zwxx) ^ nppp) & mask),
545 u.z * u_inv_cosa + asfloat((asuint(t.yxwx) ^ pnpp) & mask),
546 float4(0.0f, 0.0f, 0.0f, 1.0f)
547 );
548
549 }
550
551 /// <summary>
552 /// Returns a float4x4 rotation matrix constructed by first performing a rotation around the x-axis, then the y-axis and finally the z-axis.
553 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
554 /// </summary>
555 /// <param name="xyz">A float3 vector containing the rotation angles around the x-, y- and z-axis measures in radians.</param>
556 /// <returns>The float4x4 rotation matrix of the Euler angle rotation in x-y-z order.</returns>
557 [MethodImpl(MethodImplOptions.AggressiveInlining)]
558 public static float4x4 EulerXYZ(float3 xyz)
559 {
560 // return mul(rotateZ(xyz.z), mul(rotateY(xyz.y), rotateX(xyz.x)));
561 float3 s, c;
562 sincos(xyz, out s, out c);
563 return float4x4(
564 c.y * c.z, c.z * s.x * s.y - c.x * s.z, c.x * c.z * s.y + s.x * s.z, 0.0f,
565 c.y * s.z, c.x * c.z + s.x * s.y * s.z, c.x * s.y * s.z - c.z * s.x, 0.0f,
566 -s.y, c.y * s.x, c.x * c.y, 0.0f,
567 0.0f, 0.0f, 0.0f, 1.0f
568 );
569 }
570
571 /// <summary>
572 /// Returns a float4x4 rotation matrix constructed by first performing a rotation around the x-axis, then the z-axis and finally the y-axis.
573 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
574 /// </summary>
575 /// <param name="xyz">A float3 vector containing the rotation angles around the x-, y- and z-axis measures in radians.</param>
576 /// <returns>The float4x4 rotation matrix of the Euler angle rotation in x-z-y order.</returns>
577 [MethodImpl(MethodImplOptions.AggressiveInlining)]
578 public static float4x4 EulerXZY(float3 xyz)
579 {
580 // return mul(rotateY(xyz.y), mul(rotateZ(xyz.z), rotateX(xyz.x))); }
581 float3 s, c;
582 sincos(xyz, out s, out c);
583 return float4x4(
584 c.y * c.z, s.x * s.y - c.x * c.y * s.z, c.x * s.y + c.y * s.x * s.z, 0.0f,
585 s.z, c.x * c.z, -c.z * s.x, 0.0f,
586 -c.z * s.y, c.y * s.x + c.x * s.y * s.z, c.x * c.y - s.x * s.y * s.z, 0.0f,
587 0.0f, 0.0f, 0.0f, 1.0f
588 );
589 }
590
591 /// <summary>
592 /// Returns a float4x4 rotation matrix constructed by first performing a rotation around the y-axis, then the x-axis and finally the z-axis.
593 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
594 /// </summary>
595 /// <param name="xyz">A float3 vector containing the rotation angles around the x-, y- and z-axis measures in radians.</param>
596 /// <returns>The float4x4 rotation matrix of the Euler angle rotation in y-x-z order.</returns>
597 [MethodImpl(MethodImplOptions.AggressiveInlining)]
598 public static float4x4 EulerYXZ(float3 xyz)
599 {
600 // return mul(rotateZ(xyz.z), mul(rotateX(xyz.x), rotateY(xyz.y)));
601 float3 s, c;
602 sincos(xyz, out s, out c);
603 return float4x4(
604 c.y * c.z - s.x * s.y * s.z, -c.x * s.z, c.z * s.y + c.y * s.x * s.z, 0.0f,
605 c.z * s.x * s.y + c.y * s.z, c.x * c.z, s.y * s.z - c.y * c.z * s.x, 0.0f,
606 -c.x * s.y, s.x, c.x * c.y, 0.0f,
607 0.0f, 0.0f, 0.0f, 1.0f
608 );
609 }
610
611 /// <summary>
612 /// Returns a float4x4 rotation matrix constructed by first performing a rotation around the y-axis, then the z-axis and finally the x-axis.
613 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
614 /// </summary>
615 /// <param name="xyz">A float3 vector containing the rotation angles around the x-, y- and z-axis measures in radians.</param>
616 /// <returns>The float4x4 rotation matrix of the Euler angle rotation in y-z-x order.</returns>
617 [MethodImpl(MethodImplOptions.AggressiveInlining)]
618 public static float4x4 EulerYZX(float3 xyz)
619 {
620 // return mul(rotateX(xyz.x), mul(rotateZ(xyz.z), rotateY(xyz.y)));
621 float3 s, c;
622 sincos(xyz, out s, out c);
623 return float4x4(
624 c.y * c.z, -s.z, c.z * s.y, 0.0f,
625 s.x * s.y + c.x * c.y * s.z, c.x * c.z, c.x * s.y * s.z - c.y * s.x, 0.0f,
626 c.y * s.x * s.z - c.x * s.y, c.z * s.x, c.x * c.y + s.x * s.y * s.z, 0.0f,
627 0.0f, 0.0f, 0.0f, 1.0f
628 );
629 }
630
631 /// <summary>
632 /// Returns a float4x4 rotation matrix constructed by first performing a rotation around the z-axis, then the x-axis and finally the y-axis.
633 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
634 /// This is the default order rotation order in Unity.
635 /// </summary>
636 /// <param name="xyz">A float3 vector containing the rotation angles around the x-, y- and z-axis measures in radians.</param>
637 /// <returns>The float4x4 rotation matrix of the Euler angle rotation in z-x-y order.</returns>
638 [MethodImpl(MethodImplOptions.AggressiveInlining)]
639 public static float4x4 EulerZXY(float3 xyz)
640 {
641 // return mul(rotateY(xyz.y), mul(rotateX(xyz.x), rotateZ(xyz.z)));
642 float3 s, c;
643 sincos(xyz, out s, out c);
644 return float4x4(
645 c.y * c.z + s.x * s.y * s.z, c.z * s.x * s.y - c.y * s.z, c.x * s.y, 0.0f,
646 c.x * s.z, c.x * c.z, -s.x, 0.0f,
647 c.y * s.x * s.z - c.z * s.y, c.y * c.z * s.x + s.y * s.z, c.x * c.y, 0.0f,
648 0.0f, 0.0f, 0.0f, 1.0f
649 );
650 }
651
652 /// <summary>
653 /// Returns a float4x4 rotation matrix constructed by first performing a rotation around the z-axis, then the y-axis and finally the x-axis.
654 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
655 /// </summary>
656 /// <param name="xyz">A float3 vector containing the rotation angles around the x-, y- and z-axis measures in radians.</param>
657 /// <returns>The float4x4 rotation matrix of the Euler angle rotation in z-y-x order.</returns>
658 [MethodImpl(MethodImplOptions.AggressiveInlining)]
659 public static float4x4 EulerZYX(float3 xyz)
660 {
661 // return mul(rotateX(xyz.x), mul(rotateY(xyz.y), rotateZ(xyz.z)));
662 float3 s, c;
663 sincos(xyz, out s, out c);
664 return float4x4(
665 c.y * c.z, -c.y * s.z, s.y, 0.0f,
666 c.z * s.x * s.y + c.x * s.z, c.x * c.z - s.x * s.y * s.z, -c.y * s.x, 0.0f,
667 s.x * s.z - c.x * c.z * s.y, c.z * s.x + c.x * s.y * s.z, c.x * c.y, 0.0f,
668 0.0f, 0.0f, 0.0f, 1.0f
669 );
670 }
671
672 /// <summary>
673 /// Returns a float4x4 rotation matrix constructed by first performing a rotation around the x-axis, then the y-axis and finally the z-axis.
674 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
675 /// </summary>
676 /// <param name="x">The rotation angle around the x-axis in radians.</param>
677 /// <param name="y">The rotation angle around the y-axis in radians.</param>
678 /// <param name="z">The rotation angle around the z-axis in radians.</param>
679 /// <returns>The float4x4 rotation matrix of the Euler angle rotation in x-y-z order.</returns>
680 [MethodImpl(MethodImplOptions.AggressiveInlining)]
681 public static float4x4 EulerXYZ(float x, float y, float z) { return EulerXYZ(float3(x, y, z)); }
682
683 /// <summary>
684 /// Returns a float4x4 rotation matrix constructed by first performing a rotation around the x-axis, then the z-axis and finally the y-axis.
685 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
686 /// </summary>
687 /// <param name="x">The rotation angle around the x-axis in radians.</param>
688 /// <param name="y">The rotation angle around the y-axis in radians.</param>
689 /// <param name="z">The rotation angle around the z-axis in radians.</param>
690 /// <returns>The float4x4 rotation matrix of the Euler angle rotation in x-z-y order.</returns>
691 [MethodImpl(MethodImplOptions.AggressiveInlining)]
692 public static float4x4 EulerXZY(float x, float y, float z) { return EulerXZY(float3(x, y, z)); }
693
694 /// <summary>
695 /// Returns a float4x4 rotation matrix constructed by first performing a rotation around the y-axis, then the x-axis and finally the z-axis.
696 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
697 /// </summary>
698 /// <param name="x">The rotation angle around the x-axis in radians.</param>
699 /// <param name="y">The rotation angle around the y-axis in radians.</param>
700 /// <param name="z">The rotation angle around the z-axis in radians.</param>
701 /// <returns>The float4x4 rotation matrix of the Euler angle rotation in y-x-z order.</returns>
702 [MethodImpl(MethodImplOptions.AggressiveInlining)]
703 public static float4x4 EulerYXZ(float x, float y, float z) { return EulerYXZ(float3(x, y, z)); }
704
705 /// <summary>
706 /// Returns a float4x4 rotation matrix constructed by first performing a rotation around the y-axis, then the z-axis and finally the x-axis.
707 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
708 /// </summary>
709 /// <param name="x">The rotation angle around the x-axis in radians.</param>
710 /// <param name="y">The rotation angle around the y-axis in radians.</param>
711 /// <param name="z">The rotation angle around the z-axis in radians.</param>
712 /// <returns>The float4x4 rotation matrix of the Euler angle rotation in y-z-x order.</returns>
713 [MethodImpl(MethodImplOptions.AggressiveInlining)]
714 public static float4x4 EulerYZX(float x, float y, float z) { return EulerYZX(float3(x, y, z)); }
715
716 /// <summary>
717 /// Returns a float4x4 rotation matrix constructed by first performing a rotation around the z-axis, then the x-axis and finally the y-axis.
718 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
719 /// This is the default order rotation order in Unity.
720 /// </summary>
721 /// <param name="x">The rotation angle around the x-axis in radians.</param>
722 /// <param name="y">The rotation angle around the y-axis in radians.</param>
723 /// <param name="z">The rotation angle around the z-axis in radians.</param>
724 /// <returns>The float4x4 rotation matrix of the Euler angle rotation in z-x-y order.</returns>
725 [MethodImpl(MethodImplOptions.AggressiveInlining)]
726 public static float4x4 EulerZXY(float x, float y, float z) { return EulerZXY(float3(x, y, z)); }
727
728 /// <summary>
729 /// Returns a float4x4 rotation matrix constructed by first performing a rotation around the z-axis, then the y-axis and finally the x-axis.
730 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
731 /// </summary>
732 /// <param name="x">The rotation angle around the x-axis in radians.</param>
733 /// <param name="y">The rotation angle around the y-axis in radians.</param>
734 /// <param name="z">The rotation angle around the z-axis in radians.</param>
735 /// <returns>The float4x4 rotation matrix of the Euler angle rotation in z-y-x order.</returns>
736 [MethodImpl(MethodImplOptions.AggressiveInlining)]
737 public static float4x4 EulerZYX(float x, float y, float z) { return EulerZYX(float3(x, y, z)); }
738
739 /// <summary>
740 /// Returns a float4x4 constructed by first performing 3 rotations around the principal axes in a given order.
741 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
742 /// When the rotation order is known at compile time, it is recommended for performance reasons to use specific
743 /// Euler rotation constructors such as EulerZXY(...).
744 /// </summary>
745 /// <param name="xyz">A float3 vector containing the rotation angles around the x-, y- and z-axis measures in radians.</param>
746 /// <param name="order">The order in which the rotations are applied.</param>
747 /// <returns>The float4x4 rotation matrix of the Euler angle rotation in given order.</returns>
748 [MethodImpl(MethodImplOptions.AggressiveInlining)]
749 public static float4x4 Euler(float3 xyz, RotationOrder order = RotationOrder.Default)
750 {
751 switch (order)
752 {
753 case RotationOrder.XYZ:
754 return EulerXYZ(xyz);
755 case RotationOrder.XZY:
756 return EulerXZY(xyz);
757 case RotationOrder.YXZ:
758 return EulerYXZ(xyz);
759 case RotationOrder.YZX:
760 return EulerYZX(xyz);
761 case RotationOrder.ZXY:
762 return EulerZXY(xyz);
763 case RotationOrder.ZYX:
764 return EulerZYX(xyz);
765 default:
766 return float4x4.identity;
767 }
768 }
769
770 /// <summary>
771 /// Returns a float4x4 rotation matrix constructed by first performing 3 rotations around the principal axes in a given order.
772 /// All rotation angles are in radians and clockwise when looking along the rotation axis towards the origin.
773 /// When the rotation order is known at compile time, it is recommended for performance reasons to use specific
774 /// Euler rotation constructors such as EulerZXY(...).
775 /// </summary>
776 /// <param name="x">The rotation angle around the x-axis in radians.</param>
777 /// <param name="y">The rotation angle around the y-axis in radians.</param>
778 /// <param name="z">The rotation angle around the z-axis in radians.</param>
779 /// <param name="order">The order in which the rotations are applied.</param>
780 /// <returns>The float4x4 rotation matrix of the Euler angle rotation in given order.</returns>
781 [MethodImpl(MethodImplOptions.AggressiveInlining)]
782 public static float4x4 Euler(float x, float y, float z, RotationOrder order = RotationOrder.Default)
783 {
784 return Euler(float3(x, y, z), order);
785 }
786
787 /// <summary>Returns a float4x4 matrix that rotates around the x-axis by a given number of radians.</summary>
788 /// <param name="angle">The clockwise rotation angle when looking along the x-axis towards the origin in radians.</param>
789 /// <returns>The float4x4 rotation matrix that rotates around the x-axis.</returns>
790 [MethodImpl(MethodImplOptions.AggressiveInlining)]
791 public static float4x4 RotateX(float angle)
792 {
793 // {{1, 0, 0}, {0, c_0, -s_0}, {0, s_0, c_0}}
794 float s, c;
795 sincos(angle, out s, out c);
796 return float4x4(1.0f, 0.0f, 0.0f, 0.0f,
797 0.0f, c, -s, 0.0f,
798 0.0f, s, c, 0.0f,
799 0.0f, 0.0f, 0.0f, 1.0f);
800
801 }
802
803 /// <summary>Returns a float4x4 matrix that rotates around the y-axis by a given number of radians.</summary>
804 /// <param name="angle">The clockwise rotation angle when looking along the y-axis towards the origin in radians.</param>
805 /// <returns>The float4x4 rotation matrix that rotates around the y-axis.</returns>
806 [MethodImpl(MethodImplOptions.AggressiveInlining)]
807 public static float4x4 RotateY(float angle)
808 {
809 // {{c_1, 0, s_1}, {0, 1, 0}, {-s_1, 0, c_1}}
810 float s, c;
811 sincos(angle, out s, out c);
812 return float4x4(c, 0.0f, s, 0.0f,
813 0.0f, 1.0f, 0.0f, 0.0f,
814 -s, 0.0f, c, 0.0f,
815 0.0f, 0.0f, 0.0f, 1.0f);
816
817 }
818
819 /// <summary>Returns a float4x4 matrix that rotates around the z-axis by a given number of radians.</summary>
820 /// <param name="angle">The clockwise rotation angle when looking along the z-axis towards the origin in radians.</param>
821 /// <returns>The float4x4 rotation matrix that rotates around the z-axis.</returns>
822 [MethodImpl(MethodImplOptions.AggressiveInlining)]
823 public static float4x4 RotateZ(float angle)
824 {
825 // {{c_2, -s_2, 0}, {s_2, c_2, 0}, {0, 0, 1}}
826 float s, c;
827 sincos(angle, out s, out c);
828 return float4x4(c, -s, 0.0f, 0.0f,
829 s, c, 0.0f, 0.0f,
830 0.0f, 0.0f, 1.0f, 0.0f,
831 0.0f, 0.0f, 0.0f, 1.0f);
832
833 }
834
835 /// <summary>Returns a float4x4 scale matrix given 3 axis scales.</summary>
836 /// <param name="s">The uniform scaling factor.</param>
837 /// <returns>The float4x4 matrix that represents a uniform scale.</returns>
838 [MethodImpl(MethodImplOptions.AggressiveInlining)]
839 public static float4x4 Scale(float s)
840 {
841 return float4x4(s, 0.0f, 0.0f, 0.0f,
842 0.0f, s, 0.0f, 0.0f,
843 0.0f, 0.0f, s, 0.0f,
844 0.0f, 0.0f, 0.0f, 1.0f);
845 }
846
847 /// <summary>Returns a float4x4 scale matrix given a float3 vector containing the 3 axis scales.</summary>
848 /// <param name="x">The x-axis scaling factor.</param>
849 /// <param name="y">The y-axis scaling factor.</param>
850 /// <param name="z">The z-axis scaling factor.</param>
851 /// <returns>The float4x4 matrix that represents a non-uniform scale.</returns>
852 [MethodImpl(MethodImplOptions.AggressiveInlining)]
853 public static float4x4 Scale(float x, float y, float z)
854 {
855 return float4x4(x, 0.0f, 0.0f, 0.0f,
856 0.0f, y, 0.0f, 0.0f,
857 0.0f, 0.0f, z, 0.0f,
858 0.0f, 0.0f, 0.0f, 1.0f);
859 }
860
861 /// <summary>Returns a float4x4 scale matrix given a float3 vector containing the 3 axis scales.</summary>
862 /// <param name="scales">The vector containing scale factors for each axis.</param>
863 /// <returns>The float4x4 matrix that represents a non-uniform scale.</returns>
864 [MethodImpl(MethodImplOptions.AggressiveInlining)]
865 public static float4x4 Scale(float3 scales)
866 {
867 return Scale(scales.x, scales.y, scales.z);
868 }
869
870 /// <summary>Returns a float4x4 translation matrix given a float3 translation vector.</summary>
871 /// <param name="vector">The translation vector.</param>
872 /// <returns>The float4x4 translation matrix.</returns>
873 [MethodImpl(MethodImplOptions.AggressiveInlining)]
874 public static float4x4 Translate(float3 vector)
875 {
876 return float4x4(float4(1.0f, 0.0f, 0.0f, 0.0f),
877 float4(0.0f, 1.0f, 0.0f, 0.0f),
878 float4(0.0f, 0.0f, 1.0f, 0.0f),
879 float4(vector.x, vector.y, vector.z, 1.0f));
880 }
881
882 /// <summary>
883 /// Returns a float4x4 view matrix given an eye position, a target point and a unit length up vector.
884 /// The up vector is assumed to be unit length, the eye and target points are assumed to be distinct and
885 /// the vector between them is assumes to be collinear with the up vector.
886 /// If these assumptions are not met use float4x4.LookRotationSafe instead.
887 /// </summary>
888 /// <param name="eye">The eye position.</param>
889 /// <param name="target">The view target position.</param>
890 /// <param name="up">The eye up direction.</param>
891 /// <returns>The float4x4 view matrix.</returns>
892 [MethodImpl(MethodImplOptions.AggressiveInlining)]
893 public static float4x4 LookAt(float3 eye, float3 target, float3 up)
894 {
895 float3x3 rot = float3x3.LookRotation(normalize(target - eye), up);
896
897 float4x4 matrix;
898 matrix.c0 = float4(rot.c0, 0.0F);
899 matrix.c1 = float4(rot.c1, 0.0F);
900 matrix.c2 = float4(rot.c2, 0.0F);
901 matrix.c3 = float4(eye, 1.0F);
902 return matrix;
903 }
904
905 /// <summary>
906 /// Returns a float4x4 centered orthographic projection matrix.
907 /// </summary>
908 /// <param name="width">The width of the view volume.</param>
909 /// <param name="height">The height of the view volume.</param>
910 /// <param name="near">The distance to the near plane.</param>
911 /// <param name="far">The distance to the far plane.</param>
912 /// <returns>The float4x4 centered orthographic projection matrix.</returns>
913 [MethodImpl(MethodImplOptions.AggressiveInlining)]
914 public static float4x4 Ortho(float width, float height, float near, float far)
915 {
916 float rcpdx = 1.0f / width;
917 float rcpdy = 1.0f / height;
918 float rcpdz = 1.0f / (far - near);
919
920 return float4x4(
921 2.0f * rcpdx, 0.0f, 0.0f, 0.0f,
922 0.0f, 2.0f * rcpdy, 0.0f, 0.0f,
923 0.0f, 0.0f, -2.0f * rcpdz, -(far + near) * rcpdz,
924 0.0f, 0.0f, 0.0f, 1.0f
925 );
926 }
927
928 /// <summary>
929 /// Returns a float4x4 off-center orthographic projection matrix.
930 /// </summary>
931 /// <param name="left">The minimum x-coordinate of the view volume.</param>
932 /// <param name="right">The maximum x-coordinate of the view volume.</param>
933 /// <param name="bottom">The minimum y-coordinate of the view volume.</param>
934 /// <param name="top">The minimum y-coordinate of the view volume.</param>
935 /// <param name="near">The distance to the near plane.</param>
936 /// <param name="far">The distance to the far plane.</param>
937 /// <returns>The float4x4 off-center orthographic projection matrix.</returns>
938 [MethodImpl(MethodImplOptions.AggressiveInlining)]
939 public static float4x4 OrthoOffCenter(float left, float right, float bottom, float top, float near, float far)
940 {
941 float rcpdx = 1.0f / (right - left);
942 float rcpdy = 1.0f / (top - bottom);
943 float rcpdz = 1.0f / (far - near);
944
945 return float4x4(
946 2.0f * rcpdx, 0.0f, 0.0f, -(right + left) * rcpdx,
947 0.0f, 2.0f * rcpdy, 0.0f, -(top + bottom) * rcpdy,
948 0.0f, 0.0f, -2.0f * rcpdz, -(far + near) * rcpdz,
949 0.0f, 0.0f, 0.0f, 1.0f
950 );
951 }
952
953 /// <summary>
954 /// Returns a float4x4 perspective projection matrix based on field of view.
955 /// </summary>
956 /// <param name="verticalFov">Vertical Field of view in radians.</param>
957 /// <param name="aspect">X:Y aspect ratio.</param>
958 /// <param name="near">Distance to near plane. Must be greater than zero.</param>
959 /// <param name="far">Distance to far plane. Must be greater than zero.</param>
960 /// <returns>The float4x4 perspective projection matrix.</returns>
961 [MethodImpl(MethodImplOptions.AggressiveInlining)]
962 public static float4x4 PerspectiveFov(float verticalFov, float aspect, float near, float far)
963 {
964 float cotangent = 1.0f / tan(verticalFov * 0.5f);
965 float rcpdz = 1.0f / (near - far);
966
967 return float4x4(
968 cotangent / aspect, 0.0f, 0.0f, 0.0f,
969 0.0f, cotangent, 0.0f, 0.0f,
970 0.0f, 0.0f, (far + near) * rcpdz, 2.0f * near * far * rcpdz,
971 0.0f, 0.0f, -1.0f, 0.0f
972 );
973 }
974
975 /// <summary>
976 /// Returns a float4x4 off-center perspective projection matrix.
977 /// </summary>
978 /// <param name="left">The x-coordinate of the left side of the clipping frustum at the near plane.</param>
979 /// <param name="right">The x-coordinate of the right side of the clipping frustum at the near plane.</param>
980 /// <param name="bottom">The y-coordinate of the bottom side of the clipping frustum at the near plane.</param>
981 /// <param name="top">The y-coordinate of the top side of the clipping frustum at the near plane.</param>
982 /// <param name="near">Distance to the near plane. Must be greater than zero.</param>
983 /// <param name="far">Distance to the far plane. Must be greater than zero.</param>
984 /// <returns>The float4x4 off-center perspective projection matrix.</returns>
985 [MethodImpl(MethodImplOptions.AggressiveInlining)]
986 public static float4x4 PerspectiveOffCenter(float left, float right, float bottom, float top, float near, float far)
987 {
988 float rcpdz = 1.0f / (near - far);
989 float rcpWidth = 1.0f / (right - left);
990 float rcpHeight = 1.0f / (top - bottom);
991
992 return float4x4(
993 2.0f * near * rcpWidth, 0.0f, (left + right) * rcpWidth, 0.0f,
994 0.0f, 2.0f * near * rcpHeight, (bottom + top) * rcpHeight, 0.0f,
995 0.0f, 0.0f, (far + near) * rcpdz, 2.0f * near * far * rcpdz,
996 0.0f, 0.0f, -1.0f, 0.0f
997 );
998 }
999
1000 /// <summary>
1001 /// Returns a float4x4 matrix representing a combined scale-, rotation- and translation transform.
1002 /// Equivalent to mul(translationTransform, mul(rotationTransform, scaleTransform)).
1003 /// </summary>
1004 /// <param name="translation">The translation vector.</param>
1005 /// <param name="rotation">The quaternion rotation.</param>
1006 /// <param name="scale">The scaling factors of each axis.</param>
1007 /// <returns>The float4x4 matrix representing the translation, rotation, and scale by the inputs.</returns>
1008 [MethodImpl(MethodImplOptions.AggressiveInlining)]
1009 public static float4x4 TRS(float3 translation, quaternion rotation, float3 scale)
1010 {
1011 float3x3 r = float3x3(rotation);
1012 return float4x4( float4(r.c0 * scale.x, 0.0f),
1013 float4(r.c1 * scale.y, 0.0f),
1014 float4(r.c2 * scale.z, 0.0f),
1015 float4(translation, 1.0f));
1016 }
1017 }
1018
1019 partial class math
1020 {
1021 /// <summary>
1022 /// Extracts a float3x3 from the upper left 3x3 of a float4x4.
1023 /// </summary>
1024 /// <param name="f4x4"><see cref="float4x4"/> to extract a float3x3 from.</param>
1025 /// <returns>Upper left 3x3 matrix as float3x3.</returns>
1026 [MethodImpl(MethodImplOptions.AggressiveInlining)]
1027 public static float3x3 float3x3(float4x4 f4x4)
1028 {
1029 return new float3x3(f4x4);
1030 }
1031
1032 /// <summary>Returns a float3x3 matrix constructed from a quaternion.</summary>
1033 /// <param name="rotation">The quaternion representing a rotation.</param>
1034 /// <returns>The float3x3 constructed from a quaternion.</returns>
1035 [MethodImpl(MethodImplOptions.AggressiveInlining)]
1036 public static float3x3 float3x3(quaternion rotation)
1037 {
1038 return new float3x3(rotation);
1039 }
1040
1041 /// <summary>Returns a float4x4 constructed from a float3x3 rotation matrix and a float3 translation vector.</summary>
1042 /// <param name="rotation">The float3x3 rotation matrix.</param>
1043 /// <param name="translation">The translation vector.</param>
1044 /// <returns>The float4x4 constructed from a rotation and translation.</returns>
1045 [MethodImpl(MethodImplOptions.AggressiveInlining)]
1046 public static float4x4 float4x4(float3x3 rotation, float3 translation)
1047 {
1048 return new float4x4(rotation, translation);
1049 }
1050
1051 /// <summary>Returns a float4x4 constructed from a quaternion and a float3 translation vector.</summary>
1052 /// <param name="rotation">The quaternion rotation.</param>
1053 /// <param name="translation">The translation vector.</param>
1054 /// <returns>The float4x4 constructed from a rotation and translation.</returns>
1055 [MethodImpl(MethodImplOptions.AggressiveInlining)]
1056 public static float4x4 float4x4(quaternion rotation, float3 translation)
1057 {
1058 return new float4x4(rotation, translation);
1059 }
1060
1061 /// <summary>Returns a float4x4 constructed from a RigidTransform.</summary>
1062 /// <param name="transform">The rigid transformation.</param>
1063 /// <returns>The float4x4 constructed from a RigidTransform.</returns>
1064 [MethodImpl(MethodImplOptions.AggressiveInlining)]
1065 public static float4x4 float4x4(RigidTransform transform)
1066 {
1067 return new float4x4(transform);
1068 }
1069
1070 /// <summary>Returns an orthonormalized version of a float3x3 matrix.</summary>
1071 /// <param name="i">The float3x3 to be orthonormalized.</param>
1072 /// <returns>The orthonormalized float3x3 matrix.</returns>
1073 [MethodImpl(MethodImplOptions.AggressiveInlining)]
1074 public static float3x3 orthonormalize(float3x3 i)
1075 {
1076 float3x3 o;
1077
1078 float3 u = i.c0;
1079 float3 v = i.c1 - i.c0 * math.dot(i.c1, i.c0);
1080
1081 float lenU = math.length(u);
1082 float lenV = math.length(v);
1083
1084 bool c = lenU > 1e-30f && lenV > 1e-30f;
1085
1086 o.c0 = math.select(float3(1, 0, 0), u / lenU, c);
1087 o.c1 = math.select(float3(0, 1, 0), v / lenV, c);
1088 o.c2 = math.cross(o.c0, o.c1);
1089
1090 return o;
1091 }
1092
1093 /// <summary>
1094 /// Computes the pseudoinverse of a matrix.
1095 /// </summary>
1096 /// <param name="m">Matrix to invert.</param>
1097 /// <returns>The pseudoinverse of m.</returns>
1098 [MethodImpl(MethodImplOptions.AggressiveInlining)]
1099 public static float3x3 pseudoinverse(float3x3 m)
1100 {
1101 float scaleSq = 0.333333f * (math.lengthsq(m.c0) + math.lengthsq(m.c1) + math.lengthsq(m.c2));
1102 if (scaleSq < svd.k_EpsilonNormal)
1103 return Mathematics.float3x3.zero;
1104
1105 float3 scaleInv = math.rsqrt(scaleSq);
1106 float3x3 ms = mulScale(m, scaleInv);
1107 if (!adjInverse(ms, out float3x3 i, svd.k_EpsilonDeterminant))
1108 {
1109 i = svd.svdInverse(ms);
1110 }
1111
1112 return mulScale(i, scaleInv);
1113 }
1114 }
1115}