// Copyright 2009-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once #include "bezier_curve.h" namespace embree { namespace isa { template struct TensorLinearQuadraticBezierSurface { QuadraticBezierCurve L; QuadraticBezierCurve R; __forceinline TensorLinearQuadraticBezierSurface() {} __forceinline TensorLinearQuadraticBezierSurface(const TensorLinearQuadraticBezierSurface& curve) : L(curve.L), R(curve.R) {} __forceinline TensorLinearQuadraticBezierSurface& operator= (const TensorLinearQuadraticBezierSurface& other) { L = other.L; R = other.R; return *this; } __forceinline TensorLinearQuadraticBezierSurface(const QuadraticBezierCurve& L, const QuadraticBezierCurve& R) : L(L), R(R) {} __forceinline BBox bounds() const { return merge(L.bounds(),R.bounds()); } }; #if !defined(__SYCL_DEVICE_ONLY__) template<> struct TensorLinearQuadraticBezierSurface { QuadraticBezierCurve LR; __forceinline TensorLinearQuadraticBezierSurface() {} __forceinline TensorLinearQuadraticBezierSurface(const TensorLinearQuadraticBezierSurface& curve) : LR(curve.LR) {} __forceinline TensorLinearQuadraticBezierSurface& operator= (const TensorLinearQuadraticBezierSurface& other) { LR = other.LR; return *this; } __forceinline TensorLinearQuadraticBezierSurface(const QuadraticBezierCurve& LR) : LR(LR) {} __forceinline BBox bounds() const { const BBox b = LR.bounds(); const BBox bl(Vec2fa(b.lower),Vec2fa(b.upper)); const BBox br(Vec2fa(shuffle<2,3,2,3>(b.lower)),Vec2fa(shuffle<2,3,2,3>(b.upper))); return merge(bl,br); } }; #endif template struct TensorLinearCubicBezierSurface { CubicBezierCurve L; CubicBezierCurve R; __forceinline TensorLinearCubicBezierSurface() {} __forceinline TensorLinearCubicBezierSurface(const TensorLinearCubicBezierSurface& curve) : L(curve.L), R(curve.R) {} __forceinline TensorLinearCubicBezierSurface& operator= (const TensorLinearCubicBezierSurface& other) { L = other.L; R = other.R; return *this; } __forceinline TensorLinearCubicBezierSurface(const CubicBezierCurve& L, const CubicBezierCurve& R) : L(L), R(R) {} template class SourceCurve> __forceinline static TensorLinearCubicBezierSurface fromCenterAndNormalCurve(const SourceCurve& center, const SourceCurve& normal) { SourceCurve vcurve = center; SourceCurve ncurve = normal; /* here we construct a patch which follows the curve l(t) = * p(t) +/- r(t)*normalize(cross(n(t),dp(t))) */ const Vec3ff p0 = vcurve.eval(0.0f); const Vec3ff dp0 = vcurve.eval_du(0.0f); //const Vec3ff ddp0 = vcurve.eval_dudu(0.0f); // ddp0 is assumed to be 0 const Vec3fa n0 = ncurve.eval(0.0f); const Vec3fa dn0 = ncurve.eval_du(0.0f); const Vec3ff p1 = vcurve.eval(1.0f); const Vec3ff dp1 = vcurve.eval_du(1.0f); //const Vec3ff ddp1 = vcurve.eval_dudu(1.0f); // ddp1 is assumed to be 0 const Vec3fa n1 = ncurve.eval(1.0f); const Vec3fa dn1 = ncurve.eval_du(1.0f); const Vec3fa bt0 = cross(n0,dp0); const Vec3fa dbt0 = cross(dn0,dp0);// + cross(n0,ddp0); const Vec3fa bt1 = cross(n1,dp1); const Vec3fa dbt1 = cross(dn1,dp1);// + cross(n1,ddp1); const Vec3fa k0 = normalize(bt0); const Vec3fa dk0 = dnormalize(bt0,dbt0); const Vec3fa k1 = normalize(bt1); const Vec3fa dk1 = dnormalize(bt1,dbt1); const Vec3fa l0 = p0 - p0.w*k0; const Vec3fa dl0 = dp0 - (dp0.w*k0 + p0.w*dk0); const Vec3fa r0 = p0 + p0.w*k0; const Vec3fa dr0 = dp0 + (dp0.w*k0 + p0.w*dk0); const Vec3fa l1 = p1 - p1.w*k1; const Vec3fa dl1 = dp1 - (dp1.w*k1 + p1.w*dk1); const Vec3fa r1 = p1 + p1.w*k1; const Vec3fa dr1 = dp1 + (dp1.w*k1 + p1.w*dk1); const float scale = 1.0f/3.0f; CubicBezierCurve L(l0,l0+scale*dl0,l1-scale*dl1,l1); CubicBezierCurve R(r0,r0+scale*dr0,r1-scale*dr1,r1); return TensorLinearCubicBezierSurface(L,R); } __forceinline BBox bounds() const { return merge(L.bounds(),R.bounds()); } __forceinline BBox3fa accurateBounds() const { return merge(L.accurateBounds(),R.accurateBounds()); } __forceinline CubicBezierCurve reduce_v() const { return merge(CubicBezierCurve>(L),CubicBezierCurve>(R)); } __forceinline LinearBezierCurve reduce_u() const { return LinearBezierCurve(L.bounds(),R.bounds()); } __forceinline TensorLinearCubicBezierSurface xfm(const V& dx) const { return TensorLinearCubicBezierSurface(L.xfm(dx),R.xfm(dx)); } template __forceinline TensorLinearCubicBezierSurface> vxfm(const V& dx) const { return TensorLinearCubicBezierSurface>(L.template vxfm(dx),R.template vxfm(dx)); } __forceinline TensorLinearCubicBezierSurface xfm(const V& dx, const V& p) const { return TensorLinearCubicBezierSurface(L.xfm(dx,p),R.xfm(dx,p)); } __forceinline TensorLinearCubicBezierSurface xfm(const LinearSpace3fa& space) const { return TensorLinearCubicBezierSurface(L.xfm(space),R.xfm(space)); } __forceinline TensorLinearCubicBezierSurface xfm(const LinearSpace3fa& space, const Vec3fa& p) const { return TensorLinearCubicBezierSurface(L.xfm(space,p),R.xfm(space,p)); } __forceinline TensorLinearCubicBezierSurface xfm(const LinearSpace3fa& space, const Vec3fa& p, const float s) const { return TensorLinearCubicBezierSurface(L.xfm(space,p,s),R.xfm(space,p,s)); } __forceinline TensorLinearCubicBezierSurface clip_u(const Interval1f& u) const { return TensorLinearCubicBezierSurface(L.clip(u),R.clip(u)); } __forceinline TensorLinearCubicBezierSurface clip_v(const Interval1f& v) const { return TensorLinearCubicBezierSurface(clerp(L,R,V(v.lower)),clerp(L,R,V(v.upper))); } __forceinline TensorLinearCubicBezierSurface clip(const Interval1f& u, const Interval1f& v) const { return clip_v(v).clip_u(u); } __forceinline void split_u(TensorLinearCubicBezierSurface& left, TensorLinearCubicBezierSurface& right, const float u = 0.5f) const { CubicBezierCurve L0,L1; L.split(L0,L1,u); CubicBezierCurve R0,R1; R.split(R0,R1,u); new (&left ) TensorLinearCubicBezierSurface(L0,R0); new (&right) TensorLinearCubicBezierSurface(L1,R1); } __forceinline TensorLinearCubicBezierSurface vsplit_u(vboolx& valid, const BBox1f& u) const { valid = true; clear(valid,VSIZEX-1); return TensorLinearCubicBezierSurface(L.split(u),R.split(u)); } template __forceinline TensorLinearCubicBezierSurface> vsplit_u(vbool& valid, const BBox1f& u, int& i, int N) const { valid = true; clear(valid,W-1); auto r = TensorLinearCubicBezierSurface>(L.template split(u,i,N),R.template split(u,i,N)); i += W-1; return r; } __forceinline V eval(const float u, const float v) const { return clerp(L,R,V(v)).eval(u); } __forceinline V eval_du(const float u, const float v) const { return clerp(L,R,V(v)).eval_dt(u); } __forceinline V eval_dv(const float u, const float v) const { return (R-L).eval(u); } __forceinline void eval(const float u, const float v, V& p, V& dpdu, V& dpdv) const { V p0, dp0du; L.eval(u,p0,dp0du); V p1, dp1du; R.eval(u,p1,dp1du); p = lerp(p0,p1,v); dpdu = lerp(dp0du,dp1du,v); dpdv = p1-p0; } __forceinline TensorLinearQuadraticBezierSurface derivative_u() const { return TensorLinearQuadraticBezierSurface(L.derivative(),R.derivative()); } __forceinline CubicBezierCurve derivative_v() const { return R-L; } __forceinline V axis_u() const { return (L.end()-L.begin())+(R.end()-R.begin()); } __forceinline V axis_v() const { return (R.begin()-L.begin())+(R.end()-L.end()); } friend embree_ostream operator<<(embree_ostream cout, const TensorLinearCubicBezierSurface& a) { return cout << "TensorLinearCubicBezierSurface" << embree_endl << "{" << embree_endl << " L = " << a.L << ", " << embree_endl << " R = " << a.R << embree_endl << "}"; } friend __forceinline TensorLinearCubicBezierSurface clerp(const TensorLinearCubicBezierSurface& a, const TensorLinearCubicBezierSurface& b, const float t) { return TensorLinearCubicBezierSurface(clerp(a.L,b.L,V(t)), clerp(a.R,b.R,V(t))); } }; #if !defined(__SYCL_DEVICE_ONLY__) template<> struct TensorLinearCubicBezierSurface { CubicBezierCurve LR; __forceinline TensorLinearCubicBezierSurface() {} __forceinline TensorLinearCubicBezierSurface(const TensorLinearCubicBezierSurface& curve) : LR(curve.LR) {} __forceinline TensorLinearCubicBezierSurface& operator= (const TensorLinearCubicBezierSurface& other) { LR = other.LR; return *this; } __forceinline TensorLinearCubicBezierSurface(const CubicBezierCurve& LR) : LR(LR) {} __forceinline TensorLinearCubicBezierSurface(const CubicBezierCurve& L, const CubicBezierCurve& R) : LR(shuffle<0,1,0,1>(vfloat4(L.v0),vfloat4(R.v0)),shuffle<0,1,0,1>(vfloat4(L.v1),vfloat4(R.v1)),shuffle<0,1,0,1>(vfloat4(L.v2),vfloat4(R.v2)),shuffle<0,1,0,1>(vfloat4(L.v3),vfloat4(R.v3))) {} __forceinline CubicBezierCurve getL() const { return CubicBezierCurve(Vec2fa(LR.v0),Vec2fa(LR.v1),Vec2fa(LR.v2),Vec2fa(LR.v3)); } __forceinline CubicBezierCurve getR() const { return CubicBezierCurve(Vec2fa(shuffle<2,3,2,3>(LR.v0)),Vec2fa(shuffle<2,3,2,3>(LR.v1)),Vec2fa(shuffle<2,3,2,3>(LR.v2)),Vec2fa(shuffle<2,3,2,3>(LR.v3))); } __forceinline BBox bounds() const { const BBox b = LR.bounds(); const BBox bl(Vec2fa(b.lower),Vec2fa(b.upper)); const BBox br(Vec2fa(shuffle<2,3,2,3>(b.lower)),Vec2fa(shuffle<2,3,2,3>(b.upper))); return merge(bl,br); } __forceinline BBox1f bounds(const Vec2fa& axis) const { const CubicBezierCurve LRx = LR; const CubicBezierCurve LRy(shuffle<1,0,3,2>(LR.v0),shuffle<1,0,3,2>(LR.v1),shuffle<1,0,3,2>(LR.v2),shuffle<1,0,3,2>(LR.v3)); const CubicBezierCurve LRa = cmadd(shuffle<0>(vfloat4(axis)),LRx,shuffle<1>(vfloat4(axis))*LRy); const BBox Lb = LRa.bounds(); const BBox Rb(shuffle<3>(Lb.lower),shuffle<3>(Lb.upper)); const BBox b = merge(Lb,Rb); return BBox1f(b.lower[0],b.upper[0]); } __forceinline TensorLinearCubicBezierSurface xfm(const Vec2fa& dx) const { const CubicBezierCurve LRx = LR; const CubicBezierCurve LRy(shuffle<1,0,3,2>(LR.v0),shuffle<1,0,3,2>(LR.v1),shuffle<1,0,3,2>(LR.v2),shuffle<1,0,3,2>(LR.v3)); const CubicBezierCurve LRa = cmadd(shuffle<0>(vfloat4(dx)),LRx,shuffle<1>(vfloat4(dx))*LRy); return TensorLinearCubicBezierSurface(CubicBezierCurve(LRa.v0[0],LRa.v1[0],LRa.v2[0],LRa.v3[0]), CubicBezierCurve(LRa.v0[2],LRa.v1[2],LRa.v2[2],LRa.v3[2])); } __forceinline TensorLinearCubicBezierSurface xfm(const Vec2fa& dx, const Vec2fa& p) const { const vfloat4 pxyxy = shuffle<0,1,0,1>(vfloat4(p)); const CubicBezierCurve LRx = LR-pxyxy; const CubicBezierCurve LRy(shuffle<1,0,3,2>(LR.v0),shuffle<1,0,3,2>(LR.v1),shuffle<1,0,3,2>(LR.v2),shuffle<1,0,3,2>(LR.v3)); const CubicBezierCurve LRa = cmadd(shuffle<0>(vfloat4(dx)),LRx,shuffle<1>(vfloat4(dx))*LRy); return TensorLinearCubicBezierSurface(CubicBezierCurve(LRa.v0[0],LRa.v1[0],LRa.v2[0],LRa.v3[0]), CubicBezierCurve(LRa.v0[2],LRa.v1[2],LRa.v2[2],LRa.v3[2])); } __forceinline TensorLinearCubicBezierSurface clip_u(const Interval1f& u) const { return TensorLinearCubicBezierSurface(LR.clip(u)); } __forceinline TensorLinearCubicBezierSurface clip_v(const Interval1f& v) const { const CubicBezierCurve LL(shuffle<0,1,0,1>(LR.v0),shuffle<0,1,0,1>(LR.v1),shuffle<0,1,0,1>(LR.v2),shuffle<0,1,0,1>(LR.v3)); const CubicBezierCurve RR(shuffle<2,3,2,3>(LR.v0),shuffle<2,3,2,3>(LR.v1),shuffle<2,3,2,3>(LR.v2),shuffle<2,3,2,3>(LR.v3)); return TensorLinearCubicBezierSurface(clerp(LL,RR,vfloat4(v.lower,v.lower,v.upper,v.upper))); } __forceinline TensorLinearCubicBezierSurface clip(const Interval1f& u, const Interval1f& v) const { return clip_v(v).clip_u(u); } __forceinline void split_u(TensorLinearCubicBezierSurface& left, TensorLinearCubicBezierSurface& right, const float u = 0.5f) const { CubicBezierCurve LR0,LR1; LR.split(LR0,LR1,u); new (&left ) TensorLinearCubicBezierSurface(LR0); new (&right) TensorLinearCubicBezierSurface(LR1); } __forceinline TensorLinearCubicBezierSurface vsplit_u(vboolx& valid, const BBox1f& u) const { valid = true; clear(valid,VSIZEX-1); return TensorLinearCubicBezierSurface(getL().split(u),getR().split(u)); } template __forceinline TensorLinearCubicBezierSurface> vsplit_u(vbool& valid, const BBox1f& u, int& i, int N) const { valid = true; clear(valid,W-1); auto r = TensorLinearCubicBezierSurface>(getL().split(u,i,N),getR().split(u,i,N)); i += W-1; return r; } __forceinline Vec2fa eval(const float u, const float v) const { const vfloat4 p = LR.eval(u); return Vec2fa(lerp(shuffle<0,1,0,1>(p),shuffle<2,3,2,3>(p),v)); } __forceinline Vec2fa eval_du(const float u, const float v) const { const vfloat4 dpdu = LR.eval_dt(u); return Vec2fa(lerp(shuffle<0,1,0,1>(dpdu),shuffle<2,3,2,3>(dpdu),v)); } __forceinline Vec2fa eval_dv(const float u, const float v) const { const vfloat4 p = LR.eval(u); return Vec2fa(shuffle<2,3,2,3>(p)-shuffle<0,1,0,1>(p)); } __forceinline void eval(const float u, const float v, Vec2fa& p, Vec2fa& dpdu, Vec2fa& dpdv) const { vfloat4 p0, dp0du; LR.eval(u,p0,dp0du); p = Vec2fa(lerp(shuffle<0,1,0,1>(p0),shuffle<2,3,2,3>(p0),v)); dpdu = Vec2fa(lerp(shuffle<0,1,0,1>(dp0du),shuffle<2,3,2,3>(dp0du),v)); dpdv = Vec2fa(shuffle<2,3,2,3>(p0)-shuffle<0,1,0,1>(p0)); } __forceinline TensorLinearQuadraticBezierSurface derivative_u() const { return TensorLinearQuadraticBezierSurface(LR.derivative()); } __forceinline CubicBezierCurve derivative_v() const { return getR()-getL(); } __forceinline Vec2fa axis_u() const { const CubicBezierCurve L = getL(); const CubicBezierCurve R = getR(); return (L.end()-L.begin())+(R.end()-R.begin()); } __forceinline Vec2fa axis_v() const { const CubicBezierCurve L = getL(); const CubicBezierCurve R = getR(); return (R.begin()-L.begin())+(R.end()-L.end()); } friend embree_ostream operator<<(embree_ostream cout, const TensorLinearCubicBezierSurface& a) { return cout << "TensorLinearCubicBezierSurface" << embree_endl << "{" << embree_endl << " L = " << a.getL() << ", " << embree_endl << " R = " << a.getR() << embree_endl << "}"; } }; template<> __forceinline TensorLinearCubicBezierSurface TensorLinearCubicBezierSurface::vsplit_u<1>(bool& valid, const BBox1f& u, int& i, int N) const { auto r = TensorLinearCubicBezierSurface(getL().split1(u,i,N),getR().split1(u,i,N)); valid = true; i += 1; return r; } #else template<> template<> __forceinline TensorLinearCubicBezierSurface TensorLinearCubicBezierSurface::vsplit_u<1>(bool& valid, const BBox1f& u, int& i, int N) const { auto r = TensorLinearCubicBezierSurface(L.split1(u,i,N),R.split1(u,i,N)); valid = true; i += 1; return r; } #endif typedef TensorLinearCubicBezierSurface TensorLinearCubicBezierSurface1f; typedef TensorLinearCubicBezierSurface TensorLinearCubicBezierSurface2fa; typedef TensorLinearCubicBezierSurface TensorLinearCubicBezierSurface3fa; } }