catmullclark_ring.h 29 KB

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