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}