primitives.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. #include "primitives.h"
  2. #include <QVector3D>
  3. #include <cmath>
  4. #include <memory>
  5. #include <vector>
  6. namespace Render::GL {
  7. namespace {
  8. Mesh *createUnitCylinderMesh(int radialSegments) {
  9. const float radius = 1.0f;
  10. const float halfH = 0.5f;
  11. std::vector<Vertex> v;
  12. std::vector<unsigned int> idx;
  13. for (int y = 0; y <= 1; ++y) {
  14. float py = y ? halfH : -halfH;
  15. float vCoord = float(y);
  16. for (int i = 0; i <= radialSegments; ++i) {
  17. float u = float(i) / float(radialSegments);
  18. float ang = u * 6.28318530718f;
  19. float px = radius * std::cos(ang);
  20. float pz = radius * std::sin(ang);
  21. QVector3D n(px, 0.0f, pz);
  22. n.normalize();
  23. v.push_back({{px, py, pz}, {n.x(), n.y(), n.z()}, {u, vCoord}});
  24. }
  25. }
  26. int row = radialSegments + 1;
  27. for (int i = 0; i < radialSegments; ++i) {
  28. int a = 0 * row + i;
  29. int b = 0 * row + i + 1;
  30. int c = 1 * row + i + 1;
  31. int d = 1 * row + i;
  32. idx.push_back(a);
  33. idx.push_back(b);
  34. idx.push_back(c);
  35. idx.push_back(c);
  36. idx.push_back(d);
  37. idx.push_back(a);
  38. }
  39. int baseTop = (int)v.size();
  40. v.push_back({{0.0f, halfH, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.5f, 0.5f}});
  41. for (int i = 0; i <= radialSegments; ++i) {
  42. float u = float(i) / float(radialSegments);
  43. float ang = u * 6.28318530718f;
  44. float px = radius * std::cos(ang);
  45. float pz = radius * std::sin(ang);
  46. v.push_back({{px, halfH, pz},
  47. {0.0f, 1.0f, 0.0f},
  48. {0.5f + 0.5f * std::cos(ang), 0.5f + 0.5f * std::sin(ang)}});
  49. }
  50. for (int i = 1; i <= radialSegments; ++i) {
  51. idx.push_back(baseTop);
  52. idx.push_back(baseTop + i);
  53. idx.push_back(baseTop + i + 1);
  54. }
  55. int baseBot = (int)v.size();
  56. v.push_back({{0.0f, -halfH, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.5f, 0.5f}});
  57. for (int i = 0; i <= radialSegments; ++i) {
  58. float u = float(i) / float(radialSegments);
  59. float ang = u * 6.28318530718f;
  60. float px = radius * std::cos(ang);
  61. float pz = radius * std::sin(ang);
  62. v.push_back({{px, -halfH, pz},
  63. {0.0f, -1.0f, 0.0f},
  64. {0.5f + 0.5f * std::cos(ang), 0.5f + 0.5f * std::sin(ang)}});
  65. }
  66. for (int i = 1; i <= radialSegments; ++i) {
  67. idx.push_back(baseBot);
  68. idx.push_back(baseBot + i + 1);
  69. idx.push_back(baseBot + i);
  70. }
  71. return new Mesh(v, idx);
  72. }
  73. Mesh *createUnitSphereMesh(int latSegments, int lonSegments) {
  74. const float r = 1.0f;
  75. std::vector<Vertex> v;
  76. std::vector<unsigned int> idx;
  77. for (int y = 0; y <= latSegments; ++y) {
  78. float vy = float(y) / float(latSegments);
  79. float phi = vy * 3.14159265358979323846f;
  80. float py = r * std::cos(phi);
  81. float pr = r * std::sin(phi);
  82. for (int x = 0; x <= lonSegments; ++x) {
  83. float vx = float(x) / float(lonSegments);
  84. float theta = vx * 6.28318530717958647692f;
  85. float px = pr * std::cos(theta);
  86. float pz = pr * std::sin(theta);
  87. QVector3D n(px, py, pz);
  88. n.normalize();
  89. v.push_back({{px, py, pz}, {n.x(), n.y(), n.z()}, {vx, vy}});
  90. }
  91. }
  92. int row = lonSegments + 1;
  93. for (int y = 0; y < latSegments; ++y) {
  94. for (int x = 0; x < lonSegments; ++x) {
  95. int a = y * row + x;
  96. int b = a + 1;
  97. int c = (y + 1) * row + x + 1;
  98. int d = (y + 1) * row + x;
  99. idx.push_back(a);
  100. idx.push_back(b);
  101. idx.push_back(c);
  102. idx.push_back(c);
  103. idx.push_back(d);
  104. idx.push_back(a);
  105. }
  106. }
  107. return new Mesh(v, idx);
  108. }
  109. Mesh *createUnitConeMesh(int radialSegments) {
  110. const float baseR = 1.0f;
  111. const float halfH = 0.5f;
  112. std::vector<Vertex> v;
  113. std::vector<unsigned int> idx;
  114. int apexIdx = 0;
  115. v.push_back({{0.0f, +halfH, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.5f, 1.0f}});
  116. for (int i = 0; i <= radialSegments; ++i) {
  117. float u = float(i) / float(radialSegments);
  118. float ang = u * 6.28318530718f;
  119. float px = baseR * std::cos(ang);
  120. float pz = baseR * std::sin(ang);
  121. QVector3D n(px, baseR, pz);
  122. n.normalize();
  123. v.push_back({{px, -halfH, pz}, {n.x(), n.y(), n.z()}, {u, 0.0f}});
  124. }
  125. for (int i = 1; i <= radialSegments; ++i) {
  126. idx.push_back(apexIdx);
  127. idx.push_back(i);
  128. idx.push_back(i + 1);
  129. }
  130. int baseCenter = (int)v.size();
  131. v.push_back({{0.0f, -halfH, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.5f, 0.5f}});
  132. int baseStart = (int)v.size();
  133. for (int i = 0; i <= radialSegments; ++i) {
  134. float u = float(i) / float(radialSegments);
  135. float ang = u * 6.28318530718f;
  136. float px = baseR * std::cos(ang);
  137. float pz = baseR * std::sin(ang);
  138. v.push_back({{px, -halfH, pz},
  139. {0.0f, -1.0f, 0.0f},
  140. {0.5f + 0.5f * std::cos(ang), 0.5f + 0.5f * std::sin(ang)}});
  141. }
  142. for (int i = 0; i < radialSegments; ++i) {
  143. idx.push_back(baseCenter);
  144. idx.push_back(baseStart + i + 1);
  145. idx.push_back(baseStart + i);
  146. }
  147. return new Mesh(v, idx);
  148. }
  149. Mesh *createCapsuleMesh(int radialSegments, int heightSegments) {
  150. const float radius = 0.25f;
  151. const float halfH = 0.5f;
  152. std::vector<Vertex> verts;
  153. std::vector<unsigned int> idx;
  154. for (int y = 0; y <= heightSegments; ++y) {
  155. float v = float(y) / float(heightSegments);
  156. float py = -halfH + v * (2.0f * halfH);
  157. for (int i = 0; i <= radialSegments; ++i) {
  158. float u = float(i) / float(radialSegments);
  159. float ang = u * 6.2831853f;
  160. float px = radius * std::cos(ang);
  161. float pz = radius * std::sin(ang);
  162. QVector3D n(px, 0.0f, pz);
  163. n.normalize();
  164. verts.push_back({{px, py, pz}, {n.x(), n.y(), n.z()}, {u, v}});
  165. }
  166. }
  167. int row = radialSegments + 1;
  168. for (int y = 0; y < heightSegments; ++y) {
  169. for (int i = 0; i < radialSegments; ++i) {
  170. int a = y * row + i;
  171. int b = y * row + i + 1;
  172. int c = (y + 1) * row + i + 1;
  173. int d = (y + 1) * row + i;
  174. idx.push_back(a);
  175. idx.push_back(b);
  176. idx.push_back(c);
  177. idx.push_back(c);
  178. idx.push_back(d);
  179. idx.push_back(a);
  180. }
  181. }
  182. int baseTop = (int)verts.size();
  183. verts.push_back({{0.0f, halfH, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.5f, 0.5f}});
  184. for (int i = 0; i <= radialSegments; ++i) {
  185. float u = float(i) / float(radialSegments);
  186. float ang = u * 6.2831853f;
  187. float px = radius * std::cos(ang);
  188. float pz = radius * std::sin(ang);
  189. verts.push_back(
  190. {{px, halfH, pz},
  191. {0.0f, 1.0f, 0.0f},
  192. {0.5f + 0.5f * std::cos(ang), 0.5f + 0.5f * std::sin(ang)}});
  193. }
  194. for (int i = 1; i <= radialSegments; ++i) {
  195. idx.push_back(baseTop);
  196. idx.push_back(baseTop + i);
  197. idx.push_back(baseTop + i + 1);
  198. }
  199. int baseBot = (int)verts.size();
  200. verts.push_back({{0.0f, -halfH, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.5f, 0.5f}});
  201. for (int i = 0; i <= radialSegments; ++i) {
  202. float u = float(i) / float(radialSegments);
  203. float ang = u * 6.2831853f;
  204. float px = radius * std::cos(ang);
  205. float pz = radius * std::sin(ang);
  206. verts.push_back(
  207. {{px, -halfH, pz},
  208. {0.0f, -1.0f, 0.0f},
  209. {0.5f + 0.5f * std::cos(ang), 0.5f + 0.5f * std::sin(ang)}});
  210. }
  211. for (int i = 1; i <= radialSegments; ++i) {
  212. idx.push_back(baseBot);
  213. idx.push_back(baseBot + i + 1);
  214. idx.push_back(baseBot + i);
  215. }
  216. return new Mesh(verts, idx);
  217. }
  218. float simpleHash(float seed) {
  219. float x = std::sin(seed * 12.9898f) * 43758.5453f;
  220. return x - std::floor(x);
  221. }
  222. Mesh *createUnitTorsoMesh(int radialSegments, int heightSegments) {
  223. const float halfH = 0.5f;
  224. const float TWO_PI = 6.28318530718f;
  225. const bool invertProfile = true;
  226. auto clampf = [](float x, float a, float b) {
  227. return x < a ? a : (x > b ? b : x);
  228. };
  229. auto smoothstep01 = [&](float x) {
  230. x = clampf(x, 0.0f, 1.0f);
  231. return x * x * (3.0f - 2.0f * x);
  232. };
  233. auto smoothBand = [&](float t, float a, float b) {
  234. float enter = smoothstep01((t - a) / (b - a + 1e-6f));
  235. float exit = smoothstep01((t - b) / (a - b - 1e-6f));
  236. float v = enter < exit ? enter : exit;
  237. return clampf(v, 0.0f, 1.0f);
  238. };
  239. struct Axes {
  240. float ax;
  241. float az;
  242. };
  243. struct Key {
  244. float t;
  245. Axes A;
  246. };
  247. const Key keys[] = {
  248. {0.10f, {0.98f, 0.92f}}, {0.20f, {1.02f, 0.96f}}, {0.45f, {0.82f, 0.78f}},
  249. {0.65f, {1.20f, 1.04f}}, {0.85f, {1.42f, 1.18f}}, {1.02f, {1.60f, 1.06f}},
  250. {1.10f, {1.20f, 0.96f}},
  251. };
  252. constexpr int KEY_COUNT = sizeof(keys) / sizeof(keys[0]);
  253. auto catRom = [](float p0, float p1, float p2, float p3, float u) {
  254. return 0.5f * ((2.0f * p1) + (-p0 + p2) * u +
  255. (2.0f * p0 - 5.0f * p1 + 4.0f * p2 - p3) * u * u +
  256. (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * u * u * u);
  257. };
  258. auto sampleAxes = [&](float t) -> Axes {
  259. t = clampf(t, 0.0f, 1.0f);
  260. int i = 0;
  261. while (i + 1 < KEY_COUNT && t > keys[i + 1].t) {
  262. ++i;
  263. }
  264. int i0 = i > 0 ? i - 1 : 0;
  265. int i1 = i;
  266. int i2 = (i + 1 < KEY_COUNT) ? i + 1 : KEY_COUNT - 1;
  267. int i3 = (i + 2 < KEY_COUNT) ? i + 2 : KEY_COUNT - 1;
  268. float denom = (keys[i2].t - keys[i1].t);
  269. float u = denom > 1e-6f ? (t - keys[i1].t) / denom : 0.0f;
  270. u = clampf(u, 0.0f, 1.0f);
  271. float ax =
  272. catRom(keys[i0].A.ax, keys[i1].A.ax, keys[i2].A.ax, keys[i3].A.ax, u);
  273. float az =
  274. catRom(keys[i0].A.az, keys[i1].A.az, keys[i2].A.az, keys[i3].A.az, u);
  275. return {ax, az};
  276. };
  277. auto ellipseRadius = [](float a, float b, float ang) {
  278. float c = std::cos(ang), s = std::sin(ang);
  279. float denom = std::sqrt((b * b * c * c) + (a * a * s * s));
  280. return (a * b) / (denom + 1e-8f);
  281. };
  282. auto xOffsetAt = [&](float t) {
  283. return 0.02f * smoothBand(t, 0.6f, 0.95f) -
  284. 0.01f * smoothBand(t, 0.0f, 0.2f);
  285. };
  286. auto zOffsetAt = [&](float t) {
  287. float lordosis = -0.03f * smoothBand(t, 0.15f, 0.40f);
  288. float chestFwd = 0.035f * smoothBand(t, 0.65f, 0.85f);
  289. float neckBack = -0.015f * smoothBand(t, 0.90f, 1.00f);
  290. return lordosis + chestFwd + neckBack;
  291. };
  292. auto twistAt = [&](float t) { return 0.10f * smoothBand(t, 0.55f, 0.95f); };
  293. auto thetaScale = [&](float t, float ang) {
  294. float s = 0.0f;
  295. float sinA = std::sin(ang), cosA = std::cos(ang), cos2 = cosA * cosA;
  296. s += 0.07f * smoothBand(t, 0.68f, 0.88f) * std::max(0.0f, sinA);
  297. s += -0.03f * smoothBand(t, 0.65f, 0.90f) * std::max(0.0f, -sinA);
  298. s += 0.06f * smoothBand(t, 0.55f, 0.75f) * cos2;
  299. s += -0.02f * smoothBand(t, 0.40f, 0.55f) * cos2;
  300. s += 0.015f * smoothBand(t, 0.70f, 0.95f) * cosA;
  301. return 1.0f + s;
  302. };
  303. auto micro = [](float s) {
  304. float f = std::sin(s * 12.9898f) * 43758.5453f;
  305. return f - std::floor(f);
  306. };
  307. auto samplePos = [&](float t, float ang) -> QVector3D {
  308. float ts = invertProfile ? (1.0f - t) : t;
  309. Axes A = sampleAxes(ts);
  310. float twist = twistAt(ts);
  311. float th = ang + twist;
  312. float R = ellipseRadius(A.ax, A.az, th);
  313. float S = thetaScale(ts, th);
  314. float r = R * S;
  315. float px = r * std::cos(th);
  316. float pz = r * std::sin(th);
  317. px += xOffsetAt(ts);
  318. pz += zOffsetAt(ts);
  319. float py = -halfH + t * (2.0f * halfH);
  320. float s = (t * 37.0f) + (ang * 3.0f);
  321. px += (micro(s) - 0.5f) * 0.004f;
  322. pz += (micro(s + 1.23f) - 0.5f) * 0.004f;
  323. return QVector3D(px, py, pz);
  324. };
  325. std::vector<Vertex> v;
  326. std::vector<unsigned int> idx;
  327. v.reserve((radialSegments + 1) * (heightSegments + 1) +
  328. (radialSegments + 1) * 2 + 2);
  329. idx.reserve(radialSegments * heightSegments * 6 + radialSegments * 6);
  330. for (int y = 0; y <= heightSegments; ++y) {
  331. float t = float(y) / float(heightSegments);
  332. float dt = 1.0f / float(heightSegments);
  333. float vCoord = t;
  334. for (int i = 0; i <= radialSegments; ++i) {
  335. float u = float(i) / float(radialSegments);
  336. float ang = u * TWO_PI;
  337. float da = TWO_PI / float(radialSegments);
  338. QVector3D p = samplePos(t, ang);
  339. QVector3D pu = samplePos(t, ang + da);
  340. QVector3D pv = samplePos(clampf(t + dt, 0.0f, 1.0f), ang);
  341. QVector3D du = pu - p;
  342. QVector3D dv = pv - p;
  343. QVector3D n = QVector3D::crossProduct(du, dv);
  344. if (n.lengthSquared() > 0.0f) {
  345. n.normalize();
  346. }
  347. v.push_back({{p.x(), p.y(), p.z()}, {n.x(), n.y(), n.z()}, {u, vCoord}});
  348. }
  349. }
  350. int row = radialSegments + 1;
  351. for (int y = 0; y < heightSegments; ++y) {
  352. for (int i = 0; i < radialSegments; ++i) {
  353. int a = y * row + i;
  354. int b = y * row + i + 1;
  355. int c = (y + 1) * row + i + 1;
  356. int d = (y + 1) * row + i;
  357. idx.push_back(a);
  358. idx.push_back(b);
  359. idx.push_back(c);
  360. idx.push_back(c);
  361. idx.push_back(d);
  362. idx.push_back(a);
  363. }
  364. }
  365. {
  366. int baseTop = (int)v.size();
  367. float tTop = 1.0f;
  368. float tTopS = invertProfile ? (1.0f - tTop) : tTop;
  369. QVector3D cTop(xOffsetAt(tTopS), halfH, zOffsetAt(tTopS));
  370. v.push_back({{cTop.x(), cTop.y(), cTop.z()}, {0, 1, 0}, {0.5f, 0.5f}});
  371. for (int i = 0; i <= radialSegments; ++i) {
  372. float u = float(i) / float(radialSegments);
  373. float ang = u * TWO_PI;
  374. QVector3D p = samplePos(tTop, ang);
  375. v.push_back({{p.x(), p.y(), p.z()},
  376. {0, 1, 0},
  377. {0.5f + 0.5f * std::cos(ang), 0.5f + 0.5f * std::sin(ang)}});
  378. }
  379. for (int i = 1; i <= radialSegments; ++i) {
  380. idx.push_back(baseTop);
  381. idx.push_back(baseTop + i);
  382. idx.push_back(baseTop + i + 1);
  383. }
  384. }
  385. {
  386. int baseBot = (int)v.size();
  387. float tBot = 0.0f;
  388. float tBotS = invertProfile ? (1.0f - tBot) : tBot;
  389. QVector3D cBot(xOffsetAt(tBotS), -halfH, zOffsetAt(tBotS));
  390. v.push_back({{cBot.x(), cBot.y(), cBot.z()}, {0, -1, 0}, {0.5f, 0.5f}});
  391. for (int i = 0; i <= radialSegments; ++i) {
  392. float u = float(i) / float(radialSegments);
  393. float ang = u * TWO_PI;
  394. QVector3D p = samplePos(tBot, ang);
  395. v.push_back({{p.x(), p.y(), p.z()},
  396. {0, -1, 0},
  397. {0.5f + 0.5f * std::cos(ang), 0.5f + 0.5f * std::sin(ang)}});
  398. }
  399. for (int i = 1; i <= radialSegments; ++i) {
  400. idx.push_back(baseBot);
  401. idx.push_back(baseBot + i + 1);
  402. idx.push_back(baseBot + i);
  403. }
  404. }
  405. return new Mesh(v, idx);
  406. }
  407. } // namespace
  408. Mesh *getUnitCylinder(int radialSegments) {
  409. static std::unique_ptr<Mesh> s_mesh(createUnitCylinderMesh(radialSegments));
  410. return s_mesh.get();
  411. }
  412. Mesh *getUnitSphere(int latSegments, int lonSegments) {
  413. static std::unique_ptr<Mesh> s_mesh(
  414. createUnitSphereMesh(latSegments, lonSegments));
  415. return s_mesh.get();
  416. }
  417. Mesh *getUnitCone(int radialSegments) {
  418. static std::unique_ptr<Mesh> s_mesh(createUnitConeMesh(radialSegments));
  419. return s_mesh.get();
  420. }
  421. Mesh *getUnitCapsule(int radialSegments, int heightSegments) {
  422. static std::unique_ptr<Mesh> s_mesh(
  423. createCapsuleMesh(radialSegments, heightSegments));
  424. return s_mesh.get();
  425. }
  426. Mesh *getUnitTorso(int radialSegments, int heightSegments) {
  427. static std::unique_ptr<Mesh> s_mesh(
  428. createUnitTorsoMesh(radialSegments, heightSegments));
  429. return s_mesh.get();
  430. }
  431. } // namespace Render::GL