catmullclark_ring.h 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  1. // ======================================================================== //
  2. // Copyright 2009-2017 Intel Corporation //
  3. // //
  4. // Licensed under the Apache License, Version 2.0 (the "License"); //
  5. // you may not use this file except in compliance with the License. //
  6. // You may obtain a copy of the License at //
  7. // //
  8. // http://www.apache.org/licenses/LICENSE-2.0 //
  9. // //
  10. // Unless required by applicable law or agreed to in writing, software //
  11. // distributed under the License is distributed on an "AS IS" BASIS, //
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
  13. // See the License for the specific language governing permissions and //
  14. // limitations under the License. //
  15. // ======================================================================== //
  16. #pragma once
  17. #include "../common/geometry.h"
  18. #include "../common/buffer.h"
  19. #include "half_edge.h"
  20. #include "catmullclark_coefficients.h"
  21. namespace embree
  22. {
  23. struct __aligned(64) FinalQuad {
  24. Vec3fa vtx[4];
  25. };
  26. template<typename Vertex, typename Vertex_t = Vertex>
  27. struct __aligned(64) CatmullClark1RingT
  28. {
  29. int border_index; //!< edge index where border starts
  30. unsigned int face_valence; //!< number of adjacent quad faces
  31. unsigned int edge_valence; //!< number of adjacent edges (2*face_valence)
  32. float vertex_crease_weight; //!< weight of vertex crease (0 if no vertex crease)
  33. array_t<float,MAX_RING_FACE_VALENCE> crease_weight; //!< edge crease weights for each adjacent edge
  34. float vertex_level; //!< maximal level of all adjacent edges
  35. float edge_level; //!< level of first edge
  36. unsigned int eval_start_index; //!< topology dependent index to start evaluation
  37. unsigned int eval_unique_identifier; //!< topology dependent unique identifier for this ring
  38. Vertex vtx; //!< center vertex
  39. array_t<Vertex,MAX_RING_EDGE_VALENCE> ring; //!< ring of neighboring vertices
  40. public:
  41. CatmullClark1RingT ()
  42. : eval_start_index(0), eval_unique_identifier(0) {} // FIXME: default constructor should be empty
  43. /*! calculates number of bytes required to serialize this structure */
  44. __forceinline size_t bytes() const
  45. {
  46. size_t ofs = 0;
  47. ofs += sizeof(border_index);
  48. ofs += sizeof(face_valence);
  49. assert(2*face_valence == edge_valence);
  50. ofs += sizeof(vertex_crease_weight);
  51. ofs += face_valence*sizeof(float);
  52. ofs += sizeof(vertex_level);
  53. ofs += sizeof(edge_level);
  54. ofs += sizeof(eval_start_index);
  55. ofs += sizeof(eval_unique_identifier);
  56. ofs += sizeof(vtx);
  57. ofs += edge_valence*sizeof(Vertex);
  58. return ofs;
  59. }
  60. template<typename Ty>
  61. static __forceinline void store(char* ptr, size_t& ofs, const Ty& v) {
  62. *(Ty*)&ptr[ofs] = v; ofs += sizeof(Ty);
  63. }
  64. template<typename Ty>
  65. static __forceinline void load(char* ptr, size_t& ofs, Ty& v) {
  66. v = *(Ty*)&ptr[ofs]; ofs += sizeof(Ty);
  67. }
  68. /*! serializes the ring to some memory location */
  69. __forceinline void serialize(char* ptr, size_t& ofs) const
  70. {
  71. store(ptr,ofs,border_index);
  72. store(ptr,ofs,face_valence);
  73. store(ptr,ofs,vertex_crease_weight);
  74. for (size_t i=0; i<face_valence; i++)
  75. store(ptr,ofs,crease_weight[i]);
  76. store(ptr,ofs,vertex_level);
  77. store(ptr,ofs,edge_level);
  78. store(ptr,ofs,eval_start_index);
  79. store(ptr,ofs,eval_unique_identifier);
  80. Vertex_t::storeu(&ptr[ofs],vtx); ofs += sizeof(Vertex);
  81. for (size_t i=0; i<edge_valence; i++) {
  82. Vertex_t::storeu(&ptr[ofs],ring[i]); ofs += sizeof(Vertex);
  83. }
  84. }
  85. /*! deserializes the ring from some memory location */
  86. __forceinline void deserialize(char* ptr, size_t& ofs)
  87. {
  88. load(ptr,ofs,border_index);
  89. load(ptr,ofs,face_valence);
  90. edge_valence = 2*face_valence;
  91. load(ptr,ofs,vertex_crease_weight);
  92. for (size_t i=0; i<face_valence; i++)
  93. load(ptr,ofs,crease_weight[i]);
  94. load(ptr,ofs,vertex_level);
  95. load(ptr,ofs,edge_level);
  96. load(ptr,ofs,eval_start_index);
  97. load(ptr,ofs,eval_unique_identifier);
  98. vtx = Vertex_t::loadu(&ptr[ofs]); ofs += sizeof(Vertex);
  99. for (size_t i=0; i<edge_valence; i++) {
  100. ring[i] = Vertex_t::loadu(&ptr[ofs]); ofs += sizeof(Vertex);
  101. }
  102. }
  103. __forceinline bool hasBorder() const {
  104. return border_index != -1;
  105. }
  106. __forceinline const Vertex& front(size_t i) const {
  107. assert(edge_valence>i);
  108. return ring[i];
  109. }
  110. __forceinline const Vertex& back(size_t i) const {
  111. assert(edge_valence>=i);
  112. return ring[edge_valence-i];
  113. }
  114. __forceinline bool has_last_face() const {
  115. return (size_t)border_index != (size_t)edge_valence-2;
  116. }
  117. __forceinline bool has_opposite_front(size_t i) const {
  118. return (size_t)border_index != 2*i;
  119. }
  120. __forceinline bool has_opposite_back(size_t i) const {
  121. return (size_t)border_index != ((size_t)edge_valence-2-2*i);
  122. }
  123. __forceinline BBox3fa bounds() const
  124. {
  125. BBox3fa bounds ( vtx );
  126. for (size_t i = 0; i<edge_valence ; i++)
  127. bounds.extend( ring[i] );
  128. return bounds;
  129. }
  130. /*! initializes the ring from the half edge structure */
  131. __forceinline void init(const HalfEdge* const h, const char* vertices, size_t stride)
  132. {
  133. border_index = -1;
  134. vtx = Vertex_t::loadu(vertices+h->getStartVertexIndex()*stride);
  135. vertex_crease_weight = h->vertex_crease_weight;
  136. HalfEdge* p = (HalfEdge*) h;
  137. unsigned i=0;
  138. unsigned min_vertex_index = (unsigned)-1;
  139. unsigned min_vertex_index_face = (unsigned)-1;
  140. edge_level = p->edge_level;
  141. vertex_level = 0.0f;
  142. do
  143. {
  144. vertex_level = max(vertex_level,p->edge_level);
  145. crease_weight[i/2] = p->edge_crease_weight;
  146. assert(p->hasOpposite() || p->edge_crease_weight == float(inf));
  147. /* store first two vertices of face */
  148. p = p->next();
  149. const unsigned index0 = p->getStartVertexIndex();
  150. ring[i++] = Vertex_t::loadu(vertices+index0*stride);
  151. if (index0 < min_vertex_index) { min_vertex_index = index0; min_vertex_index_face = i>>1; }
  152. p = p->next();
  153. const unsigned index1 = p->getStartVertexIndex();
  154. ring[i++] = Vertex_t::loadu(vertices+index1*stride);
  155. p = p->next();
  156. /* continue with next face */
  157. if (likely(p->hasOpposite()))
  158. p = p->opposite();
  159. /* if there is no opposite go the long way to the other side of the border */
  160. else
  161. {
  162. /* find minimal start vertex */
  163. const unsigned index0 = p->getStartVertexIndex();
  164. if (index0 < min_vertex_index) { min_vertex_index = index0; min_vertex_index_face = i>>1; }
  165. /*! mark first border edge and store dummy vertex for face between the two border edges */
  166. border_index = i;
  167. crease_weight[i/2] = inf;
  168. ring[i++] = Vertex_t::loadu(vertices+index0*stride);
  169. ring[i++] = vtx; // dummy vertex
  170. /*! goto other side of border */
  171. p = (HalfEdge*) h;
  172. while (p->hasOpposite())
  173. p = p->opposite()->next();
  174. }
  175. } while (p != h);
  176. edge_valence = i;
  177. face_valence = i >> 1;
  178. eval_unique_identifier = min_vertex_index;
  179. eval_start_index = min_vertex_index_face;
  180. assert( hasValidPositions() );
  181. }
  182. __forceinline void subdivide(CatmullClark1RingT& dest) const
  183. {
  184. dest.edge_level = 0.5f*edge_level;
  185. dest.vertex_level = 0.5f*vertex_level;
  186. dest.face_valence = face_valence;
  187. dest.edge_valence = edge_valence;
  188. dest.border_index = border_index;
  189. dest.vertex_crease_weight = max(0.0f,vertex_crease_weight-1.0f);
  190. dest.eval_start_index = eval_start_index;
  191. dest.eval_unique_identifier = eval_unique_identifier;
  192. /* calculate face points */
  193. Vertex_t S = Vertex_t(0.0f);
  194. for (size_t i=0; i<face_valence; i++)
  195. {
  196. size_t face_index = i + eval_start_index; if (face_index >= face_valence) face_index -= face_valence; assert(face_index < face_valence);
  197. size_t index0 = 2*face_index+0; if (index0 >= edge_valence) index0 -= edge_valence; assert(index0 < edge_valence);
  198. size_t index1 = 2*face_index+1; if (index1 >= edge_valence) index1 -= edge_valence; assert(index1 < edge_valence);
  199. size_t index2 = 2*face_index+2; if (index2 >= edge_valence) index2 -= edge_valence; assert(index2 < edge_valence);
  200. S += dest.ring[index1] = ((vtx + ring[index1]) + (ring[index0] + ring[index2])) * 0.25f;
  201. }
  202. /* calculate new edge points */
  203. size_t num_creases = 0;
  204. array_t<size_t,MAX_RING_FACE_VALENCE> crease_id;
  205. for (size_t i=0; i<face_valence; i++)
  206. {
  207. size_t face_index = i + eval_start_index;
  208. if (face_index >= face_valence) face_index -= face_valence;
  209. const float edge_crease = crease_weight[face_index];
  210. dest.crease_weight[face_index] = max(edge_crease-1.0f,0.0f);
  211. size_t index = 2*face_index;
  212. size_t prev_index = face_index == 0 ? edge_valence-1 : 2*face_index-1;
  213. size_t next_index = 2*face_index+1;
  214. const Vertex_t v = vtx + ring[index];
  215. const Vertex_t f = dest.ring[prev_index] + dest.ring[next_index];
  216. S += ring[index];
  217. /* fast path for regular edge points */
  218. if (likely(edge_crease <= 0.0f)) {
  219. dest.ring[index] = (v+f) * 0.25f;
  220. }
  221. /* slower path for hard edge rule */
  222. else {
  223. crease_id[num_creases++] = face_index;
  224. dest.ring[index] = v*0.5f;
  225. /* even slower path for blended edge rule */
  226. if (unlikely(edge_crease < 1.0f)) {
  227. dest.ring[index] = lerp((v+f)*0.25f,v*0.5f,edge_crease);
  228. }
  229. }
  230. }
  231. /* compute new vertex using smooth rule */
  232. const float inv_face_valence = 1.0f / (float)face_valence;
  233. const Vertex_t v_smooth = (Vertex_t) madd(inv_face_valence,S,(float(face_valence)-2.0f)*vtx)*inv_face_valence;
  234. dest.vtx = v_smooth;
  235. /* compute new vertex using vertex_crease_weight rule */
  236. if (unlikely(vertex_crease_weight > 0.0f))
  237. {
  238. if (vertex_crease_weight >= 1.0f) {
  239. dest.vtx = vtx;
  240. } else {
  241. dest.vtx = lerp(v_smooth,vtx,vertex_crease_weight);
  242. }
  243. return;
  244. }
  245. /* no edge crease rule and dart rule */
  246. if (likely(num_creases <= 1))
  247. return;
  248. /* compute new vertex using crease rule */
  249. if (likely(num_creases == 2))
  250. {
  251. /* update vertex using crease rule */
  252. const size_t crease0 = crease_id[0], crease1 = crease_id[1];
  253. const Vertex_t v_sharp = (Vertex_t)(ring[2*crease0] + 6.0f*vtx + ring[2*crease1]) * (1.0f / 8.0f);
  254. dest.vtx = v_sharp;
  255. /* update crease_weights using chaikin rule */
  256. const float crease_weight0 = crease_weight[crease0], crease_weight1 = crease_weight[crease1];
  257. dest.crease_weight[crease0] = max(0.25f*(3.0f*crease_weight0 + crease_weight1)-1.0f,0.0f);
  258. dest.crease_weight[crease1] = max(0.25f*(3.0f*crease_weight1 + crease_weight0)-1.0f,0.0f);
  259. /* interpolate between sharp and smooth rule */
  260. const float v_blend = 0.5f*(crease_weight0+crease_weight1);
  261. if (unlikely(v_blend < 1.0f)) {
  262. dest.vtx = lerp(v_smooth,v_sharp,v_blend);
  263. }
  264. }
  265. /* compute new vertex using corner rule */
  266. else {
  267. dest.vtx = vtx;
  268. }
  269. }
  270. __forceinline bool isRegular1() const
  271. {
  272. if (border_index == -1) {
  273. if (face_valence == 4) return true;
  274. } else {
  275. if (face_valence < 4) return true;
  276. }
  277. return false;
  278. }
  279. __forceinline size_t numEdgeCreases() const
  280. {
  281. ssize_t numCreases = 0;
  282. for (size_t i=0; i<face_valence; i++) {
  283. numCreases += crease_weight[i] > 0.0f;
  284. }
  285. return numCreases;
  286. }
  287. enum Type {
  288. TYPE_NONE = 0, //!< invalid type
  289. TYPE_REGULAR = 1, //!< regular patch when ignoring creases
  290. TYPE_REGULAR_CREASES = 2, //!< regular patch when considering creases
  291. TYPE_GREGORY = 4, //!< gregory patch when ignoring creases
  292. TYPE_GREGORY_CREASES = 8, //!< gregory patch when considering creases
  293. TYPE_CREASES = 16 //!< patch has crease features
  294. };
  295. __forceinline Type type() const
  296. {
  297. /* check if there is an edge crease anywhere */
  298. const size_t numCreases = numEdgeCreases();
  299. const bool noInnerCreases = hasBorder() ? numCreases == 2 : numCreases == 0;
  300. Type crease_mask = (Type) (TYPE_REGULAR | TYPE_GREGORY);
  301. if (noInnerCreases ) crease_mask = (Type) (crease_mask | TYPE_REGULAR_CREASES | TYPE_GREGORY_CREASES);
  302. if (numCreases != 0) crease_mask = (Type) (crease_mask | TYPE_CREASES);
  303. /* calculate if this vertex is regular */
  304. bool hasBorder = border_index != -1;
  305. if (face_valence == 2 && hasBorder) {
  306. if (vertex_crease_weight == 0.0f ) return (Type) (crease_mask & (TYPE_REGULAR | TYPE_REGULAR_CREASES | TYPE_GREGORY | TYPE_GREGORY_CREASES | TYPE_CREASES));
  307. else if (vertex_crease_weight == float(inf)) return (Type) (crease_mask & (TYPE_REGULAR | TYPE_REGULAR_CREASES | TYPE_GREGORY | TYPE_GREGORY_CREASES | TYPE_CREASES));
  308. else return TYPE_CREASES;
  309. }
  310. else if (vertex_crease_weight != 0.0f) return TYPE_CREASES;
  311. else if (face_valence == 3 && hasBorder) return (Type) (crease_mask & (TYPE_REGULAR | TYPE_REGULAR_CREASES | TYPE_GREGORY | TYPE_GREGORY_CREASES | TYPE_CREASES));
  312. else if (face_valence == 4 && !hasBorder) return (Type) (crease_mask & (TYPE_REGULAR | TYPE_REGULAR_CREASES | TYPE_GREGORY | TYPE_GREGORY_CREASES | TYPE_CREASES));
  313. else return (Type) (crease_mask & (TYPE_GREGORY | TYPE_GREGORY_CREASES | TYPE_CREASES));
  314. }
  315. __forceinline bool isFinalResolution(float res) const {
  316. return vertex_level <= res;
  317. }
  318. /* computes the limit vertex */
  319. __forceinline Vertex getLimitVertex() const
  320. {
  321. /* return hard corner */
  322. if (unlikely(std::isinf(vertex_crease_weight)))
  323. return vtx;
  324. /* border vertex rule */
  325. if (unlikely(border_index != -1))
  326. {
  327. const unsigned int second_border_index = border_index+2 >= int(edge_valence) ? 0 : border_index+2;
  328. return (4.0f * vtx + (ring[border_index] + ring[second_border_index])) * 1.0f/6.0f;
  329. }
  330. Vertex_t F( 0.0f );
  331. Vertex_t E( 0.0f );
  332. assert(eval_start_index < face_valence);
  333. for (size_t i=0; i<face_valence; i++) {
  334. size_t index = i+eval_start_index;
  335. if (index >= face_valence) index -= face_valence;
  336. F += ring[2*index+1];
  337. E += ring[2*index];
  338. }
  339. const float n = (float)face_valence;
  340. return (Vertex_t)(n*n*vtx+4.0f*E+F) / ((n+5.0f)*n);
  341. }
  342. /* gets limit tangent in the direction of egde vtx -> ring[0] */
  343. __forceinline Vertex getLimitTangent() const
  344. {
  345. if (unlikely(std::isinf(vertex_crease_weight)))
  346. return ring[0] - vtx;
  347. /* border vertex rule */
  348. if (unlikely(border_index != -1))
  349. {
  350. if (border_index != (int)edge_valence-2 ) {
  351. return ring[0] - vtx;
  352. }
  353. else
  354. {
  355. const unsigned int second_border_index = border_index+2 >= int(edge_valence) ? 0 : border_index+2;
  356. return (ring[second_border_index] - ring[border_index]) * 0.5f;
  357. }
  358. }
  359. Vertex_t alpha( 0.0f );
  360. Vertex_t beta ( 0.0f );
  361. const size_t n = face_valence;
  362. assert(eval_start_index < face_valence);
  363. Vertex_t q( 0.0f );
  364. for (size_t i=0; i<face_valence; i++)
  365. {
  366. size_t index = i+eval_start_index;
  367. if (index >= face_valence) index -= face_valence;
  368. const float a = CatmullClarkPrecomputedCoefficients::table.limittangent_a(index,n);
  369. const float b = CatmullClarkPrecomputedCoefficients::table.limittangent_b(index,n);
  370. alpha += a * ring[2*index];
  371. beta += b * ring[2*index+1];
  372. }
  373. const float sigma = CatmullClarkPrecomputedCoefficients::table.limittangent_c(n);
  374. return sigma * (alpha + beta);
  375. }
  376. /* gets limit tangent in the direction of egde vtx -> ring[edge_valence-2] */
  377. __forceinline Vertex getSecondLimitTangent() const
  378. {
  379. if (unlikely(std::isinf(vertex_crease_weight)))
  380. return ring[2] - vtx;
  381. /* border vertex rule */
  382. if (unlikely(border_index != -1))
  383. {
  384. if (border_index != 2) {
  385. return ring[2] - vtx;
  386. }
  387. else {
  388. const unsigned int second_border_index = border_index+2 >= int(edge_valence) ? 0 : border_index+2;
  389. return (ring[border_index] - ring[second_border_index]) * 0.5f;
  390. }
  391. }
  392. Vertex_t alpha( 0.0f );
  393. Vertex_t beta ( 0.0f );
  394. const size_t n = face_valence;
  395. assert(eval_start_index < face_valence);
  396. for (size_t i=0; i<face_valence; i++)
  397. {
  398. size_t index = i+eval_start_index;
  399. if (index >= face_valence) index -= face_valence;
  400. size_t prev_index = index == 0 ? face_valence-1 : index-1; // need to be bit-wise exact in cosf eval
  401. const float a = CatmullClarkPrecomputedCoefficients::table.limittangent_a(prev_index,n);
  402. const float b = CatmullClarkPrecomputedCoefficients::table.limittangent_b(prev_index,n);
  403. alpha += a * ring[2*index];
  404. beta += b * ring[2*index+1];
  405. }
  406. const float sigma = CatmullClarkPrecomputedCoefficients::table.limittangent_c(n);
  407. return sigma* (alpha + beta);
  408. }
  409. /* gets surface normal */
  410. const Vertex getNormal() const {
  411. return cross(getSecondLimitTangent(),getLimitTangent());
  412. }
  413. /* returns center of the n-th quad in the 1-ring */
  414. __forceinline Vertex getQuadCenter(const size_t index) const
  415. {
  416. const Vertex_t &p0 = vtx;
  417. const Vertex_t &p1 = ring[2*index+0];
  418. const Vertex_t &p2 = ring[2*index+1];
  419. const Vertex_t &p3 = index == face_valence-1 ? ring[0] : ring[2*index+2];
  420. const Vertex p = (p0+p1+p2+p3) * 0.25f;
  421. return p;
  422. }
  423. /* returns center of the n-th edge in the 1-ring */
  424. __forceinline Vertex getEdgeCenter(const size_t index) const {
  425. return (vtx + ring[index*2]) * 0.5f;
  426. }
  427. bool hasValidPositions() const
  428. {
  429. for (size_t i=0; i<edge_valence; i++) {
  430. if (!isvalid(ring[i]))
  431. return false;
  432. }
  433. return true;
  434. }
  435. friend __forceinline std::ostream &operator<<(std::ostream &o, const CatmullClark1RingT &c)
  436. {
  437. o << "vtx " << c.vtx << " size = " << c.edge_valence << ", " <<
  438. "hard_edge = " << c.border_index << ", face_valence " << c.face_valence <<
  439. ", edge_level = " << c.edge_level << ", vertex_level = " << c.vertex_level << ", eval_start_index: " << c.eval_start_index << ", ring: " << std::endl;
  440. for (size_t i=0; i<c.edge_valence; i++) {
  441. o << i << " -> " << c.ring[i];
  442. if (i % 2 == 0) o << " crease = " << c.crease_weight[i/2];
  443. o << std::endl;
  444. }
  445. return o;
  446. }
  447. };
  448. typedef CatmullClark1RingT<Vec3fa,Vec3fa_t> CatmullClark1Ring3fa;
  449. template<typename Vertex, typename Vertex_t = Vertex>
  450. struct __aligned(64) GeneralCatmullClark1RingT
  451. {
  452. typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClark1Ring;
  453. struct Face
  454. {
  455. __forceinline Face() {}
  456. __forceinline Face (int size, float crease_weight)
  457. : size(size), crease_weight(crease_weight) {}
  458. // FIXME: add member that returns total number of vertices
  459. int size; // number of vertices-2 of nth face in ring
  460. float crease_weight;
  461. };
  462. Vertex vtx;
  463. array_t<Vertex,MAX_RING_EDGE_VALENCE> ring;
  464. array_t<Face,MAX_RING_FACE_VALENCE> faces;
  465. unsigned int face_valence;
  466. unsigned int edge_valence;
  467. int border_face;
  468. float vertex_crease_weight;
  469. float vertex_level; //!< maximal level of adjacent edges
  470. float edge_level; // level of first edge
  471. bool only_quads; // true if all faces are quads
  472. unsigned int eval_start_face_index;
  473. unsigned int eval_start_vertex_index;
  474. unsigned int eval_unique_identifier;
  475. public:
  476. GeneralCatmullClark1RingT()
  477. : eval_start_face_index(0), eval_start_vertex_index(0), eval_unique_identifier(0) {}
  478. __forceinline bool isRegular() const
  479. {
  480. if (border_face == -1 && face_valence == 4) return true;
  481. return false;
  482. }
  483. __forceinline bool has_last_face() const {
  484. return border_face != (int)face_valence-1;
  485. }
  486. __forceinline bool has_second_face() const {
  487. return (border_face == -1) || (border_face >= 2);
  488. }
  489. bool hasValidPositions() const
  490. {
  491. for (size_t i=0; i<edge_valence; i++) {
  492. if (!isvalid(ring[i]))
  493. return false;
  494. }
  495. return true;
  496. }
  497. __forceinline void init(const HalfEdge* const h, const char* vertices, size_t stride)
  498. {
  499. only_quads = true;
  500. border_face = -1;
  501. vtx = Vertex_t::loadu(vertices+h->getStartVertexIndex()*stride);
  502. vertex_crease_weight = h->vertex_crease_weight;
  503. HalfEdge* p = (HalfEdge*) h;
  504. unsigned int e=0, f=0;
  505. unsigned min_vertex_index = (unsigned)-1;
  506. unsigned min_vertex_index_face = (unsigned)-1;
  507. unsigned min_vertex_index_vertex = (unsigned)-1;
  508. edge_level = p->edge_level;
  509. vertex_level = 0.0f;
  510. do
  511. {
  512. HalfEdge* p_prev = p->prev();
  513. HalfEdge* p_next = p->next();
  514. const float crease_weight = p->edge_crease_weight;
  515. assert(p->hasOpposite() || p->edge_crease_weight == float(inf));
  516. vertex_level = max(vertex_level,p->edge_level);
  517. /* find minimal start vertex */
  518. unsigned vertex_index = p_next->getStartVertexIndex();
  519. if (vertex_index < min_vertex_index) { min_vertex_index = vertex_index; min_vertex_index_face = f; min_vertex_index_vertex = e; }
  520. /* store first N-2 vertices of face */
  521. unsigned int vn = 0;
  522. for (p = p_next; p!=p_prev; p=p->next()) {
  523. ring[e++] = Vertex_t::loadu(vertices+p->getStartVertexIndex()*stride);
  524. vn++;
  525. }
  526. faces[f++] = Face(vn,crease_weight);
  527. only_quads &= (vn == 2);
  528. /* continue with next face */
  529. if (likely(p->hasOpposite()))
  530. p = p->opposite();
  531. /* if there is no opposite go the long way to the other side of the border */
  532. else
  533. {
  534. /* find minimal start vertex */
  535. unsigned vertex_index = p->getStartVertexIndex();
  536. if (vertex_index < min_vertex_index) { min_vertex_index = vertex_index; min_vertex_index_face = f; min_vertex_index_vertex = e; }
  537. /*! mark first border edge and store dummy vertex for face between the two border edges */
  538. border_face = f;
  539. faces[f++] = Face(2,inf);
  540. ring[e++] = Vertex_t::loadu(vertices+p->getStartVertexIndex()*stride);
  541. ring[e++] = vtx; // dummy vertex
  542. /*! goto other side of border */
  543. p = (HalfEdge*) h;
  544. while (p->hasOpposite())
  545. p = p->opposite()->next();
  546. }
  547. } while (p != h);
  548. edge_valence = e;
  549. face_valence = f;
  550. eval_unique_identifier = min_vertex_index;
  551. eval_start_face_index = min_vertex_index_face;
  552. eval_start_vertex_index = min_vertex_index_vertex;
  553. assert( hasValidPositions() );
  554. }
  555. __forceinline void subdivide(CatmullClark1Ring& dest) const
  556. {
  557. dest.edge_level = 0.5f*edge_level;
  558. dest.vertex_level = 0.5f*vertex_level;
  559. dest.face_valence = face_valence;
  560. dest.edge_valence = 2*face_valence;
  561. dest.border_index = border_face == -1 ? -1 : 2*border_face; // FIXME:
  562. dest.vertex_crease_weight = max(0.0f,vertex_crease_weight-1.0f);
  563. dest.eval_start_index = eval_start_face_index;
  564. dest.eval_unique_identifier = eval_unique_identifier;
  565. assert(dest.face_valence <= MAX_RING_FACE_VALENCE);
  566. /* calculate face points */
  567. Vertex_t S = Vertex_t(0.0f);
  568. for (size_t face=0, v=eval_start_vertex_index; face<face_valence; face++) {
  569. size_t f = (face + eval_start_face_index)%face_valence;
  570. Vertex_t F = vtx;
  571. for (size_t k=v; k<=v+faces[f].size; k++) F += ring[k%edge_valence]; // FIXME: optimize
  572. S += dest.ring[2*f+1] = F/float(faces[f].size+2);
  573. v+=faces[f].size;
  574. v%=edge_valence;
  575. }
  576. /* calculate new edge points */
  577. size_t num_creases = 0;
  578. array_t<size_t,MAX_RING_FACE_VALENCE> crease_id;
  579. Vertex_t C = Vertex_t(0.0f);
  580. for (size_t face=0, j=eval_start_vertex_index; face<face_valence; face++)
  581. {
  582. size_t i = (face + eval_start_face_index)%face_valence;
  583. const Vertex_t v = vtx + ring[j];
  584. Vertex_t f = dest.ring[2*i+1];
  585. if (i == 0) f += dest.ring[dest.edge_valence-1];
  586. else f += dest.ring[2*i-1];
  587. S += ring[j];
  588. dest.crease_weight[i] = max(faces[i].crease_weight-1.0f,0.0f);
  589. /* fast path for regular edge points */
  590. if (likely(faces[i].crease_weight <= 0.0f)) {
  591. dest.ring[2*i] = (v+f) * 0.25f;
  592. }
  593. /* slower path for hard edge rule */
  594. else {
  595. C += ring[j]; crease_id[num_creases++] = i;
  596. dest.ring[2*i] = v*0.5f;
  597. /* even slower path for blended edge rule */
  598. if (unlikely(faces[i].crease_weight < 1.0f)) {
  599. dest.ring[2*i] = lerp((v+f)*0.25f,v*0.5f,faces[i].crease_weight);
  600. }
  601. }
  602. j+=faces[i].size;
  603. j%=edge_valence;
  604. }
  605. /* compute new vertex using smooth rule */
  606. const float inv_face_valence = 1.0f / (float)face_valence;
  607. const Vertex_t v_smooth = (Vertex_t) madd(inv_face_valence,S,(float(face_valence)-2.0f)*vtx)*inv_face_valence;
  608. dest.vtx = v_smooth;
  609. /* compute new vertex using vertex_crease_weight rule */
  610. if (unlikely(vertex_crease_weight > 0.0f))
  611. {
  612. if (vertex_crease_weight >= 1.0f) {
  613. dest.vtx = vtx;
  614. } else {
  615. dest.vtx = lerp(vtx,v_smooth,vertex_crease_weight);
  616. }
  617. return;
  618. }
  619. if (likely(num_creases <= 1))
  620. return;
  621. /* compute new vertex using crease rule */
  622. if (likely(num_creases == 2)) {
  623. const Vertex_t v_sharp = (Vertex_t)(C + 6.0f * vtx) * (1.0f / 8.0f);
  624. const float crease_weight0 = faces[crease_id[0]].crease_weight;
  625. const float crease_weight1 = faces[crease_id[1]].crease_weight;
  626. dest.vtx = v_sharp;
  627. dest.crease_weight[crease_id[0]] = max(0.25f*(3.0f*crease_weight0 + crease_weight1)-1.0f,0.0f);
  628. dest.crease_weight[crease_id[1]] = max(0.25f*(3.0f*crease_weight1 + crease_weight0)-1.0f,0.0f);
  629. const float v_blend = 0.5f*(crease_weight0+crease_weight1);
  630. if (unlikely(v_blend < 1.0f)) {
  631. dest.vtx = lerp(v_sharp,v_smooth,v_blend);
  632. }
  633. }
  634. /* compute new vertex using corner rule */
  635. else {
  636. dest.vtx = vtx;
  637. }
  638. }
  639. void convert(CatmullClark1Ring& dst) const
  640. {
  641. dst.edge_level = edge_level;
  642. dst.vertex_level = vertex_level;
  643. dst.vtx = vtx;
  644. dst.face_valence = face_valence;
  645. dst.edge_valence = 2*face_valence;
  646. dst.border_index = border_face == -1 ? -1 : 2*border_face;
  647. for (size_t i=0; i<face_valence; i++)
  648. dst.crease_weight[i] = faces[i].crease_weight;
  649. dst.vertex_crease_weight = vertex_crease_weight;
  650. for (size_t i=0; i<edge_valence; i++) dst.ring[i] = ring[i];
  651. dst.eval_start_index = eval_start_face_index;
  652. dst.eval_unique_identifier = eval_unique_identifier;
  653. assert( dst.hasValidPositions() );
  654. }
  655. /* gets limit tangent in the direction of egde vtx -> ring[0] */
  656. __forceinline Vertex getLimitTangent() const
  657. {
  658. CatmullClark1Ring cc_vtx;
  659. /* fast path for quad only rings */
  660. if (only_quads)
  661. {
  662. convert(cc_vtx);
  663. return cc_vtx.getLimitTangent();
  664. }
  665. subdivide(cc_vtx);
  666. return 2.0f * cc_vtx.getLimitTangent();
  667. }
  668. /* gets limit tangent in the direction of egde vtx -> ring[edge_valence-2] */
  669. __forceinline Vertex getSecondLimitTangent() const
  670. {
  671. CatmullClark1Ring cc_vtx;
  672. /* fast path for quad only rings */
  673. if (only_quads)
  674. {
  675. convert(cc_vtx);
  676. return cc_vtx.getSecondLimitTangent();
  677. }
  678. subdivide(cc_vtx);
  679. return 2.0f * cc_vtx.getSecondLimitTangent();
  680. }
  681. /* gets limit vertex */
  682. __forceinline Vertex getLimitVertex() const
  683. {
  684. CatmullClark1Ring cc_vtx;
  685. /* fast path for quad only rings */
  686. if (only_quads)
  687. convert(cc_vtx);
  688. else
  689. subdivide(cc_vtx);
  690. return cc_vtx.getLimitVertex();
  691. }
  692. friend __forceinline std::ostream &operator<<(std::ostream &o, const GeneralCatmullClark1RingT &c)
  693. {
  694. o << "vtx " << c.vtx << " size = " << c.edge_valence << ", border_face = " << c.border_face << ", " << " face_valence = " << c.face_valence <<
  695. ", edge_level = " << c.edge_level << ", vertex_level = " << c.vertex_level << ", ring: " << std::endl;
  696. for (size_t v=0, f=0; f<c.face_valence; v+=c.faces[f++].size) {
  697. for (size_t i=v; i<v+c.faces[f].size; i++) {
  698. o << i << " -> " << c.ring[i];
  699. if (i == v) o << " crease = " << c.faces[f].crease_weight;
  700. o << std::endl;
  701. }
  702. }
  703. return o;
  704. }
  705. };
  706. }