Path: blob/master/thirdparty/embree/kernels/subdiv/patch_eval_grid.h
9913 views
// Copyright 2009-2021 Intel Corporation1// SPDX-License-Identifier: Apache-2.023#pragma once45#include "patch.h"6#include "feature_adaptive_eval_grid.h"78namespace embree9{10namespace isa11{12struct PatchEvalGrid13{14typedef Patch3fa Patch;15typedef Patch::Ref Ref;16typedef GeneralCatmullClarkPatch3fa GeneralCatmullClarkPatch;17typedef CatmullClarkPatch3fa CatmullClarkPatch;18typedef BSplinePatch3fa BSplinePatch;19typedef BezierPatch3fa BezierPatch;20typedef GregoryPatch3fa GregoryPatch;21typedef BilinearPatch3fa BilinearPatch;2223private:24const unsigned x0,x1;25const unsigned y0,y1;26const unsigned swidth,sheight;27const float rcp_swidth, rcp_sheight;28float* const Px;29float* const Py;30float* const Pz;31float* const U;32float* const V;33float* const Nx;34float* const Ny;35float* const Nz;36const unsigned dwidth,dheight;37unsigned count;3839public:4041PatchEvalGrid (Ref patch, unsigned subPatch,42const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight,43float* Px, float* Py, float* Pz, float* U, float* V,44float* Nx, float* Ny, float* Nz,45const unsigned dwidth, const unsigned dheight)46: 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)),47Px(Px), Py(Py), Pz(Pz), U(U), V(V), Nx(Nx), Ny(Ny), Nz(Nz), dwidth(dwidth), dheight(dheight), count(0)48{49assert(swidth < (2<<20) && sheight < (2<<20));50const BBox2f srange(Vec2f(0.0f,0.0f),Vec2f(float(swidth-1),float(sheight-1)));51const BBox2f erange(Vec2f(float(x0),float(y0)),Vec2f((float)x1,(float)y1));52bool done MAYBE_UNUSED = eval(patch,subPatch,srange,erange);53assert(done);54assert(count == (x1-x0+1)*(y1-y0+1));55}5657template<typename Patch>58__forceinline void evalLocalGrid(const Patch* patch, const BBox2f& srange, const int lx0, const int lx1, const int ly0, const int ly1)59{60const float scale_x = rcp(srange.upper.x-srange.lower.x);61const float scale_y = rcp(srange.upper.y-srange.lower.y);62count += (lx1-lx0)*(ly1-ly0);6364#if 065for (unsigned iy=ly0; iy<ly1; iy++) {66for (unsigned ix=lx0; ix<lx1; ix++) {67const float lu = select(ix == swidth -1, float(1.0f), (float(ix)-srange.lower.x)*scale_x);68const float lv = select(iy == sheight-1, float(1.0f), (float(iy)-srange.lower.y)*scale_y);69const Vec3fa p = patch->patch.eval(lu,lv);70const float u = float(ix)*rcp_swidth;71const float v = float(iy)*rcp_sheight;72const int ofs = (iy-y0)*dwidth+(ix-x0);73Px[ofs] = p.x;74Py[ofs] = p.y;75Pz[ofs] = p.z;76U[ofs] = u;77V[ofs] = v;78}79}80#else81foreach2(lx0,lx1,ly0,ly1,[&](const vboolx& valid, const vintx& ix, const vintx& iy) {82const vfloatx lu = select(ix == swidth -1, vfloatx(1.0f), (vfloatx(ix)-srange.lower.x)*scale_x);83const vfloatx lv = select(iy == sheight-1, vfloatx(1.0f), (vfloatx(iy)-srange.lower.y)*scale_y);84const Vec3vfx p = patch->patch.eval(lu,lv);85Vec3vfx n = zero;86if (unlikely(Nx != nullptr)) n = normalize_safe(patch->patch.normal(lu,lv));87const vfloatx u = vfloatx(ix)*rcp_swidth;88const vfloatx v = vfloatx(iy)*rcp_sheight;89const vintx ofs = (iy-y0)*dwidth+(ix-x0);90if (likely(all(valid)) && all(iy==iy[0])) {91const unsigned ofs2 = ofs[0];92vfloatx::storeu(Px+ofs2,p.x);93vfloatx::storeu(Py+ofs2,p.y);94vfloatx::storeu(Pz+ofs2,p.z);95vfloatx::storeu(U+ofs2,u);96vfloatx::storeu(V+ofs2,v);97if (unlikely(Nx != nullptr)) {98vfloatx::storeu(Nx+ofs2,n.x);99vfloatx::storeu(Ny+ofs2,n.y);100vfloatx::storeu(Nz+ofs2,n.z);101}102} else {103foreach_unique_index(valid,iy,[&](const vboolx& valid, const int iy0, const int j) {104const unsigned ofs2 = ofs[j]-j;105vfloatx::storeu(valid,Px+ofs2,p.x);106vfloatx::storeu(valid,Py+ofs2,p.y);107vfloatx::storeu(valid,Pz+ofs2,p.z);108vfloatx::storeu(valid,U+ofs2,u);109vfloatx::storeu(valid,V+ofs2,v);110if (unlikely(Nx != nullptr)) {111vfloatx::storeu(valid,Nx+ofs2,n.x);112vfloatx::storeu(valid,Ny+ofs2,n.y);113vfloatx::storeu(valid,Nz+ofs2,n.z);114}115});116}117});118#endif119}120121bool eval(Ref This, const BBox2f& srange, const BBox2f& erange, const unsigned depth)122{123if (erange.empty())124return true;125126const int lx0 = (int) ceilf(erange.lower.x);127const int lx1 = (int) ceilf(erange.upper.x) + (erange.upper.x == x1 && (srange.lower.x < erange.upper.x || erange.upper.x == 0));128const int ly0 = (int) ceilf(erange.lower.y);129const int ly1 = (int) ceilf(erange.upper.y) + (erange.upper.y == y1 && (srange.lower.y < erange.upper.y || erange.upper.y == 0));130if (lx0 >= lx1 || ly0 >= ly1)131return true;132133if (!This)134return false;135136switch (This.type())137{138case Patch::BILINEAR_PATCH: {139evalLocalGrid((Patch::BilinearPatch*)This.object(),srange,lx0,lx1,ly0,ly1);140return true;141}142case Patch::BSPLINE_PATCH: {143evalLocalGrid((Patch::BSplinePatch*)This.object(),srange,lx0,lx1,ly0,ly1);144return true;145}146case Patch::BEZIER_PATCH: {147evalLocalGrid((Patch::BezierPatch*)This.object(),srange,lx0,lx1,ly0,ly1);148return true;149}150case Patch::GREGORY_PATCH: {151evalLocalGrid((Patch::GregoryPatch*)This.object(),srange,lx0,lx1,ly0,ly1);152return true;153}154case Patch::SUBDIVIDED_QUAD_PATCH:155{156const Vec2f c = srange.center();157const BBox2f srange0(srange.lower,c);158const BBox2f srange1(Vec2f(c.x,srange.lower.y),Vec2f(srange.upper.x,c.y));159const BBox2f srange2(c,srange.upper);160const BBox2f srange3(Vec2f(srange.lower.x,c.y),Vec2f(c.x,srange.upper.y));161162Patch::SubdividedQuadPatch* patch = (Patch::SubdividedQuadPatch*)This.object();163eval(patch->child[0],srange0,intersect(srange0,erange),depth+1);164eval(patch->child[1],srange1,intersect(srange1,erange),depth+1);165eval(patch->child[2],srange2,intersect(srange2,erange),depth+1);166eval(patch->child[3],srange3,intersect(srange3,erange),depth+1);167return true;168}169case Patch::EVAL_PATCH: {170CatmullClarkPatch patch; patch.deserialize(This.object());171FeatureAdaptiveEvalGrid(patch,srange,erange,depth,x0,x1,y0,y1,swidth,sheight,Px,Py,Pz,U,V,Nx,Ny,Nz,dwidth,dheight);172count += (lx1-lx0)*(ly1-ly0);173return true;174}175default:176assert(false);177return false;178}179}180181bool eval(Ref This, unsigned subPatch, const BBox2f& srange, const BBox2f& erange)182{183if (!This)184return false;185186switch (This.type())187{188case Patch::SUBDIVIDED_GENERAL_PATCH: {189Patch::SubdividedGeneralPatch* patch = (Patch::SubdividedGeneralPatch*)This.object();190assert(subPatch < patch->N);191return eval(patch->child[subPatch],srange,erange,1);192}193default:194assert(subPatch == 0);195return eval(This,srange,erange,0);196}197}198};199200__forceinline unsigned patch_eval_subdivision_count (const HalfEdge* h)201{202const unsigned N = h->numEdges();203if (N == 4) return 1;204else return N;205}206207template<typename Tessellator>208inline void patch_eval_subdivision (const HalfEdge* h, Tessellator tessellator)209{210const unsigned N = h->numEdges();211int neighborSubdiv[GeneralCatmullClarkPatch3fa::SIZE]; // FIXME: use array_t212float levels[GeneralCatmullClarkPatch3fa::SIZE];213for (unsigned i=0; i<N; i++) {214assert(i<GeneralCatmullClarkPatch3fa::SIZE);215neighborSubdiv[i] = h->hasOpposite() ? h->opposite()->numEdges() != 4 : 0;216levels[i] = h->edge_level;217h = h->next();218}219if (N == 4)220{221const Vec2f uv[4] = { Vec2f(0.0f,0.0f), Vec2f(1.0f,0.0f), Vec2f(1.0f,1.0f), Vec2f(0.0f,1.0f) };222tessellator(uv,neighborSubdiv,levels,0);223}224else225{226for (unsigned i=0; i<N; i++)227{228assert(i<MAX_PATCH_VALENCE);229static_assert(MAX_PATCH_VALENCE <= 16, "MAX_PATCH_VALENCE > 16");230const int h = (i >> 2) & 3, l = i & 3;231const Vec2f subPatchID((float)l,(float)h);232const Vec2f uv[4] = { 2.0f*subPatchID + (0.5f+Vec2f(0.0f,0.0f)),2332.0f*subPatchID + (0.5f+Vec2f(1.0f,0.0f)),2342.0f*subPatchID + (0.5f+Vec2f(1.0f,1.0f)),2352.0f*subPatchID + (0.5f+Vec2f(0.0f,1.0f)) };236const int neighborSubdiv1[4] = { 0,0,0,0 };237const 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] };238tessellator(uv,neighborSubdiv1,levels1,i);239}240}241}242}243}244245246247