| 1 | // Copyright 2009-2021 Intel Corporation |
| 2 | // SPDX-License-Identifier: Apache-2.0 |
| 3 | |
| 4 | #pragma once |
| 5 | |
| 6 | #include "catmullclark_patch.h" |
| 7 | #include "bezier_curve.h" |
| 8 | |
| 9 | namespace embree |
| 10 | { |
| 11 | template<typename Vertex, typename Vertex_t = Vertex> |
| 12 | class __aligned(64) BilinearPatchT |
| 13 | { |
| 14 | typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClarkRing; |
| 15 | typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch; |
| 16 | |
| 17 | public: |
| 18 | Vertex v[4]; |
| 19 | |
| 20 | public: |
| 21 | |
| 22 | __forceinline BilinearPatchT () {} |
| 23 | |
| 24 | __forceinline BilinearPatchT (const HalfEdge* edge, const BufferView<Vertex>& vertices) { |
| 25 | init(edge,vertices.getPtr(),vertices.getStride()); |
| 26 | } |
| 27 | |
| 28 | __forceinline BilinearPatchT (const HalfEdge* edge, const char* vertices, size_t stride) { |
| 29 | init(edge,vertices,stride); |
| 30 | } |
| 31 | |
| 32 | __forceinline void init (const HalfEdge* edge, const char* vertices, size_t stride) |
| 33 | { |
| 34 | v[0] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next(); |
| 35 | v[1] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next(); |
| 36 | v[2] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next(); |
| 37 | v[3] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next(); |
| 38 | } |
| 39 | |
| 40 | __forceinline BilinearPatchT (const CatmullClarkPatch& patch) |
| 41 | { |
| 42 | v[0] = patch.ring[0].getLimitVertex(); |
| 43 | v[1] = patch.ring[1].getLimitVertex(); |
| 44 | v[2] = patch.ring[2].getLimitVertex(); |
| 45 | v[3] = patch.ring[3].getLimitVertex(); |
| 46 | } |
| 47 | |
| 48 | __forceinline BBox<Vertex> bounds() const |
| 49 | { |
| 50 | |
| 51 | BBox<Vertex> bounds (v[0]); |
| 52 | bounds.extend(v[1]); |
| 53 | bounds.extend(v[2]); |
| 54 | bounds.extend(v[3]); |
| 55 | return bounds; |
| 56 | } |
| 57 | |
| 58 | __forceinline Vertex eval(const float uu, const float vv) const { |
| 59 | return lerp(lerp(v[0],v[1],uu),lerp(v[3],v[2],uu),vv); |
| 60 | } |
| 61 | |
| 62 | __forceinline Vertex eval_du(const float uu, const float vv) const { |
| 63 | return lerp(v[1]-v[0],v[2]-v[3],vv); |
| 64 | } |
| 65 | |
| 66 | __forceinline Vertex eval_dv(const float uu, const float vv) const { |
| 67 | return lerp(v[3]-v[0],v[2]-v[1],uu); |
| 68 | } |
| 69 | |
| 70 | __forceinline Vertex eval_dudu(const float uu, const float vv) const { |
| 71 | return Vertex(zero); |
| 72 | } |
| 73 | |
| 74 | __forceinline Vertex eval_dvdv(const float uu, const float vv) const { |
| 75 | return Vertex(zero); |
| 76 | } |
| 77 | |
| 78 | __forceinline Vertex eval_dudv(const float uu, const float vv) const { |
| 79 | return (v[2]-v[3]) - (v[1]-v[0]); |
| 80 | } |
| 81 | |
| 82 | __forceinline Vertex normal(const float uu, const float vv) const { |
| 83 | return cross(eval_du(uu,vv),eval_dv(uu,vv)); |
| 84 | } |
| 85 | |
| 86 | __forceinline void eval(const float u, const float v, |
| 87 | Vertex* P, Vertex* dPdu, Vertex* dPdv, Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv, |
| 88 | const float dscale = 1.0f) const |
| 89 | { |
| 90 | if (P) { |
| 91 | *P = eval(u,v); |
| 92 | } |
| 93 | if (dPdu) { |
| 94 | assert(dPdu); *dPdu = eval_du(u,v)*dscale; |
| 95 | assert(dPdv); *dPdv = eval_dv(u,v)*dscale; |
| 96 | } |
| 97 | if (ddPdudu) { |
| 98 | assert(ddPdudu); *ddPdudu = eval_dudu(u,v)*sqr(dscale); |
| 99 | assert(ddPdvdv); *ddPdvdv = eval_dvdv(u,v)*sqr(dscale); |
| 100 | assert(ddPdudv); *ddPdudv = eval_dudv(u,v)*sqr(dscale); |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | template<class vfloat> |
| 105 | __forceinline Vec3<vfloat> eval(const vfloat& uu, const vfloat& vv) const |
| 106 | { |
| 107 | const vfloat x = lerp(lerp(v[0].x,v[1].x,uu),lerp(v[3].x,v[2].x,uu),vv); |
| 108 | const vfloat y = lerp(lerp(v[0].y,v[1].y,uu),lerp(v[3].y,v[2].y,uu),vv); |
| 109 | const vfloat z = lerp(lerp(v[0].z,v[1].z,uu),lerp(v[3].z,v[2].z,uu),vv); |
| 110 | return Vec3<vfloat>(x,y,z); |
| 111 | } |
| 112 | |
| 113 | template<class vfloat> |
| 114 | __forceinline Vec3<vfloat> eval_du(const vfloat& uu, const vfloat& vv) const |
| 115 | { |
| 116 | const vfloat x = lerp(v[1].x-v[0].x,v[2].x-v[3].x,vv); |
| 117 | const vfloat y = lerp(v[1].y-v[0].y,v[2].y-v[3].y,vv); |
| 118 | const vfloat z = lerp(v[1].z-v[0].z,v[2].z-v[3].z,vv); |
| 119 | return Vec3<vfloat>(x,y,z); |
| 120 | } |
| 121 | |
| 122 | template<class vfloat> |
| 123 | __forceinline Vec3<vfloat> eval_dv(const vfloat& uu, const vfloat& vv) const |
| 124 | { |
| 125 | const vfloat x = lerp(v[3].x-v[0].x,v[2].x-v[1].x,uu); |
| 126 | const vfloat y = lerp(v[3].y-v[0].y,v[2].y-v[1].y,uu); |
| 127 | const vfloat z = lerp(v[3].z-v[0].z,v[2].z-v[1].z,uu); |
| 128 | return Vec3<vfloat>(x,y,z); |
| 129 | } |
| 130 | |
| 131 | template<typename vfloat> |
| 132 | __forceinline Vec3<vfloat> normal(const vfloat& uu, const vfloat& vv) const { |
| 133 | return cross(eval_du(uu,vv),eval_dv(uu,vv)); |
| 134 | } |
| 135 | |
| 136 | template<class vfloat> |
| 137 | __forceinline vfloat eval(const size_t i, const vfloat& uu, const vfloat& vv) const { |
| 138 | return lerp(lerp(v[0][i],v[1][i],uu),lerp(v[3][i],v[2][i],uu),vv); |
| 139 | } |
| 140 | |
| 141 | template<class vfloat> |
| 142 | __forceinline vfloat eval_du(const size_t i, const vfloat& uu, const vfloat& vv) const { |
| 143 | return lerp(v[1][i]-v[0][i],v[2][i]-v[3][i],vv); |
| 144 | } |
| 145 | |
| 146 | template<class vfloat> |
| 147 | __forceinline vfloat eval_dv(const size_t i, const vfloat& uu, const vfloat& vv) const { |
| 148 | return lerp(v[3][i]-v[0][i],v[2][i]-v[1][i],uu); |
| 149 | } |
| 150 | |
| 151 | template<class vfloat> |
| 152 | __forceinline vfloat eval_dudu(const size_t i, const vfloat& uu, const vfloat& vv) const { |
| 153 | return vfloat(zero); |
| 154 | } |
| 155 | |
| 156 | template<class vfloat> |
| 157 | __forceinline vfloat eval_dvdv(const size_t i, const vfloat& uu, const vfloat& vv) const { |
| 158 | return vfloat(zero); |
| 159 | } |
| 160 | |
| 161 | template<class vfloat> |
| 162 | __forceinline vfloat eval_dudv(const size_t i, const vfloat& uu, const vfloat& vv) const { |
| 163 | return (v[2][i]-v[3][i]) - (v[1][i]-v[0][i]); |
| 164 | } |
| 165 | |
| 166 | template<typename vbool, typename vfloat> |
| 167 | __forceinline void eval(const vbool& valid, const vfloat& uu, const vfloat& vv, |
| 168 | float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv, |
| 169 | const float dscale, const size_t dstride, const size_t N) const |
| 170 | { |
| 171 | if (P) { |
| 172 | for (size_t i=0; i<N; i++) vfloat::store(valid,P+i*dstride,eval(i,uu,vv)); |
| 173 | } |
| 174 | if (dPdu) { |
| 175 | for (size_t i=0; i<N; i++) { |
| 176 | assert(dPdu); vfloat::store(valid,dPdu+i*dstride,eval_du(i,uu,vv)*dscale); |
| 177 | assert(dPdv); vfloat::store(valid,dPdv+i*dstride,eval_dv(i,uu,vv)*dscale); |
| 178 | } |
| 179 | } |
| 180 | if (ddPdudu) { |
| 181 | for (size_t i=0; i<N; i++) { |
| 182 | assert(ddPdudu); vfloat::store(valid,ddPdudu+i*dstride,eval_dudu(i,uu,vv)*sqr(dscale)); |
| 183 | assert(ddPdvdv); vfloat::store(valid,ddPdvdv+i*dstride,eval_dvdv(i,uu,vv)*sqr(dscale)); |
| 184 | assert(ddPdudv); vfloat::store(valid,ddPdudv+i*dstride,eval_dudv(i,uu,vv)*sqr(dscale)); |
| 185 | } |
| 186 | } |
| 187 | } |
| 188 | }; |
| 189 | |
| 190 | typedef BilinearPatchT<Vec3fa,Vec3fa_t> BilinearPatch3fa; |
| 191 | } |
| 192 | |