patch_eval_grid.h 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. // Copyright 2009-2021 Intel Corporation
  2. // SPDX-License-Identifier: Apache-2.0
  3. #pragma once
  4. #include "patch.h"
  5. #include "feature_adaptive_eval_grid.h"
  6. namespace embree
  7. {
  8. namespace isa
  9. {
  10. struct PatchEvalGrid
  11. {
  12. typedef Patch3fa Patch;
  13. typedef Patch::Ref Ref;
  14. typedef GeneralCatmullClarkPatch3fa GeneralCatmullClarkPatch;
  15. typedef CatmullClarkPatch3fa CatmullClarkPatch;
  16. typedef BSplinePatch3fa BSplinePatch;
  17. typedef BezierPatch3fa BezierPatch;
  18. typedef GregoryPatch3fa GregoryPatch;
  19. typedef BilinearPatch3fa BilinearPatch;
  20. private:
  21. const unsigned x0,x1;
  22. const unsigned y0,y1;
  23. const unsigned swidth,sheight;
  24. const float rcp_swidth, rcp_sheight;
  25. float* const Px;
  26. float* const Py;
  27. float* const Pz;
  28. float* const U;
  29. float* const V;
  30. float* const Nx;
  31. float* const Ny;
  32. float* const Nz;
  33. const unsigned dwidth,dheight;
  34. unsigned count;
  35. public:
  36. PatchEvalGrid (Ref patch, unsigned subPatch,
  37. const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight,
  38. float* Px, float* Py, float* Pz, float* U, float* V,
  39. float* Nx, float* Ny, float* Nz,
  40. const unsigned dwidth, const unsigned dheight)
  41. : x0(x0), x1(x1), y0(y0), y1(y1), swidth(swidth), sheight(sheight), rcp_swidth(1.0f/(swidth-1.0f)), rcp_sheight(1.0f/(sheight-1.0f)),
  42. Px(Px), Py(Py), Pz(Pz), U(U), V(V), Nx(Nx), Ny(Ny), Nz(Nz), dwidth(dwidth), dheight(dheight), count(0)
  43. {
  44. assert(swidth < (2<<20) && sheight < (2<<20));
  45. const BBox2f srange(Vec2f(0.0f,0.0f),Vec2f(float(swidth-1),float(sheight-1)));
  46. const BBox2f erange(Vec2f(float(x0),float(y0)),Vec2f((float)x1,(float)y1));
  47. bool done MAYBE_UNUSED = eval(patch,subPatch,srange,erange);
  48. assert(done);
  49. assert(count == (x1-x0+1)*(y1-y0+1));
  50. }
  51. template<typename Patch>
  52. __forceinline void evalLocalGrid(const Patch* patch, const BBox2f& srange, const int lx0, const int lx1, const int ly0, const int ly1)
  53. {
  54. const float scale_x = rcp(srange.upper.x-srange.lower.x);
  55. const float scale_y = rcp(srange.upper.y-srange.lower.y);
  56. count += (lx1-lx0)*(ly1-ly0);
  57. #if 0
  58. for (unsigned iy=ly0; iy<ly1; iy++) {
  59. for (unsigned ix=lx0; ix<lx1; ix++) {
  60. const float lu = select(ix == swidth -1, float(1.0f), (float(ix)-srange.lower.x)*scale_x);
  61. const float lv = select(iy == sheight-1, float(1.0f), (float(iy)-srange.lower.y)*scale_y);
  62. const Vec3fa p = patch->patch.eval(lu,lv);
  63. const float u = float(ix)*rcp_swidth;
  64. const float v = float(iy)*rcp_sheight;
  65. const int ofs = (iy-y0)*dwidth+(ix-x0);
  66. Px[ofs] = p.x;
  67. Py[ofs] = p.y;
  68. Pz[ofs] = p.z;
  69. U[ofs] = u;
  70. V[ofs] = v;
  71. }
  72. }
  73. #else
  74. foreach2(lx0,lx1,ly0,ly1,[&](const vboolx& valid, const vintx& ix, const vintx& iy) {
  75. const vfloatx lu = select(ix == swidth -1, vfloatx(1.0f), (vfloatx(ix)-srange.lower.x)*scale_x);
  76. const vfloatx lv = select(iy == sheight-1, vfloatx(1.0f), (vfloatx(iy)-srange.lower.y)*scale_y);
  77. const Vec3vfx p = patch->patch.eval(lu,lv);
  78. Vec3vfx n = zero;
  79. if (unlikely(Nx != nullptr)) n = normalize_safe(patch->patch.normal(lu,lv));
  80. const vfloatx u = vfloatx(ix)*rcp_swidth;
  81. const vfloatx v = vfloatx(iy)*rcp_sheight;
  82. const vintx ofs = (iy-y0)*dwidth+(ix-x0);
  83. if (likely(all(valid)) && all(iy==iy[0])) {
  84. const unsigned ofs2 = ofs[0];
  85. vfloatx::storeu(Px+ofs2,p.x);
  86. vfloatx::storeu(Py+ofs2,p.y);
  87. vfloatx::storeu(Pz+ofs2,p.z);
  88. vfloatx::storeu(U+ofs2,u);
  89. vfloatx::storeu(V+ofs2,v);
  90. if (unlikely(Nx != nullptr)) {
  91. vfloatx::storeu(Nx+ofs2,n.x);
  92. vfloatx::storeu(Ny+ofs2,n.y);
  93. vfloatx::storeu(Nz+ofs2,n.z);
  94. }
  95. } else {
  96. foreach_unique_index(valid,iy,[&](const vboolx& valid, const int iy0, const int j) {
  97. const unsigned ofs2 = ofs[j]-j;
  98. vfloatx::storeu(valid,Px+ofs2,p.x);
  99. vfloatx::storeu(valid,Py+ofs2,p.y);
  100. vfloatx::storeu(valid,Pz+ofs2,p.z);
  101. vfloatx::storeu(valid,U+ofs2,u);
  102. vfloatx::storeu(valid,V+ofs2,v);
  103. if (unlikely(Nx != nullptr)) {
  104. vfloatx::storeu(valid,Nx+ofs2,n.x);
  105. vfloatx::storeu(valid,Ny+ofs2,n.y);
  106. vfloatx::storeu(valid,Nz+ofs2,n.z);
  107. }
  108. });
  109. }
  110. });
  111. #endif
  112. }
  113. bool eval(Ref This, const BBox2f& srange, const BBox2f& erange, const unsigned depth)
  114. {
  115. if (erange.empty())
  116. return true;
  117. const int lx0 = (int) ceilf(erange.lower.x);
  118. const int lx1 = (int) ceilf(erange.upper.x) + (erange.upper.x == x1 && (srange.lower.x < erange.upper.x || erange.upper.x == 0));
  119. const int ly0 = (int) ceilf(erange.lower.y);
  120. const int ly1 = (int) ceilf(erange.upper.y) + (erange.upper.y == y1 && (srange.lower.y < erange.upper.y || erange.upper.y == 0));
  121. if (lx0 >= lx1 || ly0 >= ly1)
  122. return true;
  123. if (!This)
  124. return false;
  125. switch (This.type())
  126. {
  127. case Patch::BILINEAR_PATCH: {
  128. evalLocalGrid((Patch::BilinearPatch*)This.object(),srange,lx0,lx1,ly0,ly1);
  129. return true;
  130. }
  131. case Patch::BSPLINE_PATCH: {
  132. evalLocalGrid((Patch::BSplinePatch*)This.object(),srange,lx0,lx1,ly0,ly1);
  133. return true;
  134. }
  135. case Patch::BEZIER_PATCH: {
  136. evalLocalGrid((Patch::BezierPatch*)This.object(),srange,lx0,lx1,ly0,ly1);
  137. return true;
  138. }
  139. case Patch::GREGORY_PATCH: {
  140. evalLocalGrid((Patch::GregoryPatch*)This.object(),srange,lx0,lx1,ly0,ly1);
  141. return true;
  142. }
  143. case Patch::SUBDIVIDED_QUAD_PATCH:
  144. {
  145. const Vec2f c = srange.center();
  146. const BBox2f srange0(srange.lower,c);
  147. const BBox2f srange1(Vec2f(c.x,srange.lower.y),Vec2f(srange.upper.x,c.y));
  148. const BBox2f srange2(c,srange.upper);
  149. const BBox2f srange3(Vec2f(srange.lower.x,c.y),Vec2f(c.x,srange.upper.y));
  150. Patch::SubdividedQuadPatch* patch = (Patch::SubdividedQuadPatch*)This.object();
  151. eval(patch->child[0],srange0,intersect(srange0,erange),depth+1);
  152. eval(patch->child[1],srange1,intersect(srange1,erange),depth+1);
  153. eval(patch->child[2],srange2,intersect(srange2,erange),depth+1);
  154. eval(patch->child[3],srange3,intersect(srange3,erange),depth+1);
  155. return true;
  156. }
  157. case Patch::EVAL_PATCH: {
  158. CatmullClarkPatch patch; patch.deserialize(This.object());
  159. FeatureAdaptiveEvalGrid(patch,srange,erange,depth,x0,x1,y0,y1,swidth,sheight,Px,Py,Pz,U,V,Nx,Ny,Nz,dwidth,dheight);
  160. count += (lx1-lx0)*(ly1-ly0);
  161. return true;
  162. }
  163. default:
  164. assert(false);
  165. return false;
  166. }
  167. }
  168. bool eval(Ref This, unsigned subPatch, const BBox2f& srange, const BBox2f& erange)
  169. {
  170. if (!This)
  171. return false;
  172. switch (This.type())
  173. {
  174. case Patch::SUBDIVIDED_GENERAL_PATCH: {
  175. Patch::SubdividedGeneralPatch* patch = (Patch::SubdividedGeneralPatch*)This.object();
  176. assert(subPatch < patch->N);
  177. return eval(patch->child[subPatch],srange,erange,1);
  178. }
  179. default:
  180. assert(subPatch == 0);
  181. return eval(This,srange,erange,0);
  182. }
  183. }
  184. };
  185. __forceinline unsigned patch_eval_subdivision_count (const HalfEdge* h)
  186. {
  187. const unsigned N = h->numEdges();
  188. if (N == 4) return 1;
  189. else return N;
  190. }
  191. template<typename Tessellator>
  192. inline void patch_eval_subdivision (const HalfEdge* h, Tessellator tessellator)
  193. {
  194. const unsigned N = h->numEdges();
  195. int neighborSubdiv[GeneralCatmullClarkPatch3fa::SIZE]; // FIXME: use array_t
  196. float levels[GeneralCatmullClarkPatch3fa::SIZE];
  197. for (unsigned i=0; i<N; i++) {
  198. assert(i<GeneralCatmullClarkPatch3fa::SIZE);
  199. neighborSubdiv[i] = h->hasOpposite() ? h->opposite()->numEdges() != 4 : 0;
  200. levels[i] = h->edge_level;
  201. h = h->next();
  202. }
  203. if (N == 4)
  204. {
  205. const Vec2f uv[4] = { Vec2f(0.0f,0.0f), Vec2f(1.0f,0.0f), Vec2f(1.0f,1.0f), Vec2f(0.0f,1.0f) };
  206. tessellator(uv,neighborSubdiv,levels,0);
  207. }
  208. else
  209. {
  210. for (unsigned i=0; i<N; i++)
  211. {
  212. assert(i<MAX_PATCH_VALENCE);
  213. static_assert(MAX_PATCH_VALENCE <= 16, "MAX_PATCH_VALENCE > 16");
  214. const int h = (i >> 2) & 3, l = i & 3;
  215. const Vec2f subPatchID((float)l,(float)h);
  216. const Vec2f uv[4] = { 2.0f*subPatchID + (0.5f+Vec2f(0.0f,0.0f)),
  217. 2.0f*subPatchID + (0.5f+Vec2f(1.0f,0.0f)),
  218. 2.0f*subPatchID + (0.5f+Vec2f(1.0f,1.0f)),
  219. 2.0f*subPatchID + (0.5f+Vec2f(0.0f,1.0f)) };
  220. const int neighborSubdiv1[4] = { 0,0,0,0 };
  221. const float levels1[4] = { 0.5f*levels[(i+0)%N], 0.5f*levels[(i+0)%N], 0.5f*levels[(i+N-1)%N], 0.5f*levels[(i+N-1)%N] };
  222. tessellator(uv,neighborSubdiv1,levels1,i);
  223. }
  224. }
  225. }
  226. }
  227. }