// Copyright 2009-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #include "subdivpatch1base.h" namespace embree { namespace isa { Vec3fa patchEval(const SubdivPatch1Base& patch, const float uu, const float vv) { if (likely(patch.type == SubdivPatch1Base::BEZIER_PATCH)) return ((BezierPatch3fa*)patch.patch_v)->eval(uu,vv); else if (likely(patch.type == SubdivPatch1Base::BSPLINE_PATCH)) return ((BSplinePatch3fa*)patch.patch_v)->eval(uu,vv); else if (likely(patch.type == SubdivPatch1Base::GREGORY_PATCH)) return ((DenseGregoryPatch3fa*)patch.patch_v)->eval(uu,vv); else if (likely(patch.type == SubdivPatch1Base::BILINEAR_PATCH)) return ((BilinearPatch3fa*)patch.patch_v)->eval(uu,vv); return Vec3fa( zero ); } Vec3fa patchNormal(const SubdivPatch1Base& patch, const float uu, const float vv) { if (likely(patch.type == SubdivPatch1Base::BEZIER_PATCH)) return ((BezierPatch3fa*)patch.patch_v)->normal(uu,vv); else if (likely(patch.type == SubdivPatch1Base::BSPLINE_PATCH)) return ((BSplinePatch3fa*)patch.patch_v)->normal(uu,vv); else if (likely(patch.type == SubdivPatch1Base::GREGORY_PATCH)) return ((DenseGregoryPatch3fa*)patch.patch_v)->normal(uu,vv); else if (likely(patch.type == SubdivPatch1Base::BILINEAR_PATCH)) return ((BilinearPatch3fa*)patch.patch_v)->normal(uu,vv); return Vec3fa( zero ); } template Vec3 patchEval(const SubdivPatch1Base& patch, const simdf& uu, const simdf& vv) { if (likely(patch.type == SubdivPatch1Base::BEZIER_PATCH)) return ((BezierPatch3fa*)patch.patch_v)->eval(uu,vv); else if (likely(patch.type == SubdivPatch1Base::BSPLINE_PATCH)) return ((BSplinePatch3fa*)patch.patch_v)->eval(uu,vv); else if (likely(patch.type == SubdivPatch1Base::GREGORY_PATCH)) return ((DenseGregoryPatch3fa*)patch.patch_v)->eval(uu,vv); else if (likely(patch.type == SubdivPatch1Base::BILINEAR_PATCH)) return ((BilinearPatch3fa*)patch.patch_v)->eval(uu,vv); return Vec3( zero ); } template Vec3 patchNormal(const SubdivPatch1Base& patch, const simdf& uu, const simdf& vv) { if (likely(patch.type == SubdivPatch1Base::BEZIER_PATCH)) return ((BezierPatch3fa*)patch.patch_v)->normal(uu,vv); else if (likely(patch.type == SubdivPatch1Base::BSPLINE_PATCH)) return ((BSplinePatch3fa*)patch.patch_v)->normal(uu,vv); else if (likely(patch.type == SubdivPatch1Base::GREGORY_PATCH)) return ((DenseGregoryPatch3fa*)patch.patch_v)->normal(uu,vv); else if (likely(patch.type == SubdivPatch1Base::BILINEAR_PATCH)) return ((BilinearPatch3fa*)patch.patch_v)->normal(uu,vv); return Vec3( zero ); } /* eval grid over patch and stich edges when required */ void evalGrid(const SubdivPatch1Base& patch, const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight, float *__restrict__ const grid_x, float *__restrict__ const grid_y, float *__restrict__ const grid_z, float *__restrict__ const grid_u, float *__restrict__ const grid_v, const SubdivMesh* const geom) { const unsigned dwidth = x1-x0+1; const unsigned dheight = y1-y0+1; const unsigned M = dwidth*dheight+VSIZEX; const unsigned grid_size_simd_blocks = (M-1)/VSIZEX; if (unlikely(patch.type == SubdivPatch1Base::EVAL_PATCH)) { const bool displ = geom->displFunc; const unsigned N = displ ? M : 0; dynamic_large_stack_array(float,grid_Ng_x,N,32*32*sizeof(float)); dynamic_large_stack_array(float,grid_Ng_y,N,32*32*sizeof(float)); dynamic_large_stack_array(float,grid_Ng_z,N,32*32*sizeof(float)); if (geom->patch_eval_trees.size()) { feature_adaptive_eval_grid (geom->patch_eval_trees[geom->numTimeSteps*patch.primID()+patch.time()], patch.subPatch(), patch.needsStitching() ? patch.level : nullptr, x0,x1,y0,y1,swidth,sheight, grid_x,grid_y,grid_z,grid_u,grid_v, displ ? (float*)grid_Ng_x : nullptr, displ ? (float*)grid_Ng_y : nullptr, displ ? (float*)grid_Ng_z : nullptr, dwidth,dheight); } else { GeneralCatmullClarkPatch3fa ccpatch(patch.edge(),geom->getVertexBuffer(patch.time())); feature_adaptive_eval_grid (ccpatch, patch.subPatch(), patch.needsStitching() ? patch.level : nullptr, x0,x1,y0,y1,swidth,sheight, grid_x,grid_y,grid_z,grid_u,grid_v, displ ? (float*)grid_Ng_x : nullptr, displ ? (float*)grid_Ng_y : nullptr, displ ? (float*)grid_Ng_z : nullptr, dwidth,dheight); } /* convert sub-patch UVs to patch UVs*/ const Vec2f uv0 = patch.getUV(0); const Vec2f uv1 = patch.getUV(1); const Vec2f uv2 = patch.getUV(2); const Vec2f uv3 = patch.getUV(3); for (unsigned i=0; idisplFunc)) { RTCDisplacementFunctionNArguments args; args.geometryUserPtr = geom->userPtr; args.geometry = (RTCGeometry)geom; //args.geomID = patch.geomID(); args.primID = patch.primID(); args.timeStep = patch.time(); args.u = grid_u; args.v = grid_v; args.Ng_x = grid_Ng_x; args.Ng_y = grid_Ng_y; args.Ng_z = grid_Ng_z; args.P_x = grid_x; args.P_y = grid_y; args.P_z = grid_z; args.N = dwidth*dheight; geom->displFunc(&args); } /* set last elements in u,v array to 1.0f */ const float last_u = grid_u[dwidth*dheight-1]; const float last_v = grid_v[dwidth*dheight-1]; const float last_x = grid_x[dwidth*dheight-1]; const float last_y = grid_y[dwidth*dheight-1]; const float last_z = grid_z[dwidth*dheight-1]; for (unsigned i=dwidth*dheight;idisplFunc != nullptr)) { const Vec3vfx normal = normalize_safe(patchNormal(patch, u, v)); RTCDisplacementFunctionNArguments args; args.geometryUserPtr = geom->userPtr; args.geometry = (RTCGeometry)geom; //args.geomID = patch.geomID(); args.primID = patch.primID(); args.timeStep = patch.time(); args.u = &u[0]; args.v = &v[0]; args.Ng_x = &normal.x[0]; args.Ng_y = &normal.y[0]; args.Ng_z = &normal.z[0]; args.P_x = &vtx.x[0]; args.P_y = &vtx.y[0]; args.P_z = &vtx.z[0]; args.N = VSIZEX; geom->displFunc(&args); } vfloatx::store(&grid_x[i*VSIZEX],vtx.x); vfloatx::store(&grid_y[i*VSIZEX],vtx.y); vfloatx::store(&grid_z[i*VSIZEX],vtx.z); } } } /* eval grid over patch and stich edges when required */ BBox3fa evalGridBounds(const SubdivPatch1Base& patch, const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight, const SubdivMesh* const geom) { BBox3fa b(empty); const unsigned dwidth = x1-x0+1; const unsigned dheight = y1-y0+1; const unsigned M = dwidth*dheight+VSIZEX; const unsigned grid_size_simd_blocks = (M-1)/VSIZEX; dynamic_large_stack_array(float,grid_u,M,64*64*sizeof(float)); dynamic_large_stack_array(float,grid_v,M,64*64*sizeof(float)); if (unlikely(patch.type == SubdivPatch1Base::EVAL_PATCH)) { const bool displ = geom->displFunc; dynamic_large_stack_array(float,grid_x,M,64*64*sizeof(float)); dynamic_large_stack_array(float,grid_y,M,64*64*sizeof(float)); dynamic_large_stack_array(float,grid_z,M,64*64*sizeof(float)); dynamic_large_stack_array(float,grid_Ng_x,displ ? M : 0,64*64*sizeof(float)); dynamic_large_stack_array(float,grid_Ng_y,displ ? M : 0,64*64*sizeof(float)); dynamic_large_stack_array(float,grid_Ng_z,displ ? M : 0,64*64*sizeof(float)); if (geom->patch_eval_trees.size()) { feature_adaptive_eval_grid (geom->patch_eval_trees[geom->numTimeSteps*patch.primID()+patch.time()], patch.subPatch(), patch.needsStitching() ? patch.level : nullptr, x0,x1,y0,y1,swidth,sheight, grid_x,grid_y,grid_z,grid_u,grid_v, displ ? (float*)grid_Ng_x : nullptr, displ ? (float*)grid_Ng_y : nullptr, displ ? (float*)grid_Ng_z : nullptr, dwidth,dheight); } else { GeneralCatmullClarkPatch3fa ccpatch(patch.edge(),geom->getVertexBuffer(patch.time())); feature_adaptive_eval_grid (ccpatch, patch.subPatch(), patch.needsStitching() ? patch.level : nullptr, x0,x1,y0,y1,swidth,sheight, grid_x,grid_y,grid_z,grid_u,grid_v, displ ? (float*)grid_Ng_x : nullptr, displ ? (float*)grid_Ng_y : nullptr, displ ? (float*)grid_Ng_z : nullptr, dwidth,dheight); } /* call displacement shader */ if (unlikely(geom->displFunc)) { RTCDisplacementFunctionNArguments args; args.geometryUserPtr = geom->userPtr; args.geometry = (RTCGeometry)geom; //args.geomID = patch.geomID(); args.primID = patch.primID(); args.timeStep = patch.time(); args.u = grid_u; args.v = grid_v; args.Ng_x = grid_Ng_x; args.Ng_y = grid_Ng_y; args.Ng_z = grid_Ng_z; args.P_x = grid_x; args.P_y = grid_y; args.P_z = grid_z; args.N = dwidth*dheight; geom->displFunc(&args); } /* set last elements in u,v array to 1.0f */ const float last_u = grid_u[dwidth*dheight-1]; const float last_v = grid_v[dwidth*dheight-1]; const float last_x = grid_x[dwidth*dheight-1]; const float last_y = grid_y[dwidth*dheight-1]; const float last_z = grid_z[dwidth*dheight-1]; for (unsigned i=dwidth*dheight;idisplFunc != nullptr)) { const Vec3vfx normal = normalize_safe(patchNormal(patch,u,v)); RTCDisplacementFunctionNArguments args; args.geometryUserPtr = geom->userPtr; args.geometry = (RTCGeometry)geom; //args.geomID = patch.geomID(); args.primID = patch.primID(); args.timeStep = patch.time(); args.u = &u[0]; args.v = &v[0]; args.Ng_x = &normal.x[0]; args.Ng_y = &normal.y[0]; args.Ng_z = &normal.z[0]; args.P_x = &vtx.x[0]; args.P_y = &vtx.y[0]; args.P_z = &vtx.z[0]; args.N = VSIZEX; geom->displFunc(&args); } bounds_min[0] = min(bounds_min[0],vtx.x); bounds_max[0] = max(bounds_max[0],vtx.x); bounds_min[1] = min(bounds_min[1],vtx.y); bounds_max[1] = max(bounds_max[1],vtx.y); bounds_min[2] = min(bounds_min[2],vtx.z); bounds_max[2] = max(bounds_max[2],vtx.z); } b.lower.x = reduce_min(bounds_min[0]); b.lower.y = reduce_min(bounds_min[1]); b.lower.z = reduce_min(bounds_min[2]); b.upper.x = reduce_max(bounds_max[0]); b.upper.y = reduce_max(bounds_max[1]); b.upper.z = reduce_max(bounds_max[2]); //b.lower.a = 0; //b.upper.a = 0; } assert( std::isfinite(b.lower.x) ); assert( std::isfinite(b.lower.y) ); assert( std::isfinite(b.lower.z) ); assert( std::isfinite(b.upper.x) ); assert( std::isfinite(b.upper.y) ); assert( std::isfinite(b.upper.z) ); assert(b.lower.x <= b.upper.x); assert(b.lower.y <= b.upper.y); assert(b.lower.z <= b.upper.z); return b; } } }