pod_math.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. #pragma once
  2. #include <algorithm>
  3. #include <array>
  4. #include <cmath>
  5. namespace Render::Math {
  6. struct alignas(16) Vec3 {
  7. float x, y, z, w;
  8. Vec3() noexcept : x(0), y(0), z(0), w(0) {}
  9. Vec3(float x_, float y_, float z_) noexcept : x(x_), y(y_), z(z_), w(0) {}
  10. auto operator+(const Vec3 &o) const noexcept -> Vec3 {
  11. return {x + o.x, y + o.y, z + o.z};
  12. }
  13. auto operator-(const Vec3 &o) const noexcept -> Vec3 {
  14. return {x - o.x, y - o.y, z - o.z};
  15. }
  16. auto operator*(float s) const noexcept -> Vec3 {
  17. return {x * s, y * s, z * s};
  18. }
  19. [[nodiscard]] auto dot(const Vec3 &o) const noexcept -> float {
  20. return x * o.x + y * o.y + z * o.z;
  21. }
  22. [[nodiscard]] auto cross(const Vec3 &o) const noexcept -> Vec3 {
  23. return {y * o.z - z * o.y, z * o.x - x * o.z, x * o.y - y * o.x};
  24. }
  25. [[nodiscard]] auto lengthSquared() const noexcept -> float {
  26. return x * x + y * y + z * z;
  27. }
  28. [[nodiscard]] auto length() const noexcept -> float {
  29. return std::sqrt(lengthSquared());
  30. }
  31. [[nodiscard]] auto normalized() const noexcept -> Vec3 {
  32. float const len = length();
  33. if (len < 1e-6F) {
  34. return {0, 1, 0};
  35. }
  36. float const inv_len = 1.0F / len;
  37. return {x * inv_len, y * inv_len, z * inv_len};
  38. }
  39. void normalize() noexcept {
  40. float const len = length();
  41. if (len > 1e-6F) {
  42. float const inv_len = 1.0F / len;
  43. x *= inv_len;
  44. y *= inv_len;
  45. z *= inv_len;
  46. }
  47. }
  48. };
  49. struct alignas(16) Mat3x4 {
  50. std::array<std::array<float, 4>, 3> m{};
  51. Mat3x4() noexcept {
  52. for (auto &row : m) {
  53. row.fill(0.0F);
  54. }
  55. m[0][0] = m[1][1] = m[2][2] = 1.0F;
  56. }
  57. static auto TRS(const Vec3 &translation,
  58. const std::array<std::array<float, 3>, 3> &rotation,
  59. float scale_x, float scaleY,
  60. float scale_z) noexcept -> Mat3x4 {
  61. Mat3x4 result;
  62. for (int row = 0; row < 3; ++row) {
  63. result.m[row][0] = rotation[row][0] * scale_x;
  64. result.m[row][1] = rotation[row][1] * scaleY;
  65. result.m[row][2] = rotation[row][2] * scale_z;
  66. result.m[row][3] = (&translation.x)[row];
  67. }
  68. return result;
  69. }
  70. [[nodiscard]] auto transform_point(const Vec3 &p) const noexcept -> Vec3 {
  71. return {m[0][0] * p.x + m[0][1] * p.y + m[0][2] * p.z + m[0][3],
  72. m[1][0] * p.x + m[1][1] * p.y + m[1][2] * p.z + m[1][3],
  73. m[2][0] * p.x + m[2][1] * p.y + m[2][2] * p.z + m[2][3]};
  74. }
  75. [[nodiscard]] auto transform_vector(const Vec3 &v) const noexcept -> Vec3 {
  76. return {m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z,
  77. m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z,
  78. m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z};
  79. }
  80. auto operator*(const Mat3x4 &o) const noexcept -> Mat3x4 {
  81. Mat3x4 result;
  82. for (int row = 0; row < 3; ++row) {
  83. for (int col = 0; col < 3; ++col) {
  84. result.m[row][col] = m[row][0] * o.m[0][col] + m[row][1] * o.m[1][col] +
  85. m[row][2] * o.m[2][col];
  86. }
  87. result.m[row][3] = m[row][0] * o.m[0][3] + m[row][1] * o.m[1][3] +
  88. m[row][2] * o.m[2][3] + m[row][3];
  89. }
  90. return result;
  91. }
  92. void set_translation(const Vec3 &t) noexcept {
  93. m[0][3] = t.x;
  94. m[1][3] = t.y;
  95. m[2][3] = t.z;
  96. }
  97. [[nodiscard]] auto get_translation() const noexcept -> Vec3 {
  98. return {m[0][3], m[1][3], m[2][3]};
  99. }
  100. };
  101. struct CylinderTransform {
  102. Vec3 center;
  103. Vec3 axis;
  104. Vec3 tangent;
  105. Vec3 bitangent;
  106. float length{};
  107. float radius{};
  108. static auto fromPoints(const Vec3 &start, const Vec3 &end,
  109. float radius) noexcept -> CylinderTransform {
  110. CylinderTransform ct;
  111. ct.radius = radius;
  112. Vec3 const diff = end - start;
  113. float const len_sq = diff.lengthSquared();
  114. if (len_sq < 1e-10F) {
  115. ct.center = start;
  116. ct.axis = Vec3(0, 1, 0);
  117. ct.tangent = Vec3(1, 0, 0);
  118. ct.bitangent = Vec3(0, 0, 1);
  119. ct.length = 0.0F;
  120. return ct;
  121. }
  122. ct.length = std::sqrt(len_sq);
  123. ct.center = Vec3((start.x + end.x) * 0.5F, (start.y + end.y) * 0.5F,
  124. (start.z + end.z) * 0.5F);
  125. ct.axis = diff * (1.0F / ct.length);
  126. Vec3 const up =
  127. (std::abs(ct.axis.y) < 0.999F) ? Vec3(0, 1, 0) : Vec3(1, 0, 0);
  128. ct.tangent = up.cross(ct.axis).normalized();
  129. ct.bitangent = ct.axis.cross(ct.tangent).normalized();
  130. return ct;
  131. }
  132. [[nodiscard]] auto to_matrix() const noexcept -> Mat3x4 {
  133. Mat3x4 m;
  134. m.m[0][0] = tangent.x * radius;
  135. m.m[1][0] = tangent.y * radius;
  136. m.m[2][0] = tangent.z * radius;
  137. m.m[0][1] = axis.x * length;
  138. m.m[1][1] = axis.y * length;
  139. m.m[2][1] = axis.z * length;
  140. m.m[0][2] = bitangent.x * radius;
  141. m.m[1][2] = bitangent.y * radius;
  142. m.m[2][2] = bitangent.z * radius;
  143. m.m[0][3] = center.x;
  144. m.m[1][3] = center.y;
  145. m.m[2][3] = center.z;
  146. return m;
  147. }
  148. };
  149. inline auto cylinder_between_fast(const Vec3 &a, const Vec3 &b,
  150. float radius) noexcept -> Mat3x4 {
  151. const float dx = b.x - a.x;
  152. const float dy = b.y - a.y;
  153. const float dz = b.z - a.z;
  154. const float len_sq = dx * dx + dy * dy + dz * dz;
  155. constexpr float k_epsilonSq = 1e-12F;
  156. constexpr float k_rad_to_deg = 57.2957795131F;
  157. Vec3 const center((a.x + b.x) * 0.5F, (a.y + b.y) * 0.5F, (a.z + b.z) * 0.5F);
  158. if (len_sq < k_epsilonSq) {
  159. Mat3x4 m;
  160. m.m[0][0] = radius;
  161. m.m[0][1] = 0;
  162. m.m[0][2] = 0;
  163. m.m[1][0] = 0;
  164. m.m[1][1] = 1.0F;
  165. m.m[1][2] = 0;
  166. m.m[2][0] = 0;
  167. m.m[2][1] = 0;
  168. m.m[2][2] = radius;
  169. m.set_translation(center);
  170. return m;
  171. }
  172. const float len = std::sqrt(len_sq);
  173. const float inv_len = 1.0F / len;
  174. const float ndx = dx * inv_len;
  175. const float ndy = dy * inv_len;
  176. const float ndz = dz * inv_len;
  177. const float axis_x = ndz;
  178. const float axis_z = -ndx;
  179. const float axis_len_sq = axis_x * axis_x + axis_z * axis_z;
  180. std::array<std::array<float, 3>, 3> rot{};
  181. if (axis_len_sq < k_epsilonSq) {
  182. if (ndy < 0.0F) {
  183. rot[0][0] = 1;
  184. rot[0][1] = 0;
  185. rot[0][2] = 0;
  186. rot[1][0] = 0;
  187. rot[1][1] = -1;
  188. rot[1][2] = 0;
  189. rot[2][0] = 0;
  190. rot[2][1] = 0;
  191. rot[2][2] = -1;
  192. } else {
  193. rot[0][0] = 1;
  194. rot[0][1] = 0;
  195. rot[0][2] = 0;
  196. rot[1][0] = 0;
  197. rot[1][1] = 1;
  198. rot[1][2] = 0;
  199. rot[2][0] = 0;
  200. rot[2][1] = 0;
  201. rot[2][2] = 1;
  202. }
  203. } else {
  204. const float axis_inv_len = 1.0F / std::sqrt(axis_len_sq);
  205. const float ax = axis_x * axis_inv_len;
  206. const float az = axis_z * axis_inv_len;
  207. const float dot = std::clamp(ndy, -1.0F, 1.0F);
  208. const float angle = std::acos(dot);
  209. const float c = std::cos(angle);
  210. const float s = std::sin(angle);
  211. const float t = 1.0F - c;
  212. rot[0][0] = t * ax * ax + c;
  213. rot[0][1] = t * ax * 0;
  214. rot[0][2] = t * ax * az - s * 0;
  215. rot[1][0] = t * 0 * ax + s * az;
  216. rot[1][1] = t * 0 * 0 + c;
  217. rot[1][2] = t * 0 * az - s * ax;
  218. rot[2][0] = t * az * ax + s * 0;
  219. rot[2][1] = t * az * 0 - s * ax;
  220. rot[2][2] = t * az * az + c;
  221. }
  222. Mat3x4 result = Mat3x4::TRS(center, rot, radius, len, radius);
  223. return result;
  224. }
  225. inline auto sphere_at_fast(const Vec3 &pos, float radius) noexcept -> Mat3x4 {
  226. Mat3x4 m;
  227. m.m[0][0] = radius;
  228. m.m[0][1] = 0;
  229. m.m[0][2] = 0;
  230. m.m[1][0] = 0;
  231. m.m[1][1] = radius;
  232. m.m[1][2] = 0;
  233. m.m[2][0] = 0;
  234. m.m[2][1] = 0;
  235. m.m[2][2] = radius;
  236. m.set_translation(pos);
  237. return m;
  238. }
  239. inline auto cylinder_between_fast(const Mat3x4 &parent, const Vec3 &a,
  240. const Vec3 &b,
  241. float radius) noexcept -> Mat3x4 {
  242. Mat3x4 const local = cylinder_between_fast(a, b, radius);
  243. return parent * local;
  244. }
  245. inline auto sphere_at_fast(const Mat3x4 &parent, const Vec3 &pos,
  246. float radius) noexcept -> Mat3x4 {
  247. Mat3x4 const local = sphere_at_fast(pos, radius);
  248. return parent * local;
  249. }
  250. } // namespace Render::Math