| 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<class T, class S> | 
| 12 |     static __forceinline T deCasteljau(const S& uu, const T& v0, const T& v1, const T& v2, const T& v3) | 
| 13 |   { | 
| 14 |     const T v0_1 = lerp(v0,v1,uu); | 
| 15 |     const T v1_1 = lerp(v1,v2,uu); | 
| 16 |     const T v2_1 = lerp(v2,v3,uu); | 
| 17 |     const T v0_2 = lerp(v0_1,v1_1,uu); | 
| 18 |     const T v1_2 = lerp(v1_1,v2_1,uu); | 
| 19 |     const T v0_3 = lerp(v0_2,v1_2,uu); | 
| 20 |     return v0_3; | 
| 21 |   } | 
| 22 |    | 
| 23 |   template<class T, class S> | 
| 24 |     static __forceinline T deCasteljau_tangent(const S& uu, const T& v0, const T& v1, const T& v2, const T& v3) | 
| 25 |   { | 
| 26 |     const T v0_1 = lerp(v0,v1,uu); | 
| 27 |     const T v1_1 = lerp(v1,v2,uu); | 
| 28 |     const T v2_1 = lerp(v2,v3,uu); | 
| 29 |     const T v0_2 = lerp(v0_1,v1_1,uu); | 
| 30 |     const T v1_2 = lerp(v1_1,v2_1,uu); | 
| 31 |     return S(3.0f)*(v1_2-v0_2); | 
| 32 |   } | 
| 33 |  | 
| 34 |   template<typename Vertex> | 
| 35 |     __forceinline Vertex computeInnerBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x) { | 
| 36 |     return 1.0f / 36.0f * (16.0f * v[y][x] + 4.0f * (v[y-1][x] +  v[y+1][x] + v[y][x-1] + v[y][x+1]) + (v[y-1][x-1] + v[y+1][x+1] + v[y-1][x+1] + v[y+1][x-1])); | 
| 37 |   } | 
| 38 |    | 
| 39 |   template<typename Vertex> | 
| 40 |     __forceinline Vertex computeTopEdgeBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x) { | 
| 41 |     return 1.0f / 18.0f * (8.0f * v[y][x] + 4.0f * v[y-1][x] + 2.0f * (v[y][x-1] + v[y][x+1]) + (v[y-1][x-1] + v[y-1][x+1])); | 
| 42 |   } | 
| 43 |  | 
| 44 |   template<typename Vertex> | 
| 45 |     __forceinline Vertex computeBottomEdgeBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x) { | 
| 46 |     return 1.0f / 18.0f * (8.0f * v[y][x] + 4.0f * v[y+1][x] + 2.0f * (v[y][x-1] + v[y][x+1]) + v[y+1][x-1] + v[y+1][x+1]); | 
| 47 |   } | 
| 48 |    | 
| 49 |   template<typename Vertex> | 
| 50 |     __forceinline Vertex computeLeftEdgeBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x) { | 
| 51 |     return 1.0f / 18.0f * (8.0f * v[y][x] + 4.0f * v[y][x-1] + 2.0f * (v[y-1][x] + v[y+1][x]) + v[y-1][x-1] + v[y+1][x-1]); | 
| 52 |   } | 
| 53 |    | 
| 54 |   template<typename Vertex> | 
| 55 |     __forceinline Vertex computeRightEdgeBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x) { | 
| 56 |     return 1.0f / 18.0f * (8.0f * v[y][x] + 4.0f * v[y][x+1] + 2.0f * (v[y-1][x] + v[y+1][x]) + v[y-1][x+1] + v[y+1][x+1]); | 
| 57 |   } | 
| 58 |    | 
| 59 |   template<typename Vertex> | 
| 60 |     __forceinline Vertex computeCornerBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x, const ssize_t delta_y, const ssize_t delta_x) | 
| 61 |   { | 
| 62 |     return 1.0f / 9.0f * (4.0f * v[y][x] + 2.0f * (v[y+delta_y][x] + v[y][x+delta_x]) + v[y+delta_y][x+delta_x]); | 
| 63 |   } | 
| 64 |  | 
| 65 |   template<typename Vertex, typename Vertex_t> | 
| 66 |     class __aligned(64) BezierPatchT | 
| 67 |   { | 
| 68 |    public: | 
| 69 |       Vertex matrix[4][4]; | 
| 70 |      | 
| 71 |   public: | 
| 72 |  | 
| 73 |     __forceinline BezierPatchT() {} | 
| 74 |  | 
| 75 |     __forceinline BezierPatchT (const HalfEdge* edge, const char* vertices, size_t stride); | 
| 76 |  | 
| 77 |     __forceinline BezierPatchT(const CatmullClarkPatchT<Vertex,Vertex_t>& patch); | 
| 78 |  | 
| 79 |     __forceinline BezierPatchT(const CatmullClarkPatchT<Vertex,Vertex_t>& patch, | 
| 80 |                                const BezierCurveT<Vertex>* border0, | 
| 81 |                                const BezierCurveT<Vertex>* border1, | 
| 82 |                                const BezierCurveT<Vertex>* border2, | 
| 83 |                                const BezierCurveT<Vertex>* border3); | 
| 84 |                                 | 
| 85 |     __forceinline BezierPatchT(const BSplinePatchT<Vertex,Vertex_t>& source) | 
| 86 |     { | 
| 87 |       /* compute inner bezier control points */ | 
| 88 |       matrix[0][0] = computeInnerBezierControlPoint(source.v,1,1); | 
| 89 |       matrix[0][3] = computeInnerBezierControlPoint(source.v,1,2); | 
| 90 |       matrix[3][3] = computeInnerBezierControlPoint(source.v,2,2); | 
| 91 |       matrix[3][0] = computeInnerBezierControlPoint(source.v,2,1); | 
| 92 |        | 
| 93 |       /* compute top edge control points */ | 
| 94 |       matrix[0][1] = computeRightEdgeBezierControlPoint(source.v,1,1); | 
| 95 |       matrix[0][2] = computeLeftEdgeBezierControlPoint(source.v,1,2);  | 
| 96 |        | 
| 97 |       /* compute buttom edge control points */ | 
| 98 |       matrix[3][1] = computeRightEdgeBezierControlPoint(source.v,2,1); | 
| 99 |       matrix[3][2] = computeLeftEdgeBezierControlPoint(source.v,2,2); | 
| 100 |        | 
| 101 |       /* compute left edge control points */ | 
| 102 |       matrix[1][0] = computeBottomEdgeBezierControlPoint(source.v,1,1); | 
| 103 |       matrix[2][0] = computeTopEdgeBezierControlPoint(source.v,2,1); | 
| 104 |        | 
| 105 |       /* compute right edge control points */ | 
| 106 |       matrix[1][3] = computeBottomEdgeBezierControlPoint(source.v,1,2); | 
| 107 |       matrix[2][3] = computeTopEdgeBezierControlPoint(source.v,2,2); | 
| 108 |        | 
| 109 |       /* compute corner control points */ | 
| 110 |       matrix[1][1] = computeCornerBezierControlPoint(source.v,1,1, 1, 1); | 
| 111 |       matrix[1][2] = computeCornerBezierControlPoint(source.v,1,2, 1,-1); | 
| 112 |       matrix[2][2] = computeCornerBezierControlPoint(source.v,2,2,-1,-1); | 
| 113 |       matrix[2][1] = computeCornerBezierControlPoint(source.v,2,1,-1, 1);       | 
| 114 |     } | 
| 115 |  | 
| 116 |     static __forceinline Vertex_t bilinear(const Vec4f Bu, const Vertex matrix[4][4], const Vec4f Bv) | 
| 117 |     { | 
| 118 |       const Vertex_t M0 = madd(Bu.x,matrix[0][0],madd(Bu.y,matrix[0][1],madd(Bu.z,matrix[0][2],Bu.w * matrix[0][3])));  | 
| 119 |       const Vertex_t M1 = madd(Bu.x,matrix[1][0],madd(Bu.y,matrix[1][1],madd(Bu.z,matrix[1][2],Bu.w * matrix[1][3]))); | 
| 120 |       const Vertex_t M2 = madd(Bu.x,matrix[2][0],madd(Bu.y,matrix[2][1],madd(Bu.z,matrix[2][2],Bu.w * matrix[2][3]))); | 
| 121 |       const Vertex_t M3 = madd(Bu.x,matrix[3][0],madd(Bu.y,matrix[3][1],madd(Bu.z,matrix[3][2],Bu.w * matrix[3][3]))); | 
| 122 |       return madd(Bv.x,M0,madd(Bv.y,M1,madd(Bv.z,M2,Bv.w*M3))); | 
| 123 |     } | 
| 124 |  | 
| 125 |     static __forceinline Vertex_t eval(const Vertex matrix[4][4], const float uu, const float vv)  | 
| 126 |     {       | 
| 127 |       const Vec4f Bu = BezierBasis::eval(u: uu); | 
| 128 |       const Vec4f Bv = BezierBasis::eval(u: vv); | 
| 129 |       return bilinear(Bu,matrix,Bv); | 
| 130 |     } | 
| 131 |  | 
| 132 |     static __forceinline Vertex_t eval_du(const Vertex matrix[4][4], const float uu, const float vv)  | 
| 133 |     { | 
| 134 |       const Vec4f Bu = BezierBasis::derivative(u: uu); | 
| 135 |       const Vec4f Bv = BezierBasis::eval(u: vv); | 
| 136 |       return bilinear(Bu,matrix,Bv); | 
| 137 |     } | 
| 138 |  | 
| 139 |     static __forceinline Vertex_t eval_dv(const Vertex matrix[4][4], const float uu, const float vv)  | 
| 140 |     { | 
| 141 |       const Vec4f Bu = BezierBasis::eval(u: uu); | 
| 142 |       const Vec4f Bv = BezierBasis::derivative(u: vv); | 
| 143 |       return bilinear(Bu,matrix,Bv); | 
| 144 |     } | 
| 145 |  | 
| 146 |     static __forceinline Vertex_t eval_dudu(const Vertex matrix[4][4], const float uu, const float vv)  | 
| 147 |     { | 
| 148 |       const Vec4f Bu = BezierBasis::derivative2(u: uu); | 
| 149 |       const Vec4f Bv = BezierBasis::eval(u: vv); | 
| 150 |       return bilinear(Bu,matrix,Bv); | 
| 151 |     } | 
| 152 |  | 
| 153 |     static __forceinline Vertex_t eval_dvdv(const Vertex matrix[4][4], const float uu, const float vv)  | 
| 154 |     { | 
| 155 |       const Vec4f Bu = BezierBasis::eval(u: uu); | 
| 156 |       const Vec4f Bv = BezierBasis::derivative2(u: vv); | 
| 157 |       return bilinear(Bu,matrix,Bv); | 
| 158 |     } | 
| 159 |  | 
| 160 |     static __forceinline Vertex_t eval_dudv(const Vertex matrix[4][4], const float uu, const float vv)  | 
| 161 |     { | 
| 162 |       const Vec4f Bu = BezierBasis::derivative(u: uu); | 
| 163 |       const Vec4f Bv = BezierBasis::derivative(u: vv); | 
| 164 |       return bilinear(Bu,matrix,Bv); | 
| 165 |     } | 
| 166 |  | 
| 167 |     static __forceinline Vertex_t normal(const Vertex matrix[4][4], const float uu, const float vv)  | 
| 168 |     { | 
| 169 |       const Vertex_t dPdu = eval_du(matrix,uu,vv); | 
| 170 |       const Vertex_t dPdv = eval_dv(matrix,uu,vv); | 
| 171 |       return cross(dPdu,dPdv); | 
| 172 |     } | 
| 173 |  | 
| 174 |     __forceinline Vertex_t normal(const float uu, const float vv)  | 
| 175 |     { | 
| 176 |       const Vertex_t dPdu = eval_du(matrix,uu,vv); | 
| 177 |       const Vertex_t dPdv = eval_dv(matrix,uu,vv); | 
| 178 |       return cross(dPdu,dPdv); | 
| 179 |     } | 
| 180 |  | 
| 181 |     __forceinline Vertex_t eval(const float uu, const float vv) const { | 
| 182 |       return eval(matrix,uu,vv); | 
| 183 |     } | 
| 184 |  | 
| 185 |     __forceinline Vertex_t eval_du(const float uu, const float vv) const {  | 
| 186 |       return eval_du(matrix,uu,vv); | 
| 187 |     } | 
| 188 |  | 
| 189 |     __forceinline Vertex_t eval_dv(const float uu, const float vv) const { | 
| 190 |       return eval_dv(matrix,uu,vv); | 
| 191 |     } | 
| 192 |  | 
| 193 |     __forceinline Vertex_t eval_dudu(const float uu, const float vv) const {  | 
| 194 |       return eval_dudu(matrix,uu,vv); | 
| 195 |     } | 
| 196 |      | 
| 197 |     __forceinline Vertex_t eval_dvdv(const float uu, const float vv) const {  | 
| 198 |       return eval_dvdv(matrix,uu,vv); | 
| 199 |     } | 
| 200 |  | 
| 201 |     __forceinline Vertex_t eval_dudv(const float uu, const float vv) const {  | 
| 202 |       return eval_dudv(matrix,uu,vv); | 
| 203 |     } | 
| 204 |  | 
| 205 |     __forceinline void eval(const float u, const float v, Vertex* P, Vertex* dPdu, Vertex* dPdv, Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv, const float dscale = 1.0f) const | 
| 206 |     { | 
| 207 |       if (P) { | 
| 208 |         *P = eval(u,v);  | 
| 209 |       } | 
| 210 |       if (dPdu) { | 
| 211 |         assert(dPdu); *dPdu = eval_du(u,v)*dscale;  | 
| 212 |         assert(dPdv); *dPdv = eval_dv(u,v)*dscale;  | 
| 213 |       } | 
| 214 |       if (ddPdudu) { | 
| 215 |         assert(ddPdudu); *ddPdudu = eval_dudu(u,v)*sqr(x: dscale);  | 
| 216 |         assert(ddPdvdv); *ddPdvdv = eval_dvdv(u,v)*sqr(x: dscale);  | 
| 217 |         assert(ddPdudv); *ddPdudv = eval_dudv(u,v)*sqr(x: dscale);  | 
| 218 |       } | 
| 219 |     } | 
| 220 |  | 
| 221 |     template<class vfloat> | 
| 222 |       __forceinline vfloat eval(const size_t i, const vfloat& uu, const vfloat& vv, const Vec4<vfloat>& u_n, const Vec4<vfloat>& v_n) const | 
| 223 |       { | 
| 224 |         const vfloat curve0_x = v_n[0] * vfloat(matrix[0][0][i]) + v_n[1] * vfloat(matrix[1][0][i]) + v_n[2] * vfloat(matrix[2][0][i]) + v_n[3] * vfloat(matrix[3][0][i]); | 
| 225 |         const vfloat curve1_x = v_n[0] * vfloat(matrix[0][1][i]) + v_n[1] * vfloat(matrix[1][1][i]) + v_n[2] * vfloat(matrix[2][1][i]) + v_n[3] * vfloat(matrix[3][1][i]); | 
| 226 |         const vfloat curve2_x = v_n[0] * vfloat(matrix[0][2][i]) + v_n[1] * vfloat(matrix[1][2][i]) + v_n[2] * vfloat(matrix[2][2][i]) + v_n[3] * vfloat(matrix[3][2][i]); | 
| 227 |         const vfloat curve3_x = v_n[0] * vfloat(matrix[0][3][i]) + v_n[1] * vfloat(matrix[1][3][i]) + v_n[2] * vfloat(matrix[2][3][i]) + v_n[3] * vfloat(matrix[3][3][i]); | 
| 228 |         return u_n[0] * curve0_x + u_n[1] * curve1_x + u_n[2] * curve2_x + u_n[3] * curve3_x; | 
| 229 |       } | 
| 230 |  | 
| 231 |     template<typename vbool, typename vfloat> | 
| 232 |       __forceinline void eval(const vbool& valid, const vfloat& uu, const vfloat& vv,  | 
| 233 |                               float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv, | 
| 234 |                               const float dscale, const size_t dstride, const size_t N) const | 
| 235 |       { | 
| 236 |         if (P) { | 
| 237 |           const Vec4<vfloat> u_n = BezierBasis::eval(uu);  | 
| 238 |           const Vec4<vfloat> v_n = BezierBasis::eval(vv);  | 
| 239 |           for (size_t i=0; i<N; i++) vfloat::store(valid,P+i*dstride,eval(i,uu,vv,u_n,v_n)); | 
| 240 |         } | 
| 241 |         if (dPdu)  | 
| 242 |         { | 
| 243 |           { | 
| 244 |             assert(dPdu); | 
| 245 |             const Vec4<vfloat> u_n = BezierBasis::derivative(uu); | 
| 246 |             const Vec4<vfloat> v_n = BezierBasis::eval(vv);  | 
| 247 |             for (size_t i=0; i<N; i++) vfloat::store(valid,dPdu+i*dstride,eval(i,uu,vv,u_n,v_n)*dscale); | 
| 248 |           } | 
| 249 |           { | 
| 250 |             assert(dPdv); | 
| 251 |             const Vec4<vfloat> u_n = BezierBasis::eval(uu); | 
| 252 |             const Vec4<vfloat> v_n = BezierBasis::derivative(vv);  | 
| 253 |             for (size_t i=0; i<N; i++) vfloat::store(valid,dPdv+i*dstride,eval(i,uu,vv,u_n,v_n)*dscale); | 
| 254 |           } | 
| 255 |         } | 
| 256 |         if (ddPdudu)  | 
| 257 |         { | 
| 258 |           { | 
| 259 |             assert(ddPdudu); | 
| 260 |             const Vec4<vfloat> u_n = BezierBasis::derivative2(uu); | 
| 261 |             const Vec4<vfloat> v_n = BezierBasis::eval(vv);  | 
| 262 |             for (size_t i=0; i<N; i++) vfloat::store(valid,ddPdudu+i*dstride,eval(i,uu,vv,u_n,v_n)*sqr(x: dscale)); | 
| 263 |           } | 
| 264 |           { | 
| 265 |             assert(ddPdvdv); | 
| 266 |             const Vec4<vfloat> u_n = BezierBasis::eval(uu); | 
| 267 |             const Vec4<vfloat> v_n = BezierBasis::derivative2(vv);  | 
| 268 |             for (size_t i=0; i<N; i++) vfloat::store(valid,ddPdvdv+i*dstride,eval(i,uu,vv,u_n,v_n)*sqr(x: dscale)); | 
| 269 |           } | 
| 270 |           { | 
| 271 |             assert(ddPdudv); | 
| 272 |             const Vec4<vfloat> u_n = BezierBasis::derivative(uu); | 
| 273 |             const Vec4<vfloat> v_n = BezierBasis::derivative(vv);  | 
| 274 |             for (size_t i=0; i<N; i++) vfloat::store(valid,ddPdudv+i*dstride,eval(i,uu,vv,u_n,v_n)*sqr(x: dscale)); | 
| 275 |           } | 
| 276 |         } | 
| 277 |       } | 
| 278 |  | 
| 279 |     template<typename T> | 
| 280 |       static __forceinline Vec3<T> eval(const Vertex matrix[4][4], const T& uu, const T& vv)  | 
| 281 |     {       | 
| 282 |       const T one_minus_uu = 1.0f - uu; | 
| 283 |       const T one_minus_vv = 1.0f - vv;       | 
| 284 |  | 
| 285 |       const T B0_u = one_minus_uu * one_minus_uu * one_minus_uu; | 
| 286 |       const T B0_v = one_minus_vv * one_minus_vv * one_minus_vv; | 
| 287 |       const T B1_u = 3.0f * (one_minus_uu * uu * one_minus_uu); | 
| 288 |       const T B1_v = 3.0f * (one_minus_vv * vv * one_minus_vv); | 
| 289 |       const T B2_u = 3.0f * (uu * one_minus_uu * uu); | 
| 290 |       const T B2_v = 3.0f * (vv * one_minus_vv * vv); | 
| 291 |       const T B3_u = uu * uu * uu; | 
| 292 |       const T B3_v = vv * vv * vv; | 
| 293 |        | 
| 294 |       const T x =  | 
| 295 |         madd(B0_v,madd(B0_u,matrix[0][0].x,madd(B1_u,matrix[0][1].x,madd(B2_u,matrix[0][2].x,B3_u*matrix[0][3].x))),  | 
| 296 |         madd(B1_v,madd(B0_u,matrix[1][0].x,madd(B1_u,matrix[1][1].x,madd(B2_u,matrix[1][2].x,B3_u*matrix[1][3].x))), | 
| 297 |         madd(B2_v,madd(B0_u,matrix[2][0].x,madd(B1_u,matrix[2][1].x,madd(B2_u,matrix[2][2].x,B3_u*matrix[2][3].x))), | 
| 298 |              B3_v*madd(B0_u,matrix[3][0].x,madd(B1_u,matrix[3][1].x,madd(B2_u,matrix[3][2].x,B3_u*matrix[3][3].x))))));  | 
| 299 |  | 
| 300 |       const T y =  | 
| 301 |         madd(B0_v,madd(B0_u,matrix[0][0].y,madd(B1_u,matrix[0][1].y,madd(B2_u,matrix[0][2].y,B3_u*matrix[0][3].y))),  | 
| 302 |         madd(B1_v,madd(B0_u,matrix[1][0].y,madd(B1_u,matrix[1][1].y,madd(B2_u,matrix[1][2].y,B3_u*matrix[1][3].y))), | 
| 303 |         madd(B2_v,madd(B0_u,matrix[2][0].y,madd(B1_u,matrix[2][1].y,madd(B2_u,matrix[2][2].y,B3_u*matrix[2][3].y))), | 
| 304 |              B3_v*madd(B0_u,matrix[3][0].y,madd(B1_u,matrix[3][1].y,madd(B2_u,matrix[3][2].y,B3_u*matrix[3][3].y))))));  | 
| 305 |        | 
| 306 |       const T z =  | 
| 307 |         madd(B0_v,madd(B0_u,matrix[0][0].z,madd(B1_u,matrix[0][1].z,madd(B2_u,matrix[0][2].z,B3_u*matrix[0][3].z))),  | 
| 308 |         madd(B1_v,madd(B0_u,matrix[1][0].z,madd(B1_u,matrix[1][1].z,madd(B2_u,matrix[1][2].z,B3_u*matrix[1][3].z))), | 
| 309 |         madd(B2_v,madd(B0_u,matrix[2][0].z,madd(B1_u,matrix[2][1].z,madd(B2_u,matrix[2][2].z,B3_u*matrix[2][3].z))), | 
| 310 |              B3_v*madd(B0_u,matrix[3][0].z,madd(B1_u,matrix[3][1].z,madd(B2_u,matrix[3][2].z,B3_u*matrix[3][3].z))))));  | 
| 311 |        | 
| 312 |       return Vec3<T>(x,y,z); | 
| 313 |     } | 
| 314 |  | 
| 315 |     template<typename vfloat> | 
| 316 |       __forceinline Vec3<vfloat> eval(const vfloat& uu, const vfloat& vv) const {      | 
| 317 |       return eval(matrix,uu,vv); | 
| 318 |     } | 
| 319 |  | 
| 320 |     template<class T> | 
| 321 |       static __forceinline Vec3<T> normal(const Vertex matrix[4][4], const T& uu, const T& vv)  | 
| 322 |     { | 
| 323 |        | 
| 324 |       const Vec3<T> matrix_00 = Vec3<T>(matrix[0][0].x,matrix[0][0].y,matrix[0][0].z); | 
| 325 |       const Vec3<T> matrix_01 = Vec3<T>(matrix[0][1].x,matrix[0][1].y,matrix[0][1].z); | 
| 326 |       const Vec3<T> matrix_02 = Vec3<T>(matrix[0][2].x,matrix[0][2].y,matrix[0][2].z); | 
| 327 |       const Vec3<T> matrix_03 = Vec3<T>(matrix[0][3].x,matrix[0][3].y,matrix[0][3].z); | 
| 328 |  | 
| 329 |       const Vec3<T> matrix_10 = Vec3<T>(matrix[1][0].x,matrix[1][0].y,matrix[1][0].z); | 
| 330 |       const Vec3<T> matrix_11 = Vec3<T>(matrix[1][1].x,matrix[1][1].y,matrix[1][1].z); | 
| 331 |       const Vec3<T> matrix_12 = Vec3<T>(matrix[1][2].x,matrix[1][2].y,matrix[1][2].z); | 
| 332 |       const Vec3<T> matrix_13 = Vec3<T>(matrix[1][3].x,matrix[1][3].y,matrix[1][3].z); | 
| 333 |  | 
| 334 |       const Vec3<T> matrix_20 = Vec3<T>(matrix[2][0].x,matrix[2][0].y,matrix[2][0].z); | 
| 335 |       const Vec3<T> matrix_21 = Vec3<T>(matrix[2][1].x,matrix[2][1].y,matrix[2][1].z); | 
| 336 |       const Vec3<T> matrix_22 = Vec3<T>(matrix[2][2].x,matrix[2][2].y,matrix[2][2].z); | 
| 337 |       const Vec3<T> matrix_23 = Vec3<T>(matrix[2][3].x,matrix[2][3].y,matrix[2][3].z); | 
| 338 |  | 
| 339 |       const Vec3<T> matrix_30 = Vec3<T>(matrix[3][0].x,matrix[3][0].y,matrix[3][0].z); | 
| 340 |       const Vec3<T> matrix_31 = Vec3<T>(matrix[3][1].x,matrix[3][1].y,matrix[3][1].z); | 
| 341 |       const Vec3<T> matrix_32 = Vec3<T>(matrix[3][2].x,matrix[3][2].y,matrix[3][2].z); | 
| 342 |       const Vec3<T> matrix_33 = Vec3<T>(matrix[3][3].x,matrix[3][3].y,matrix[3][3].z); | 
| 343 |              | 
| 344 |       /* tangentU */ | 
| 345 |       const Vec3<T> col0 = deCasteljau(vv, matrix_00, matrix_10, matrix_20, matrix_30); | 
| 346 |       const Vec3<T> col1 = deCasteljau(vv, matrix_01, matrix_11, matrix_21, matrix_31); | 
| 347 |       const Vec3<T> col2 = deCasteljau(vv, matrix_02, matrix_12, matrix_22, matrix_32); | 
| 348 |       const Vec3<T> col3 = deCasteljau(vv, matrix_03, matrix_13, matrix_23, matrix_33); | 
| 349 |        | 
| 350 |       const Vec3<T> tangentU = deCasteljau_tangent(uu, col0, col1, col2, col3); | 
| 351 |        | 
| 352 |       /* tangentV */ | 
| 353 |       const Vec3<T> row0 = deCasteljau(uu, matrix_00, matrix_01, matrix_02, matrix_03); | 
| 354 |       const Vec3<T> row1 = deCasteljau(uu, matrix_10, matrix_11, matrix_12, matrix_13); | 
| 355 |       const Vec3<T> row2 = deCasteljau(uu, matrix_20, matrix_21, matrix_22, matrix_23); | 
| 356 |       const Vec3<T> row3 = deCasteljau(uu, matrix_30, matrix_31, matrix_32, matrix_33); | 
| 357 |        | 
| 358 |       const Vec3<T> tangentV = deCasteljau_tangent(vv, row0, row1, row2, row3); | 
| 359 |        | 
| 360 |       /* normal = tangentU x tangentV */ | 
| 361 |       const Vec3<T> n = cross(tangentU,tangentV); | 
| 362 |       return n; | 
| 363 |     } | 
| 364 |  | 
| 365 |     template<typename vfloat> | 
| 366 |       __forceinline Vec3<vfloat> normal(const vfloat& uu, const vfloat& vv) const {      | 
| 367 |       return normal(matrix,uu,vv); | 
| 368 |     } | 
| 369 |   }; | 
| 370 |  | 
| 371 |   typedef BezierPatchT<Vec3fa,Vec3fa_t> BezierPatch3fa; | 
| 372 | } | 
| 373 |  |