415 lines
16 KiB
C++
415 lines
16 KiB
C++
// 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<typename simdf>
|
|
Vec3<simdf> 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<simdf>( zero );
|
|
}
|
|
|
|
template<typename simdf>
|
|
Vec3<simdf> 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<simdf>( 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<PatchEvalGrid>
|
|
(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<FeatureAdaptiveEvalGrid,GeneralCatmullClarkPatch3fa>
|
|
(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; i<grid_size_simd_blocks; i++)
|
|
{
|
|
const vfloatx u = vfloatx::load(&grid_u[i*VSIZEX]);
|
|
const vfloatx v = vfloatx::load(&grid_v[i*VSIZEX]);
|
|
const vfloatx patch_u = lerp2(uv0.x,uv1.x,uv3.x,uv2.x,u,v);
|
|
const vfloatx patch_v = lerp2(uv0.y,uv1.y,uv3.y,uv2.y,u,v);
|
|
vfloatx::store(&grid_u[i*VSIZEX],patch_u);
|
|
vfloatx::store(&grid_v[i*VSIZEX],patch_v);
|
|
}
|
|
|
|
/* 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;i<grid_size_simd_blocks*VSIZEX;i++)
|
|
{
|
|
grid_u[i] = last_u;
|
|
grid_v[i] = last_v;
|
|
grid_x[i] = last_x;
|
|
grid_y[i] = last_y;
|
|
grid_z[i] = last_z;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* grid_u, grid_v need to be padded as we write with SIMD granularity */
|
|
gridUVTessellator(patch.level,swidth,sheight,x0,y0,dwidth,dheight,grid_u,grid_v);
|
|
|
|
/* set last elements in u,v array to last valid point */
|
|
const float last_u = grid_u[dwidth*dheight-1];
|
|
const float last_v = grid_v[dwidth*dheight-1];
|
|
for (unsigned i=dwidth*dheight;i<grid_size_simd_blocks*VSIZEX;i++) {
|
|
grid_u[i] = last_u;
|
|
grid_v[i] = last_v;
|
|
}
|
|
|
|
/* stitch edges if necessary */
|
|
if (unlikely(patch.needsStitching()))
|
|
stitchUVGrid(patch.level,swidth,sheight,x0,y0,dwidth,dheight,grid_u,grid_v);
|
|
|
|
/* iterates over all grid points */
|
|
for (unsigned i=0; i<grid_size_simd_blocks; i++)
|
|
{
|
|
const vfloatx u = vfloatx::load(&grid_u[i*VSIZEX]);
|
|
const vfloatx v = vfloatx::load(&grid_v[i*VSIZEX]);
|
|
Vec3vfx vtx = patchEval(patch,u,v);
|
|
|
|
/* evaluate displacement function */
|
|
if (unlikely(geom->displFunc != 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<PatchEvalGrid>
|
|
(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 <FeatureAdaptiveEvalGrid,GeneralCatmullClarkPatch3fa>
|
|
(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;i<grid_size_simd_blocks*VSIZEX;i++)
|
|
{
|
|
grid_u[i] = last_u;
|
|
grid_v[i] = last_v;
|
|
grid_x[i] = last_x;
|
|
grid_y[i] = last_y;
|
|
grid_z[i] = last_z;
|
|
}
|
|
|
|
vfloatx bounds_min_x = pos_inf;
|
|
vfloatx bounds_min_y = pos_inf;
|
|
vfloatx bounds_min_z = pos_inf;
|
|
vfloatx bounds_max_x = neg_inf;
|
|
vfloatx bounds_max_y = neg_inf;
|
|
vfloatx bounds_max_z = neg_inf;
|
|
for (unsigned i = 0; i<grid_size_simd_blocks; i++)
|
|
{
|
|
vfloatx x = vfloatx::loadu(&grid_x[i * VSIZEX]);
|
|
vfloatx y = vfloatx::loadu(&grid_y[i * VSIZEX]);
|
|
vfloatx z = vfloatx::loadu(&grid_z[i * VSIZEX]);
|
|
|
|
bounds_min_x = min(bounds_min_x,x);
|
|
bounds_min_y = min(bounds_min_y,y);
|
|
bounds_min_z = min(bounds_min_z,z);
|
|
|
|
bounds_max_x = max(bounds_max_x,x);
|
|
bounds_max_y = max(bounds_max_y,y);
|
|
bounds_max_z = max(bounds_max_z,z);
|
|
}
|
|
|
|
b.lower.x = reduce_min(bounds_min_x);
|
|
b.lower.y = reduce_min(bounds_min_y);
|
|
b.lower.z = reduce_min(bounds_min_z);
|
|
b.upper.x = reduce_max(bounds_max_x);
|
|
b.upper.y = reduce_max(bounds_max_y);
|
|
b.upper.z = reduce_max(bounds_max_z);
|
|
//b.lower.a = 0;
|
|
//b.upper.a = 0;
|
|
}
|
|
else
|
|
{
|
|
/* grid_u, grid_v need to be padded as we write with SIMD granularity */
|
|
gridUVTessellator(patch.level,swidth,sheight,x0,y0,dwidth,dheight,grid_u,grid_v);
|
|
|
|
/* set last elements in u,v array to last valid point */
|
|
const float last_u = grid_u[dwidth*dheight-1];
|
|
const float last_v = grid_v[dwidth*dheight-1];
|
|
for (unsigned i=dwidth*dheight;i<grid_size_simd_blocks*VSIZEX;i++) {
|
|
grid_u[i] = last_u;
|
|
grid_v[i] = last_v;
|
|
}
|
|
|
|
/* stitch edges if necessary */
|
|
if (unlikely(patch.needsStitching()))
|
|
stitchUVGrid(patch.level,swidth,sheight,x0,y0,dwidth,dheight,grid_u,grid_v);
|
|
|
|
/* iterates over all grid points */
|
|
Vec3vfx bounds_min;
|
|
bounds_min[0] = pos_inf;
|
|
bounds_min[1] = pos_inf;
|
|
bounds_min[2] = pos_inf;
|
|
|
|
Vec3vfx bounds_max;
|
|
bounds_max[0] = neg_inf;
|
|
bounds_max[1] = neg_inf;
|
|
bounds_max[2] = neg_inf;
|
|
|
|
for (unsigned i=0; i<grid_size_simd_blocks; i++)
|
|
{
|
|
const vfloatx u = vfloatx::load(&grid_u[i*VSIZEX]);
|
|
const vfloatx v = vfloatx::load(&grid_v[i*VSIZEX]);
|
|
Vec3vfx vtx = patchEval(patch,u,v);
|
|
|
|
/* evaluate displacement function */
|
|
if (unlikely(geom->displFunc != 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;
|
|
}
|
|
}
|
|
}
|