primitives.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  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. int i0 = i > 0 ? i - 1 : 0;
  264. int i1 = i;
  265. int i2 = (i + 1 < KEY_COUNT) ? i + 1 : KEY_COUNT - 1;
  266. int i3 = (i + 2 < KEY_COUNT) ? i + 2 : KEY_COUNT - 1;
  267. float denom = (keys[i2].t - keys[i1].t);
  268. float u = denom > 1e-6f ? (t - keys[i1].t) / denom : 0.0f;
  269. u = clampf(u, 0.0f, 1.0f);
  270. float ax =
  271. catRom(keys[i0].A.ax, keys[i1].A.ax, keys[i2].A.ax, keys[i3].A.ax, u);
  272. float az =
  273. catRom(keys[i0].A.az, keys[i1].A.az, keys[i2].A.az, keys[i3].A.az, u);
  274. return {ax, az};
  275. };
  276. auto ellipseRadius = [](float a, float b, float ang) {
  277. float c = std::cos(ang), s = std::sin(ang);
  278. float denom = std::sqrt((b * b * c * c) + (a * a * s * s));
  279. return (a * b) / (denom + 1e-8f);
  280. };
  281. auto xOffsetAt = [&](float t) {
  282. return 0.02f * smoothBand(t, 0.6f, 0.95f) -
  283. 0.01f * smoothBand(t, 0.0f, 0.2f);
  284. };
  285. auto zOffsetAt = [&](float t) {
  286. float lordosis = -0.03f * smoothBand(t, 0.15f, 0.40f);
  287. float chestFwd = 0.035f * smoothBand(t, 0.65f, 0.85f);
  288. float neckBack = -0.015f * smoothBand(t, 0.90f, 1.00f);
  289. return lordosis + chestFwd + neckBack;
  290. };
  291. auto twistAt = [&](float t) { return 0.10f * smoothBand(t, 0.55f, 0.95f); };
  292. auto thetaScale = [&](float t, float ang) {
  293. float s = 0.0f;
  294. float sinA = std::sin(ang), cosA = std::cos(ang), cos2 = cosA * cosA;
  295. s += 0.07f * smoothBand(t, 0.68f, 0.88f) * std::max(0.0f, sinA);
  296. s += -0.03f * smoothBand(t, 0.65f, 0.90f) * std::max(0.0f, -sinA);
  297. s += 0.06f * smoothBand(t, 0.55f, 0.75f) * cos2;
  298. s += -0.02f * smoothBand(t, 0.40f, 0.55f) * cos2;
  299. s += 0.015f * smoothBand(t, 0.70f, 0.95f) * cosA;
  300. return 1.0f + s;
  301. };
  302. auto micro = [](float s) {
  303. float f = std::sin(s * 12.9898f) * 43758.5453f;
  304. return f - std::floor(f);
  305. };
  306. auto samplePos = [&](float t, float ang) -> QVector3D {
  307. float ts = invertProfile ? (1.0f - t) : t;
  308. Axes A = sampleAxes(ts);
  309. float twist = twistAt(ts);
  310. float th = ang + twist;
  311. float R = ellipseRadius(A.ax, A.az, th);
  312. float S = thetaScale(ts, th);
  313. float r = R * S;
  314. float px = r * std::cos(th);
  315. float pz = r * std::sin(th);
  316. px += xOffsetAt(ts);
  317. pz += zOffsetAt(ts);
  318. float py = -halfH + t * (2.0f * halfH);
  319. float s = (t * 37.0f) + (ang * 3.0f);
  320. px += (micro(s) - 0.5f) * 0.004f;
  321. pz += (micro(s + 1.23f) - 0.5f) * 0.004f;
  322. return QVector3D(px, py, pz);
  323. };
  324. std::vector<Vertex> v;
  325. std::vector<unsigned int> idx;
  326. v.reserve((radialSegments + 1) * (heightSegments + 1) +
  327. (radialSegments + 1) * 2 + 2);
  328. idx.reserve(radialSegments * heightSegments * 6 + radialSegments * 6);
  329. for (int y = 0; y <= heightSegments; ++y) {
  330. float t = float(y) / float(heightSegments);
  331. float dt = 1.0f / float(heightSegments);
  332. float vCoord = t;
  333. for (int i = 0; i <= radialSegments; ++i) {
  334. float u = float(i) / float(radialSegments);
  335. float ang = u * TWO_PI;
  336. float da = TWO_PI / float(radialSegments);
  337. QVector3D p = samplePos(t, ang);
  338. QVector3D pu = samplePos(t, ang + da);
  339. QVector3D pv = samplePos(clampf(t + dt, 0.0f, 1.0f), ang);
  340. QVector3D du = pu - p;
  341. QVector3D dv = pv - p;
  342. QVector3D n = QVector3D::crossProduct(du, dv);
  343. if (n.lengthSquared() > 0.0f)
  344. n.normalize();
  345. v.push_back({{p.x(), p.y(), p.z()}, {n.x(), n.y(), n.z()}, {u, vCoord}});
  346. }
  347. }
  348. int row = radialSegments + 1;
  349. for (int y = 0; y < heightSegments; ++y) {
  350. for (int i = 0; i < radialSegments; ++i) {
  351. int a = y * row + i;
  352. int b = y * row + i + 1;
  353. int c = (y + 1) * row + i + 1;
  354. int d = (y + 1) * row + i;
  355. idx.push_back(a);
  356. idx.push_back(b);
  357. idx.push_back(c);
  358. idx.push_back(c);
  359. idx.push_back(d);
  360. idx.push_back(a);
  361. }
  362. }
  363. {
  364. int baseTop = (int)v.size();
  365. float tTop = 1.0f;
  366. float tTopS = invertProfile ? (1.0f - tTop) : tTop;
  367. QVector3D cTop(xOffsetAt(tTopS), halfH, zOffsetAt(tTopS));
  368. v.push_back({{cTop.x(), cTop.y(), cTop.z()}, {0, 1, 0}, {0.5f, 0.5f}});
  369. for (int i = 0; i <= radialSegments; ++i) {
  370. float u = float(i) / float(radialSegments);
  371. float ang = u * TWO_PI;
  372. QVector3D p = samplePos(tTop, ang);
  373. v.push_back({{p.x(), p.y(), p.z()},
  374. {0, 1, 0},
  375. {0.5f + 0.5f * std::cos(ang), 0.5f + 0.5f * std::sin(ang)}});
  376. }
  377. for (int i = 1; i <= radialSegments; ++i) {
  378. idx.push_back(baseTop);
  379. idx.push_back(baseTop + i);
  380. idx.push_back(baseTop + i + 1);
  381. }
  382. }
  383. {
  384. int baseBot = (int)v.size();
  385. float tBot = 0.0f;
  386. float tBotS = invertProfile ? (1.0f - tBot) : tBot;
  387. QVector3D cBot(xOffsetAt(tBotS), -halfH, zOffsetAt(tBotS));
  388. v.push_back({{cBot.x(), cBot.y(), cBot.z()}, {0, -1, 0}, {0.5f, 0.5f}});
  389. for (int i = 0; i <= radialSegments; ++i) {
  390. float u = float(i) / float(radialSegments);
  391. float ang = u * TWO_PI;
  392. QVector3D p = samplePos(tBot, ang);
  393. v.push_back({{p.x(), p.y(), p.z()},
  394. {0, -1, 0},
  395. {0.5f + 0.5f * std::cos(ang), 0.5f + 0.5f * std::sin(ang)}});
  396. }
  397. for (int i = 1; i <= radialSegments; ++i) {
  398. idx.push_back(baseBot);
  399. idx.push_back(baseBot + i + 1);
  400. idx.push_back(baseBot + i);
  401. }
  402. }
  403. return new Mesh(v, idx);
  404. }
  405. } // namespace
  406. Mesh *getUnitCylinder(int radialSegments) {
  407. static std::unique_ptr<Mesh> s_mesh(createUnitCylinderMesh(radialSegments));
  408. return s_mesh.get();
  409. }
  410. Mesh *getUnitSphere(int latSegments, int lonSegments) {
  411. static std::unique_ptr<Mesh> s_mesh(
  412. createUnitSphereMesh(latSegments, lonSegments));
  413. return s_mesh.get();
  414. }
  415. Mesh *getUnitCone(int radialSegments) {
  416. static std::unique_ptr<Mesh> s_mesh(createUnitConeMesh(radialSegments));
  417. return s_mesh.get();
  418. }
  419. Mesh *getUnitCapsule(int radialSegments, int heightSegments) {
  420. static std::unique_ptr<Mesh> s_mesh(
  421. createCapsuleMesh(radialSegments, heightSegments));
  422. return s_mesh.get();
  423. }
  424. Mesh *getUnitTorso(int radialSegments, int heightSegments) {
  425. static std::unique_ptr<Mesh> s_mesh(
  426. createUnitTorsoMesh(radialSegments, heightSegments));
  427. return s_mesh.get();
  428. }
  429. } // namespace Render::GL