Без опису
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

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