25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

easymeshtransform.cpp 17 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2010—2020 Sam Hocevar <sam@hocevar.net>
  5. // © 2009—2015 Cédric Lecacheur <jordx@free.fr>
  6. // © 2009—2015 Benjamin “Touky” Huet <huet.benjamin@gmail.com>
  7. //
  8. // Lol Engine is free software. It comes without any warranty, to
  9. // the extent permitted by applicable law. You can redistribute it
  10. // and/or modify it under the terms of the Do What the Fuck You Want
  11. // to Public License, Version 2, as published by the WTFPL Task Force.
  12. // See http://www.wtfpl.net/ for more details.
  13. //
  14. #include <lol/engine-internal.h>
  15. // EasyMesh-Transform — The code belonging to transform operations
  16. namespace lol
  17. {
  18. //-----------------------------------------------------------------------------
  19. void EasyMesh::TranslateX(float t) { Translate(vec3(t, 0.f, 0.f)); }
  20. void EasyMesh::TranslateY(float t) { Translate(vec3(0.f, t, 0.f)); }
  21. void EasyMesh::TranslateZ(float t) { Translate(vec3(0.f, 0.f, t)); }
  22. //-----------------------------------------------------------------------------
  23. void EasyMesh::Translate(vec3 const &v)
  24. {
  25. if (BD()->IsEnabled(MeshBuildOperation::CommandRecording))
  26. {
  27. BD()->CmdStack().AddCmd(EasyMeshCmdType::Translate);
  28. BD()->CmdStack() << v;
  29. return;
  30. }
  31. for (int i = std::get<0>(m_cursors.last()); i < m_vert.count(); i++)
  32. m_vert[i].m_coord += v;
  33. }
  34. //-----------------------------------------------------------------------------
  35. void EasyMesh::RotateX(float degrees) { Rotate(degrees, vec3(1, 0, 0)); }
  36. void EasyMesh::RotateY(float degrees) { Rotate(degrees, vec3(0, 1, 0)); }
  37. void EasyMesh::RotateZ(float degrees) { Rotate(degrees, vec3(0, 0, 1)); }
  38. //-----------------------------------------------------------------------------
  39. void EasyMesh::Rotate(float degrees, vec3 const &axis)
  40. {
  41. if (BD()->IsEnabled(MeshBuildOperation::CommandRecording))
  42. {
  43. BD()->CmdStack().AddCmd(EasyMeshCmdType::Rotate);
  44. BD()->CmdStack() << degrees << axis;
  45. return;
  46. }
  47. mat3 m = mat3::rotate(radians(degrees), axis);
  48. for (int i = std::get<0>(m_cursors.last()); i < m_vert.count(); i++)
  49. {
  50. m_vert[i].m_coord = m * m_vert[i].m_coord;
  51. m_vert[i].m_normal = m * m_vert[i].m_normal;
  52. }
  53. }
  54. //-----------------------------------------------------------------------------
  55. void EasyMesh::RadialJitter(float r)
  56. {
  57. if (BD()->IsEnabled(MeshBuildOperation::CommandRecording))
  58. {
  59. BD()->CmdStack().AddCmd(EasyMeshCmdType::RadialJitter);
  60. BD()->CmdStack() << r;
  61. return;
  62. }
  63. easy_array<int> welded;
  64. welded.push(-1);
  65. for (int i = std::get<0>(m_cursors.last()) + 1; i < m_vert.count(); i++)
  66. {
  67. int j, k;
  68. for (j = std::get<0>(m_cursors.last()), k = 0; j < i; j++, k++)
  69. {
  70. if(welded[k] < 0)
  71. {
  72. vec3 diff = m_vert[i].m_coord - m_vert[j].m_coord;
  73. if(diff.x > 0.1f || diff.x < -0.1f)
  74. continue;
  75. if(diff.y > 0.1f || diff.y < -0.1f)
  76. continue;
  77. if(diff.z > 0.1f || diff.z < -0.1f)
  78. continue;
  79. break;
  80. }
  81. }
  82. welded.push(j != i ? j : -1);
  83. }
  84. int i, j;
  85. for (i = std::get<0>(m_cursors.last()), j = 0; i < m_vert.count(); i++, j++)
  86. {
  87. if(welded[j] == -1)
  88. m_vert[i].m_coord *= 1.0f + rand(r);
  89. else
  90. m_vert[i].m_coord = m_vert[welded[j]].m_coord;
  91. }
  92. ComputeNormals(std::get<1>(m_cursors.last()), m_indices.count() - std::get<1>(m_cursors.last()));
  93. }
  94. //-----------------------------------------------------------------------------
  95. void EasyMesh::TaperX(float ny, float nz, float xoff, bool absolute) { DoMeshTransform(MeshTransform::Taper, Axis::X, Axis::X, ny, nz, xoff, absolute); }
  96. void EasyMesh::TaperY(float nx, float nz, float yoff, bool absolute) { DoMeshTransform(MeshTransform::Taper, Axis::Y, Axis::Y, nz, nx, yoff, absolute); }
  97. void EasyMesh::TaperZ(float nx, float ny, float zoff, bool absolute) { DoMeshTransform(MeshTransform::Taper, Axis::Z, Axis::Z, nx, ny, zoff, absolute); }
  98. //-----------------------------------------------------------------------------
  99. void EasyMesh::TwistX(float t, float toff) { DoMeshTransform(MeshTransform::Twist, Axis::X, Axis::X, t, t, toff); }
  100. void EasyMesh::TwistY(float t, float toff) { DoMeshTransform(MeshTransform::Twist, Axis::Y, Axis::Y, t, t, toff); }
  101. void EasyMesh::TwistZ(float t, float toff) { DoMeshTransform(MeshTransform::Twist, Axis::Z, Axis::Z, t, t, toff); }
  102. //-----------------------------------------------------------------------------
  103. void EasyMesh::ShearX(float ny, float nz, float xoff, bool absolute) { DoMeshTransform(MeshTransform::Shear, Axis::X, Axis::X, ny, nz, xoff, absolute); }
  104. void EasyMesh::ShearY(float nx, float nz, float yoff, bool absolute) { DoMeshTransform(MeshTransform::Shear, Axis::Y, Axis::Y, nz, nx, yoff, absolute); }
  105. void EasyMesh::ShearZ(float nx, float ny, float zoff, bool absolute) { DoMeshTransform(MeshTransform::Shear, Axis::Z, Axis::Z, nx, ny, zoff, absolute); }
  106. //-----------------------------------------------------------------------------
  107. void EasyMesh::StretchX(float ny, float nz, float xoff) { DoMeshTransform(MeshTransform::Stretch, Axis::X, Axis::X, ny, nz, xoff); }
  108. void EasyMesh::StretchY(float nx, float nz, float yoff) { DoMeshTransform(MeshTransform::Stretch, Axis::Y, Axis::Y, nz, nx, yoff); }
  109. void EasyMesh::StretchZ(float nx, float ny, float zoff) { DoMeshTransform(MeshTransform::Stretch, Axis::Z, Axis::Z, nx, ny, zoff); }
  110. //-----------------------------------------------------------------------------
  111. void EasyMesh::BendXY(float t, float toff) { DoMeshTransform(MeshTransform::Bend, Axis::X, Axis::Y, t, t, toff); }
  112. void EasyMesh::BendXZ(float t, float toff) { DoMeshTransform(MeshTransform::Bend, Axis::X, Axis::Z, t, t, toff); }
  113. void EasyMesh::BendYX(float t, float toff) { DoMeshTransform(MeshTransform::Bend, Axis::Y, Axis::X, t, t, toff); }
  114. void EasyMesh::BendYZ(float t, float toff) { DoMeshTransform(MeshTransform::Bend, Axis::Y, Axis::Z, t, t, toff); }
  115. void EasyMesh::BendZX(float t, float toff) { DoMeshTransform(MeshTransform::Bend, Axis::Z, Axis::X, t, t, toff); }
  116. void EasyMesh::BendZY(float t, float toff) { DoMeshTransform(MeshTransform::Bend, Axis::Z, Axis::Y, t, t, toff); }
  117. //-----------------------------------------------------------------------------
  118. void EasyMesh::DoMeshTransform(MeshTransform ct, Axis axis0, Axis axis1, float n0, float n1, float noff, bool absolute)
  119. {
  120. if (BD()->IsEnabled(MeshBuildOperation::CommandRecording))
  121. {
  122. BD()->CmdStack().AddCmd(EasyMeshCmdType::MeshTranform);
  123. BD()->CmdStack() << ct << axis0 << axis1 << n0 << n1 << noff << absolute;
  124. return;
  125. }
  126. for (int i = std::get<0>(m_cursors.last()); i < m_vert.count(); i++)
  127. {
  128. switch (ct.ToScalar())
  129. {
  130. case MeshTransform::Taper:
  131. {
  132. float value = m_vert[i].m_coord[axis0.ToScalar()];
  133. if (absolute) value = fabs(value);
  134. m_vert[i].m_coord[(axis0.ToScalar() + 1) % 3] *= max(0.f, 1.f + (n0 * value + noff));
  135. m_vert[i].m_coord[(axis0.ToScalar() + 2) % 3] *= max(0.f, 1.f + (n1 * value + noff));
  136. break;
  137. }
  138. case MeshTransform::Twist:
  139. {
  140. vec3 rotaxis = vec3(1.f); rotaxis[(axis0.ToScalar() + 1) % 3] = .0f; rotaxis[(axis0.ToScalar() + 2) % 3] = .0f;
  141. m_vert[i].m_coord = mat3::rotate(radians(m_vert[i].m_coord[axis0.ToScalar()] * n0 + noff), rotaxis) * m_vert[i].m_coord;
  142. break;
  143. }
  144. case MeshTransform::Shear:
  145. {
  146. float value = m_vert[i].m_coord[axis0.ToScalar()];
  147. if (absolute) value = fabs(value);
  148. m_vert[i].m_coord[(axis0.ToScalar() + 1) % 3] += (n0 * value + noff);
  149. m_vert[i].m_coord[(axis0.ToScalar() + 2) % 3] += (n1 * value + noff);
  150. break;
  151. }
  152. case MeshTransform::Stretch:
  153. {
  154. //float value = fabs(std::get<0>(m_vert[i])[axis0.ToScalar()]);
  155. //std::get<0>(m_vert[i])[(axis0.ToScalar() + 1) % 3] += (lol::pow(value, n0) + noff);
  156. //std::get<0>(m_vert[i])[(axis0.ToScalar() + 2) % 3] += (lol::pow(value, n1) + noff);
  157. break;
  158. }
  159. case MeshTransform::Bend:
  160. {
  161. vec3 rotaxis = vec3(1.f); rotaxis[(axis1.ToScalar() + 1) % 3] = .0f; rotaxis[(axis1.ToScalar() + 2) % 3] = .0f;
  162. m_vert[i].m_coord = mat3::rotate(radians(m_vert[i].m_coord[axis0.ToScalar()] * n0 + noff), rotaxis) * m_vert[i].m_coord;
  163. break;
  164. }
  165. }
  166. }
  167. ComputeNormals(std::get<1>(m_cursors.last()), m_indices.count() - std::get<1>(m_cursors.last()));
  168. }
  169. //-----------------------------------------------------------------------------
  170. void EasyMesh::Scale(float s) { Scale(vec3(s)); }
  171. void EasyMesh::ScaleX(float s) { Scale(vec3(s, 0.f, 0.f)); }
  172. void EasyMesh::ScaleY(float s) { Scale(vec3(0.f, s, 0.f)); }
  173. void EasyMesh::ScaleZ(float s) { Scale(vec3(0.f, 0.f, s)); }
  174. void EasyMesh::Scale(vec3 const &s)
  175. {
  176. if (BD()->IsEnabled(MeshBuildOperation::CommandRecording))
  177. {
  178. BD()->CmdStack().AddCmd(EasyMeshCmdType::Scale);
  179. BD()->CmdStack() << s;
  180. return;
  181. }
  182. vec3 const invs = vec3(1) / s;
  183. for (int i = std::get<0>(m_cursors.last()); i < m_vert.count(); i++)
  184. {
  185. m_vert[i].m_coord *= s;
  186. m_vert[i].m_normal = normalize(m_vert[i].m_normal * invs);
  187. }
  188. /* Flip winding if the scaling involves mirroring */
  189. if (!BD()->IsEnabled(MeshBuildOperation::ScaleWinding) && s.x * s.y * s.z < 0)
  190. {
  191. for (int i = std::get<1>(m_cursors.last()); i < m_indices.count(); i += 3)
  192. {
  193. uint16_t tmp = m_indices[i + 0];
  194. m_indices[i + 0] = m_indices[i + 1];
  195. m_indices[i + 1] = tmp;
  196. }
  197. }
  198. }
  199. //-----------------------------------------------------------------------------
  200. void EasyMesh::MirrorX() { DupAndScale(vec3(-1, 1, 1)); }
  201. void EasyMesh::MirrorY() { DupAndScale(vec3(1, -1, 1)); }
  202. void EasyMesh::MirrorZ() { DupAndScale(vec3(1, 1, -1)); }
  203. //-----------------------------------------------------------------------------
  204. void EasyMesh::DupAndScale(vec3 const &s, bool open_brace)
  205. {
  206. if (BD()->IsEnabled(MeshBuildOperation::CommandRecording))
  207. {
  208. BD()->CmdStack().AddCmd(EasyMeshCmdType::DupAndScale);
  209. BD()->CmdStack() << s << open_brace;
  210. return;
  211. }
  212. int vlen = m_vert.count() - std::get<0>(m_cursors.last());
  213. int tlen = m_indices.count() - std::get<1>(m_cursors.last());
  214. for (int i = 0; i < vlen; i++)
  215. AddDupVertex(std::get<0>(m_cursors.last())++);
  216. for (int i = 0; i < tlen; i++)
  217. m_indices << m_indices[std::get<1>(m_cursors.last())++] + vlen;
  218. Scale(s);
  219. std::get<0>(m_cursors.last()) -= vlen;
  220. std::get<1>(m_cursors.last()) -= tlen;
  221. if (open_brace)
  222. {
  223. OpenBrace();
  224. std::get<0>(m_cursors.last()) -= vlen;
  225. std::get<1>(m_cursors.last()) -= tlen;
  226. }
  227. }
  228. //-----------------------------------------------------------------------------
  229. void EasyMesh::Chamfer(float f)
  230. {
  231. if (BD()->IsEnabled(MeshBuildOperation::CommandRecording))
  232. {
  233. BD()->CmdStack().AddCmd(EasyMeshCmdType::Chamfer);
  234. BD()->CmdStack() << f;
  235. return;
  236. }
  237. int vlen = m_vert.count() - std::get<0>(m_cursors.last());
  238. int ilen = m_indices.count() - std::get<1>(m_cursors.last());
  239. /* Step 1: enumerate all faces. This is done by merging triangles
  240. * that are coplanar and share an edge. */
  241. int *triangle_classes = new int[ilen / 3];
  242. for (int i = 0; i < ilen / 3; i++)
  243. triangle_classes[i] = -1;
  244. for (int i = 0; i < ilen / 3; i++)
  245. {
  246. }
  247. /* Fun shit: reduce all triangles */
  248. int *vertices = new int[vlen];
  249. memset(vertices, 0, vlen * sizeof(int));
  250. for (int i = 0; i < ilen; i++)
  251. vertices[m_indices[i]]++;
  252. for (int i = 0; i < ilen / 3; i++)
  253. {
  254. #if 0
  255. if (vertices[m_indices[i * 3]] > 1)
  256. continue;
  257. if (vertices[m_indices[i * 3 + 1]] > 1)
  258. continue;
  259. if (vertices[m_indices[i * 3 + 2]] > 1)
  260. continue;
  261. #endif
  262. vec3 bary = 1.f / 3.f * (m_vert[m_indices[i * 3]].m_coord +
  263. m_vert[m_indices[i * 3 + 1]].m_coord +
  264. m_vert[m_indices[i * 3 + 2]].m_coord);
  265. for (int k = 0; k < 3; k++)
  266. {
  267. vec3 &p = m_vert[m_indices[i * 3 + k]].m_coord;
  268. p -= normalize(p - bary) * f;
  269. }
  270. }
  271. }
  272. //-----------------------------------------------------------------------------
  273. void EasyMesh::SplitTriangles(int pass)
  274. {
  275. if (BD()->IsEnabled(MeshBuildOperation::CommandRecording))
  276. {
  277. BD()->CmdStack().AddCmd(EasyMeshCmdType::SplitTriangles);
  278. BD()->CmdStack() << pass;
  279. return;
  280. }
  281. SplitTriangles(pass, nullptr);
  282. }
  283. //-----------------------------------------------------------------------------
  284. void EasyMesh::SplitTriangles(int pass, VertexDictionnary *vert_dict)
  285. {
  286. while (pass--)
  287. {
  288. int trimax = m_indices.count();
  289. for (int i = std::get<1>(m_cursors.last()); i < trimax; i += 3)
  290. {
  291. int vbase = m_vert.count();
  292. int j = -1;
  293. while (++j < 3)
  294. {
  295. AddLerpVertex(m_indices[i + j], m_indices[i + (j + 1) % 3], .5f);
  296. if (vert_dict)
  297. vert_dict->RegisterVertex(vbase + j, m_vert[vbase + j].m_coord);
  298. }
  299. //Add new triangles
  300. AddTriangle(vbase, m_indices[i + 1], vbase + 1, 0);
  301. AddTriangle(vbase + 2, vbase + 1, m_indices[i + 2], 0);
  302. AddTriangle(vbase, vbase + 1, vbase + 2, 0);
  303. //Change current triangle
  304. m_indices[i + 1] = vbase;
  305. m_indices[i + 2] = vbase + 2;
  306. }
  307. }
  308. ComputeNormals(std::get<1>(m_cursors.last()), m_indices.count() - std::get<1>(m_cursors.last()));
  309. }
  310. //-----------------------------------------------------------------------------
  311. //TODO : Add an half-edges implementation to refine smooth.
  312. //TODO : Smooth should only use connected vertices that are on edges of the mesh (See box).
  313. void EasyMesh::SmoothMesh(int main_pass, int split_per_main_pass, int smooth_per_main_pass)
  314. {
  315. if (BD()->IsEnabled(MeshBuildOperation::CommandRecording))
  316. {
  317. BD()->CmdStack().AddCmd(EasyMeshCmdType::SmoothMesh);
  318. BD()->CmdStack() << main_pass << split_per_main_pass << smooth_per_main_pass;
  319. return;
  320. }
  321. VertexDictionnary vert_dict;
  322. easy_array<vec3> smooth_buf[2];
  323. easy_array<int> master_list;
  324. easy_array<int> matching_ids;
  325. easy_array<int> connected_vert;
  326. int smbuf = 0;
  327. for (int i = std::get<0>(m_cursors.last()); i < m_vert.count(); i++)
  328. vert_dict.RegisterVertex(i, m_vert[i].m_coord);
  329. while (main_pass--)
  330. {
  331. int split_pass = split_per_main_pass;
  332. int smooth_pass = smooth_per_main_pass;
  333. SplitTriangles(split_pass, &vert_dict);
  334. matching_ids.reserve(m_vert.count() - std::get<0>(m_cursors.last()));
  335. connected_vert.reserve(m_vert.count() - std::get<0>(m_cursors.last()));
  336. smooth_buf[0].resize(m_vert.count() - std::get<0>(m_cursors.last()));
  337. smooth_buf[1].resize(m_vert.count() - std::get<0>(m_cursors.last()));
  338. for (int i = std::get<0>(m_cursors.last()); i < m_vert.count(); i++)
  339. smooth_buf[smbuf][i - std::get<0>(m_cursors.last())] = m_vert[i].m_coord;
  340. while (smooth_pass--)
  341. {
  342. master_list.clear();
  343. if (vert_dict.GetMasterList(master_list))
  344. {
  345. for (int i = 0; i < master_list.count(); i++)
  346. {
  347. connected_vert.clear();
  348. if (vert_dict.FindConnectedVertices(master_list[i], m_indices, std::get<1>(m_cursors.last()), connected_vert))
  349. {
  350. //Calculate vertices sum
  351. vec3 vert_sum = vec3(.0f);
  352. for (int j = 0; j < connected_vert.count(); j++)
  353. vert_sum += smooth_buf[smbuf][connected_vert[j] - std::get<0>(m_cursors.last())];
  354. //Calculate new master vertex
  355. float n = (float)connected_vert.count();
  356. //b(n) = 5/4 - pow(3 + 2 * cos(2.f * F_PI / n), 2) / 32
  357. float beta = 3.f + 2.f * cos(2.f * F_PI / n);
  358. beta = 5.f / 4.f - beta * beta / 32.f;
  359. //a(n) = n * (1 - b(n)) / b(n)
  360. float alpha = (n * (1 - beta)) / beta;
  361. //V = (a(n) * v + v1 + ... + vn) / (a(n) + n)
  362. vec3 new_vert = (alpha * smooth_buf[smbuf][master_list[i] - std::get<0>(m_cursors.last())] + vert_sum) / (alpha + n);
  363. //Set all matching vertices to new value
  364. matching_ids.clear();
  365. matching_ids << master_list[i];
  366. vert_dict.FindMatchingVertices(master_list[i], matching_ids);
  367. for (int j = 0; j < matching_ids.count(); j++)
  368. smooth_buf[1 - smbuf][matching_ids[j] - std::get<0>(m_cursors.last())] = new_vert;
  369. }
  370. }
  371. }
  372. smbuf = 1 - smbuf;
  373. }
  374. for (int i = 0; i < smooth_buf[smbuf].count(); i++)
  375. m_vert[i + std::get<0>(m_cursors.last())].m_coord = smooth_buf[smbuf][i];
  376. }
  377. }
  378. } /* namespace lol */