matrix.cs 47 KB

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