/subdivision/src/protolayer/subdivision/CatmullClarkLevel.cpp

https://github.com/williamwaterson/protolayer
C++ | 416 lines | 315 code | 95 blank | 6 comment | 53 complexity | 63753036ad2111c6dbdffffb758343ba MD5 | raw file
  1. #include "CatmullClarkLevel.h"
  2. namespace protolayer
  3. {
  4. namespace subdivision
  5. {
  6. void CatmullClarkLevel::evaluatePositions(Mesh& subdivision)
  7. {
  8. for (int i = 0; i < subdivision.getNumberVertices(); i++) {
  9. Vertex& vertex = subdivision.getVertex(i);
  10. Vertex* mapping = vertex.getMapping();
  11. if (vertex.isCorner()) {
  12. mapping->_gamma = 0;
  13. mapping->_beta = 0;
  14. mapping->_alpha = 1;
  15. } else if (vertex.isBoundary()) {
  16. mapping->_gamma = 0;
  17. mapping->_gamma = 0;
  18. mapping->_beta = 1;
  19. mapping->_beta /= 8;
  20. mapping->_alpha = 3;
  21. mapping->_alpha /= 4;
  22. } else {
  23. mapping->_beta = 3;
  24. mapping->_beta /= 2;
  25. mapping->_beta /= mapping->_valency;
  26. mapping->_gamma = 1;
  27. mapping->_gamma /= 4;
  28. mapping->_gamma /= mapping->_valency;
  29. mapping->_alpha = 1 - mapping->_gamma - mapping->_beta;
  30. mapping->_beta /= mapping->_valency;
  31. mapping->_gamma /= mapping->_valency;
  32. }
  33. mapping->_coordinates[0] = vertex._coordinates[0] * mapping->_alpha;
  34. mapping->_coordinates[1] = vertex._coordinates[1] * mapping->_alpha;
  35. mapping->_coordinates[2] = vertex._coordinates[2] * mapping->_alpha;
  36. }
  37. for (int i = 0; i < subdivision.getNumberFaces(); i++) {
  38. Face& face = subdivision.getFace(i);
  39. Vertex* center = face.getCenter();
  40. float factor = 1;
  41. factor /= face.getNumberVertices();
  42. for (int j = 0; j < face.getNumberVertices(); j++) {
  43. center->_coordinates[0] += face.getVertex(j)._coordinates[0] * factor;
  44. center->_coordinates[1] += face.getVertex(j)._coordinates[1] * factor;
  45. center->_coordinates[2] += face.getVertex(j)._coordinates[2] * factor;
  46. }
  47. center->_coordinates[3] = 1;
  48. }
  49. for (int i = 0; i < subdivision.getNumberEdges(); i++) {
  50. Edge& edge = subdivision.getEdge(i);
  51. HalfEdge& halfEdge = edge.getFirstHalf();
  52. Vertex* midpoint = halfEdge.getMidpoint();
  53. Vertex& fromVertex = edge.getFirstHalf().getFromVertex();
  54. Vertex& toVertex = edge.getFirstHalf().getToVertex();
  55. Vertex* mappedFromVertex = fromVertex.getMapping();
  56. Vertex* mappedToVertex = toVertex.getMapping();
  57. if (edge.isBoundary()) {
  58. midpoint->_coordinates[0] = fromVertex._coordinates[0] + toVertex._coordinates[0];
  59. midpoint->_coordinates[1] = fromVertex._coordinates[1] + toVertex._coordinates[1];
  60. midpoint->_coordinates[2] = fromVertex._coordinates[2] + toVertex._coordinates[2];
  61. midpoint->_coordinates[0] /= 2;
  62. midpoint->_coordinates[1] /= 2;
  63. midpoint->_coordinates[2] /= 2;
  64. if (!mappedFromVertex->isCorner()) {
  65. mappedFromVertex->_coordinates[0] += toVertex._coordinates[0] * mappedFromVertex->_beta;
  66. mappedFromVertex->_coordinates[1] += toVertex._coordinates[1] * mappedFromVertex->_beta;
  67. mappedFromVertex->_coordinates[2] += toVertex._coordinates[2] * mappedFromVertex->_beta;
  68. }
  69. if (!mappedToVertex->isCorner()) {
  70. mappedToVertex->_coordinates[0] += fromVertex._coordinates[0] * mappedToVertex->_beta;
  71. mappedToVertex->_coordinates[1] += fromVertex._coordinates[1] * mappedToVertex->_beta;
  72. mappedToVertex->_coordinates[2] += fromVertex._coordinates[2] * mappedToVertex->_beta;
  73. }
  74. } else {
  75. float factor = 3;
  76. factor /= 8;
  77. midpoint->_coordinates[0] += halfEdge.getFromVertex()._coordinates[0] * factor;
  78. midpoint->_coordinates[1] += halfEdge.getFromVertex()._coordinates[1] * factor;
  79. midpoint->_coordinates[2] += halfEdge.getFromVertex()._coordinates[2] * factor;
  80. midpoint->_coordinates[0] += halfEdge.getToVertex()._coordinates[0] * factor;
  81. midpoint->_coordinates[1] += halfEdge.getToVertex()._coordinates[1] * factor;
  82. midpoint->_coordinates[2] += halfEdge.getToVertex()._coordinates[2] * factor;
  83. if (mappedFromVertex->isCorner()) {
  84. // Do nothing to mapped from vertex
  85. } else if (mappedFromVertex->isBoundary() && !mappedToVertex->isBoundary()) {
  86. // Do nothing to mapped from vertex
  87. } else if (mappedFromVertex->isBoundary() && mappedToVertex->isBoundary()) {
  88. // Do nothing to mapped from vertex
  89. } else {
  90. mappedFromVertex->_coordinates[0] += toVertex._coordinates[0] * mappedFromVertex->_beta;
  91. mappedFromVertex->_coordinates[1] += toVertex._coordinates[1] * mappedFromVertex->_beta;
  92. mappedFromVertex->_coordinates[2] += toVertex._coordinates[2] * mappedFromVertex->_beta;
  93. }
  94. if (mappedToVertex->isCorner()) {
  95. // Do nothing to mapped to vertex
  96. } else if (!mappedFromVertex->isBoundary() && mappedToVertex->isBoundary()) {
  97. // Do nothing to mapped to vertex
  98. } else if (mappedFromVertex->isBoundary() && mappedToVertex->isBoundary()) {
  99. // Do nothing to mapped from vertex
  100. } else {
  101. mappedToVertex->_coordinates[0] += fromVertex._coordinates[0] * mappedToVertex->_beta;
  102. mappedToVertex->_coordinates[1] += fromVertex._coordinates[1] * mappedToVertex->_beta;
  103. mappedToVertex->_coordinates[2] += fromVertex._coordinates[2] * mappedToVertex->_beta;
  104. }
  105. }
  106. }
  107. for (int i = 0; i < subdivision.getNumberFaces(); i++) {
  108. Face& face = subdivision.getFace(i);
  109. {
  110. HalfEdge& halfEdge = face.getHalfEdge(0);
  111. if (!halfEdge.isBoundary()) {
  112. Vertex* midpoint = halfEdge.getMidpoint();
  113. Vertex& from = face.getHalfEdge(2).getFromVertex();
  114. Vertex& to = face.getHalfEdge(2).getToVertex();
  115. midpoint->_coordinates[0] += from._coordinates[0] / 16;
  116. midpoint->_coordinates[1] += from._coordinates[1] / 16;
  117. midpoint->_coordinates[2] += from._coordinates[2] / 16;
  118. midpoint->_coordinates[0] += to._coordinates[0] / 16;
  119. midpoint->_coordinates[1] += to._coordinates[1] / 16;
  120. midpoint->_coordinates[2] += to._coordinates[2] / 16;
  121. }
  122. }
  123. {
  124. HalfEdge& halfEdge = face.getHalfEdge(1);
  125. if (!halfEdge.isBoundary()) {
  126. Vertex* midpoint = halfEdge.getMidpoint();
  127. Vertex& from = face.getHalfEdge(3).getFromVertex();
  128. Vertex& to = face.getHalfEdge(3).getToVertex();
  129. midpoint->_coordinates[0] += from._coordinates[0] / 16;
  130. midpoint->_coordinates[1] += from._coordinates[1] / 16;
  131. midpoint->_coordinates[2] += from._coordinates[2] / 16;
  132. midpoint->_coordinates[0] += to._coordinates[0] / 16;
  133. midpoint->_coordinates[1] += to._coordinates[1] / 16;
  134. midpoint->_coordinates[2] += to._coordinates[2] / 16;
  135. }
  136. }
  137. {
  138. HalfEdge& halfEdge = face.getHalfEdge(2);
  139. if (!halfEdge.isBoundary()) {
  140. Vertex* midpoint = halfEdge.getMidpoint();
  141. Vertex& from = face.getHalfEdge(0).getFromVertex();
  142. Vertex& to = face.getHalfEdge(0).getToVertex();
  143. midpoint->_coordinates[0] += from._coordinates[0] / 16;
  144. midpoint->_coordinates[1] += from._coordinates[1] / 16;
  145. midpoint->_coordinates[2] += from._coordinates[2] / 16;
  146. midpoint->_coordinates[0] += to._coordinates[0] / 16;
  147. midpoint->_coordinates[1] += to._coordinates[1] / 16;
  148. midpoint->_coordinates[2] += to._coordinates[2] / 16;
  149. }
  150. }
  151. {
  152. HalfEdge& halfEdge = face.getHalfEdge(3);
  153. if (!halfEdge.isBoundary()) {
  154. Vertex* midpoint = halfEdge.getMidpoint();
  155. Vertex& from = face.getHalfEdge(1).getFromVertex();
  156. Vertex& to = face.getHalfEdge(1).getToVertex();
  157. midpoint->_coordinates[0] += from._coordinates[0] / 16;
  158. midpoint->_coordinates[1] += from._coordinates[1] / 16;
  159. midpoint->_coordinates[2] += from._coordinates[2] / 16;
  160. midpoint->_coordinates[0] += to._coordinates[0] / 16;
  161. midpoint->_coordinates[1] += to._coordinates[1] / 16;
  162. midpoint->_coordinates[2] += to._coordinates[2] / 16;
  163. }
  164. }
  165. {
  166. Vertex& vertex = face.getVertex(0);
  167. if (!vertex.isBoundary()) {
  168. Vertex* mapping = vertex.getMapping();
  169. Vertex& opposite = face.getVertex(2);
  170. mapping->_coordinates[0] += opposite._coordinates[0] * mapping->_gamma;
  171. mapping->_coordinates[1] += opposite._coordinates[1] * mapping->_gamma;
  172. mapping->_coordinates[2] += opposite._coordinates[2] * mapping->_gamma;
  173. }
  174. }
  175. {
  176. Vertex& vertex = face.getVertex(1);
  177. if (!vertex.isBoundary()) {
  178. Vertex* mapping = vertex.getMapping();
  179. Vertex& opposite = face.getVertex(3);
  180. mapping->_coordinates[0] += opposite._coordinates[0] * mapping->_gamma;
  181. mapping->_coordinates[1] += opposite._coordinates[1] * mapping->_gamma;
  182. mapping->_coordinates[2] += opposite._coordinates[2] * mapping->_gamma;
  183. }
  184. }
  185. {
  186. Vertex& vertex = face.getVertex(2);
  187. if (!vertex.isBoundary()) {
  188. Vertex* mapping = vertex.getMapping();
  189. Vertex& opposite = face.getVertex(0);
  190. mapping->_coordinates[0] += opposite._coordinates[0] * mapping->_gamma;
  191. mapping->_coordinates[1] += opposite._coordinates[1] * mapping->_gamma;
  192. mapping->_coordinates[2] += opposite._coordinates[2] * mapping->_gamma;
  193. }
  194. }
  195. {
  196. Vertex& vertex = face.getVertex(3);
  197. if (!vertex.isBoundary()) {
  198. Vertex* mapping = vertex.getMapping();
  199. Vertex& opposite = face.getVertex(1);
  200. mapping->_coordinates[0] += opposite._coordinates[0] * mapping->_gamma;
  201. mapping->_coordinates[1] += opposite._coordinates[1] * mapping->_gamma;
  202. mapping->_coordinates[2] += opposite._coordinates[2] * mapping->_gamma;
  203. }
  204. }
  205. }
  206. }
  207. void CatmullClarkLevel::subdivideMesh(Mesh& subdivision)
  208. {
  209. for (int i = 0; i < subdivision.getNumberVertices(); i++) {
  210. Vertex& vertex = subdivision.getVertex(i);
  211. Vertex& created = createVertex(vertex);
  212. vertex.setMapping(created);
  213. }
  214. for (int i = 0; i < subdivision.getNumberEdges(); i++) {
  215. Edge& edge = subdivision.getEdge(i);
  216. bool isBoundary = edge.isBoundary();
  217. HalfEdge& firstHalfEdge = edge.getFirstHalf();
  218. HalfEdge& secondHalfEdge = edge.getSecondHalf();
  219. Vertex& fromVertex = firstHalfEdge.getFromVertex();
  220. Vertex& toVertex = firstHalfEdge.getToVertex();
  221. Vertex* midpoint = new Vertex();
  222. if (isBoundary) {
  223. midpoint->setBoundary(isBoundary);
  224. }
  225. _subdivision.add(*midpoint);
  226. firstHalfEdge.setMidpoint(*midpoint);
  227. secondHalfEdge.setMidpoint(*midpoint);
  228. Vertex* mappedFromVertex = fromVertex.getMapping();
  229. Vertex* mappedToVertex = toVertex.getMapping();
  230. Edge* created = _subdivision.createEdge(*mappedFromVertex, *midpoint);
  231. if (isBoundary) {
  232. created->setBoundary(true);
  233. }
  234. created = _subdivision.createEdge(*midpoint, *mappedToVertex);
  235. if (isBoundary) {
  236. created->setBoundary(true);
  237. }
  238. mappedFromVertex->incrementValency();
  239. mappedToVertex->incrementValency();
  240. }
  241. for (int i = 0; i < subdivision.getNumberFaces(); i++) {
  242. Face& face = subdivision.getFace(i);
  243. Vertex* center = new Vertex();
  244. face.setCenter(*center);
  245. _subdivision.add(*center);
  246. for (int j = 0; j < face.getNumberHalfEdges(); j++) {
  247. HalfEdge& halfEdge = face.getHalfEdge(j);
  248. Vertex* midpoint = halfEdge.getMidpoint();
  249. Edge* edge = _subdivision.createEdge(*midpoint, *center);
  250. }
  251. }
  252. for (int i = 0; i < subdivision.getNumberFaces(); i++) {
  253. Face& face = subdivision.getFace(i);
  254. Vertex* center = face.getCenter();
  255. int numberEdges = face.getNumberHalfEdges();
  256. HalfEdge& lastHalfEdge = face.getHalfEdge(numberEdges - 1);
  257. Vertex* last = lastHalfEdge.getMidpoint();
  258. for (int j = 0; j < face.getNumberHalfEdges(); j++) {
  259. HalfEdge& halfEdge = face.getHalfEdge(j);
  260. Vertex& oldCorner = halfEdge.getFromVertex();
  261. Vertex* corner = oldCorner.getMapping();
  262. Vertex* next = halfEdge.getMidpoint();
  263. Face* createdFace = _subdivision.createFace(*corner, *next, *center, *last);
  264. if (face.isTrackingPropagation()) {
  265. face.getPropagation()->addFace(*createdFace);
  266. }
  267. last = next;
  268. }
  269. }
  270. }
  271. HalfEdge& CatmullClarkLevel::getHalfEdge(Vertex& from,
  272. Vertex& to)
  273. {
  274. HalfEdge* result = 0;
  275. for (int i = 0; i < _subdivision.getNumberEdges(); i++) {
  276. Edge& edge = _subdivision.getEdge(i);
  277. if (edge.getFirstHalf().isEquivalent(from, to)) {
  278. result = &(edge.getFirstHalf());
  279. break;
  280. } else if (edge.getSecondHalf().isEquivalent(from, to)) {
  281. result = &(edge.getSecondHalf());
  282. break;
  283. }
  284. }
  285. assert(result != 0);
  286. return *result;
  287. }
  288. Vertex& CatmullClarkLevel::createVertex(Vertex& copyFromVertex)
  289. {
  290. Vertex* created = new Vertex();
  291. _subdivision.add(*created);
  292. created->_coordinates[0] = copyFromVertex._coordinates[0];
  293. created->_coordinates[1] = copyFromVertex._coordinates[1];
  294. created->_coordinates[2] = copyFromVertex._coordinates[2];
  295. created->_coordinates[3] = copyFromVertex._coordinates[3];
  296. created->_isBoundary = copyFromVertex._isBoundary;
  297. created->_isCorner = copyFromVertex._isCorner;
  298. return *created;
  299. }
  300. CatmullClarkLevel::CatmullClarkLevel(Mesh& mesh)
  301. {
  302. mesh.detectBoundaries();
  303. mesh.detectFlowers();
  304. subdivideMesh(mesh);
  305. evaluatePositions(mesh);
  306. for (int i = 0; i < mesh.getFaces().size(); i++) {
  307. mesh.getFaces()[i]->updateRelativePositions();
  308. mesh.getFaces()[i]->updateNormal();
  309. mesh.getFaces()[i]->updateVertexNormals();
  310. }
  311. }
  312. Mesh& CatmullClarkLevel::getMesh()
  313. {
  314. return _subdivision;
  315. }
  316. const Mesh& CatmullClarkLevel::getMesh() const
  317. {
  318. return _subdivision;
  319. }
  320. }
  321. }