Path: blob/master/thirdparty/embree/kernels/subdiv/bspline_curve.h
9913 views
// Copyright 2009-2021 Intel Corporation1// SPDX-License-Identifier: Apache-2.023#pragma once45#include "../common/default.h"6#include "bezier_curve.h"78namespace embree9{10class BSplineBasis11{12public:1314template<typename T>15static __forceinline Vec4<T> eval(const T& u)16{17const T t = u;18const T s = T(1.0f) - u;19const T n0 = s*s*s;20const T n1 = (4.0f*(s*s*s)+(t*t*t)) + (12.0f*((s*t)*s) + 6.0f*((t*s)*t));21const T n2 = (4.0f*(t*t*t)+(s*s*s)) + (12.0f*((t*s)*t) + 6.0f*((s*t)*s));22const T n3 = t*t*t;23return T(1.0f/6.0f)*Vec4<T>(n0,n1,n2,n3);24}2526template<typename T>27static __forceinline Vec4<T> derivative(const T& u)28{29const T t = u;30const T s = 1.0f - u;31const T n0 = -s*s;32const T n1 = -t*t - 4.0f*(t*s);33const T n2 = s*s + 4.0f*(s*t);34const T n3 = t*t;35return T(0.5f)*Vec4<T>(n0,n1,n2,n3);36}3738template<typename T>39static __forceinline Vec4<T> derivative2(const T& u)40{41const T t = u;42const T s = 1.0f - u;43const T n0 = s;44const T n1 = t - 2.0f*s;45const T n2 = s - 2.0f*t;46const T n3 = t;47return Vec4<T>(n0,n1,n2,n3);48}49};5051struct PrecomputedBSplineBasis52{53enum { N = 16 };54public:55PrecomputedBSplineBasis() {}56PrecomputedBSplineBasis(int shift);5758/* basis for bspline evaluation */59public:60float c0[N+1][N+1];61float c1[N+1][N+1];62float c2[N+1][N+1];63float c3[N+1][N+1];6465/* basis for bspline derivative evaluation */66public:67float d0[N+1][N+1];68float d1[N+1][N+1];69float d2[N+1][N+1];70float d3[N+1][N+1];71};72extern PrecomputedBSplineBasis bspline_basis0;73extern PrecomputedBSplineBasis bspline_basis1;7475template<typename Vertex>76struct BSplineCurveT77{78Vertex v0,v1,v2,v3;7980__forceinline BSplineCurveT() {}8182__forceinline BSplineCurveT(const Vertex& v0, const Vertex& v1, const Vertex& v2, const Vertex& v3)83: v0(v0), v1(v1), v2(v2), v3(v3) {}8485__forceinline Vertex begin() const {86return madd(1.0f/6.0f,v0,madd(2.0f/3.0f,v1,1.0f/6.0f*v2));87}8889__forceinline Vertex end() const {90return madd(1.0f/6.0f,v1,madd(2.0f/3.0f,v2,1.0f/6.0f*v3));91}9293__forceinline Vertex center() const {94return 0.25f*(v0+v1+v2+v3);95}9697__forceinline BBox<Vertex> bounds() const {98return merge(BBox<Vertex>(v0),BBox<Vertex>(v1),BBox<Vertex>(v2),BBox<Vertex>(v3));99}100101__forceinline friend BSplineCurveT operator -( const BSplineCurveT& a, const Vertex& b ) {102return BSplineCurveT(a.v0-b,a.v1-b,a.v2-b,a.v3-b);103}104105__forceinline BSplineCurveT<Vec3ff> xfm_pr(const LinearSpace3fa& space, const Vec3fa& p) const106{107const Vec3ff q0(xfmVector(space,(Vec3fa)v0-p), v0.w);108const Vec3ff q1(xfmVector(space,(Vec3fa)v1-p), v1.w);109const Vec3ff q2(xfmVector(space,(Vec3fa)v2-p), v2.w);110const Vec3ff q3(xfmVector(space,(Vec3fa)v3-p), v3.w);111return BSplineCurveT<Vec3ff>(q0,q1,q2,q3);112}113114__forceinline Vertex eval(const float t) const115{116const Vec4<float> b = BSplineBasis::eval(t);117return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));118}119120__forceinline Vertex eval_du(const float t) const121{122const Vec4<float> b = BSplineBasis::derivative(t);123return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));124}125126__forceinline Vertex eval_dudu(const float t) const127{128const Vec4<float> b = BSplineBasis::derivative2(t);129return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));130}131132__forceinline void eval(const float t, Vertex& p, Vertex& dp) const133{134p = eval(t);135dp = eval_du(t);136}137138__forceinline void eval(const float t, Vertex& p, Vertex& dp, Vertex& ddp) const139{140p = eval(t);141dp = eval_du(t);142ddp = eval_dudu(t);143}144145template<int M>146__forceinline Vec4vf<M> veval(const vfloat<M>& t) const147{148const Vec4vf<M> b = BSplineBasis::eval(t);149return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));150}151152template<int M>153__forceinline Vec4vf<M> veval_du(const vfloat<M>& t) const154{155const Vec4vf<M> b = BSplineBasis::derivative(t);156return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));157}158159template<int M>160__forceinline Vec4vf<M> veval_dudu(const vfloat<M>& t) const161{162const Vec4vf<M> b = BSplineBasis::derivative2(t);163return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));164}165166template<int M>167__forceinline void veval(const vfloat<M>& t, Vec4vf<M>& p, Vec4vf<M>& dp) const168{169p = veval<M>(t);170dp = veval_du<M>(t);171}172173template<int M>174__forceinline Vec4vf<M> eval0(const int ofs, const int size) const175{176assert(size <= PrecomputedBSplineBasis::N);177assert(ofs <= size);178return madd(vfloat<M>::loadu(&bspline_basis0.c0[size][ofs]), Vec4vf<M>(v0),179madd(vfloat<M>::loadu(&bspline_basis0.c1[size][ofs]), Vec4vf<M>(v1),180madd(vfloat<M>::loadu(&bspline_basis0.c2[size][ofs]), Vec4vf<M>(v2),181vfloat<M>::loadu(&bspline_basis0.c3[size][ofs]) * Vec4vf<M>(v3))));182}183184template<int M>185__forceinline Vec4vf<M> eval1(const int ofs, const int size) const186{187assert(size <= PrecomputedBSplineBasis::N);188assert(ofs <= size);189return madd(vfloat<M>::loadu(&bspline_basis1.c0[size][ofs]), Vec4vf<M>(v0),190madd(vfloat<M>::loadu(&bspline_basis1.c1[size][ofs]), Vec4vf<M>(v1),191madd(vfloat<M>::loadu(&bspline_basis1.c2[size][ofs]), Vec4vf<M>(v2),192vfloat<M>::loadu(&bspline_basis1.c3[size][ofs]) * Vec4vf<M>(v3))));193}194195template<int M>196__forceinline Vec4vf<M> derivative0(const int ofs, const int size) const197{198assert(size <= PrecomputedBSplineBasis::N);199assert(ofs <= size);200return madd(vfloat<M>::loadu(&bspline_basis0.d0[size][ofs]), Vec4vf<M>(v0),201madd(vfloat<M>::loadu(&bspline_basis0.d1[size][ofs]), Vec4vf<M>(v1),202madd(vfloat<M>::loadu(&bspline_basis0.d2[size][ofs]), Vec4vf<M>(v2),203vfloat<M>::loadu(&bspline_basis0.d3[size][ofs]) * Vec4vf<M>(v3))));204}205206template<int M>207__forceinline Vec4vf<M> derivative1(const int ofs, const int size) const208{209assert(size <= PrecomputedBSplineBasis::N);210assert(ofs <= size);211return madd(vfloat<M>::loadu(&bspline_basis1.d0[size][ofs]), Vec4vf<M>(v0),212madd(vfloat<M>::loadu(&bspline_basis1.d1[size][ofs]), Vec4vf<M>(v1),213madd(vfloat<M>::loadu(&bspline_basis1.d2[size][ofs]), Vec4vf<M>(v2),214vfloat<M>::loadu(&bspline_basis1.d3[size][ofs]) * Vec4vf<M>(v3))));215}216217/* calculates bounds of bspline curve geometry */218__forceinline BBox3fa accurateRoundBounds() const219{220const int N = 7;221const float scale = 1.0f/(3.0f*(N-1));222Vec4vfx pl(pos_inf), pu(neg_inf);223for (int i=0; i<=N; i+=VSIZEX)224{225vintx vi = vintx(i)+vintx(step);226vboolx valid = vi <= vintx(N);227const Vec4vfx p = eval0<VSIZEX>(i,N);228const Vec4vfx dp = derivative0<VSIZEX>(i,N);229const Vec4vfx pm = p-Vec4vfx(scale)*select(vi!=vintx(0),dp,Vec4vfx(zero));230const Vec4vfx pp = p+Vec4vfx(scale)*select(vi!=vintx(N),dp,Vec4vfx(zero));231pl = select(valid,min(pl,p,pm,pp),pl); // FIXME: use masked min232pu = select(valid,max(pu,p,pm,pp),pu); // FIXME: use masked min233}234const Vec3fa lower(reduce_min(pl.x),reduce_min(pl.y),reduce_min(pl.z));235const Vec3fa upper(reduce_max(pu.x),reduce_max(pu.y),reduce_max(pu.z));236const float r_min = reduce_min(pl.w);237const float r_max = reduce_max(pu.w);238const Vec3fa upper_r = Vec3fa(max(abs(r_min),abs(r_max)));239return enlarge(BBox3fa(lower,upper),upper_r);240}241242/* calculates bounds when tessellated into N line segments */243__forceinline BBox3fa accurateFlatBounds(int N) const244{245if (likely(N == 4))246{247const Vec4vf4 pi = eval0<4>(0,4);248const Vec3fa lower(reduce_min(pi.x),reduce_min(pi.y),reduce_min(pi.z));249const Vec3fa upper(reduce_max(pi.x),reduce_max(pi.y),reduce_max(pi.z));250const Vec3fa upper_r = Vec3fa(reduce_max(abs(pi.w)));251const Vec3ff pe = end();252return enlarge(BBox3fa(min(lower,pe),max(upper,pe)),max(upper_r,Vec3fa(abs(pe.w))));253}254else255{256Vec3vfx pl(pos_inf), pu(neg_inf); vfloatx ru(0.0f);257for (int i=0; i<=N; i+=VSIZEX)258{259vboolx valid = vintx(i)+vintx(step) <= vintx(N);260const Vec4vfx pi = eval0<VSIZEX>(i,N);261262pl.x = select(valid,min(pl.x,pi.x),pl.x); // FIXME: use masked min263pl.y = select(valid,min(pl.y,pi.y),pl.y);264pl.z = select(valid,min(pl.z,pi.z),pl.z);265266pu.x = select(valid,max(pu.x,pi.x),pu.x); // FIXME: use masked min267pu.y = select(valid,max(pu.y,pi.y),pu.y);268pu.z = select(valid,max(pu.z,pi.z),pu.z);269270ru = select(valid,max(ru,abs(pi.w)),ru);271}272const Vec3fa lower(reduce_min(pl.x),reduce_min(pl.y),reduce_min(pl.z));273const Vec3fa upper(reduce_max(pu.x),reduce_max(pu.y),reduce_max(pu.z));274const Vec3fa upper_r(reduce_max(ru));275return enlarge(BBox3fa(lower,upper),upper_r);276}277}278279friend __forceinline embree_ostream operator<<(embree_ostream cout, const BSplineCurveT& curve) {280return cout << "BSplineCurve { v0 = " << curve.v0 << ", v1 = " << curve.v1 << ", v2 = " << curve.v2 << ", v3 = " << curve.v3 << " }";281}282};283284template<typename Vertex>285__forceinline void convert(const BezierCurveT<Vertex>& icurve, BezierCurveT<Vertex>& ocurve) {286ocurve = icurve;287}288289template<typename Vertex>290__forceinline void convert(const BSplineCurveT<Vertex>& icurve, BSplineCurveT<Vertex>& ocurve) {291ocurve = icurve;292}293294template<typename Vertex>295__forceinline void convert(const BezierCurveT<Vertex>& icurve, BSplineCurveT<Vertex>& ocurve)296{297const Vertex v0 = madd(6.0f,icurve.v0,madd(-7.0f,icurve.v1,2.0f*icurve.v2));298const Vertex v1 = msub(2.0f,icurve.v1,icurve.v2);299const Vertex v2 = msub(2.0f,icurve.v2,icurve.v1);300const Vertex v3 = madd(2.0f,icurve.v1,madd(-7.0f,icurve.v2,6.0f*icurve.v3));301ocurve = BSplineCurveT<Vertex>(v0,v1,v2,v3);302}303304template<typename Vertex>305__forceinline void convert(const BSplineCurveT<Vertex>& icurve, BezierCurveT<Vertex>& ocurve)306{307const Vertex v0 = madd(1.0f/6.0f,icurve.v0,madd(2.0f/3.0f,icurve.v1,1.0f/6.0f*icurve.v2));308const Vertex v1 = madd(2.0f/3.0f,icurve.v1,1.0f/3.0f*icurve.v2);309const Vertex v2 = madd(1.0f/3.0f,icurve.v1,2.0f/3.0f*icurve.v2);310const Vertex v3 = madd(1.0f/6.0f,icurve.v1,madd(2.0f/3.0f,icurve.v2,1.0f/6.0f*icurve.v3));311ocurve = BezierCurveT<Vertex>(v0,v1,v2,v3);312}313314template<typename CurveGeometry>315__forceinline BSplineCurveT<Vec3ff> enlargeRadiusToMinWidth(const RayQueryContext* context, const CurveGeometry* geom, const Vec3fa& ray_org, const BSplineCurveT<Vec3ff>& curve)316{317return BSplineCurveT<Vec3ff>(enlargeRadiusToMinWidth(context,geom,ray_org,curve.v0),318enlargeRadiusToMinWidth(context,geom,ray_org,curve.v1),319enlargeRadiusToMinWidth(context,geom,ray_org,curve.v2),320enlargeRadiusToMinWidth(context,geom,ray_org,curve.v3));321}322323typedef BSplineCurveT<Vec3fa> BSplineCurve3fa;324}325326327328