RenderKit / openvkl

Intel(R) Open Volume Kernel Library
Apache License 2.0
200 stars 26 forks source link

[Question] Does anyone know logic of iso-parametric interpolation functions for different unstructured type of cells? #30

Open kuldip-wagh opened 3 months ago

kuldip-wagh commented 3 months ago

We can see the r,s,t based interolation code for unstructured cell type types. Does anyone know logic/algorithm explanation behind it? The code looks something like this:

//----------------------------------------------------------------------------
// Compute iso-parametric interpolation functions
//
static inline void pyramidInterpolationFunctions(float pcoords[3], float sf[5])
{
  float rm, sm, tm;

  rm = 1.f - pcoords[0];
  sm = 1.f - pcoords[1];
  tm = 1.f - pcoords[2];

  sf[0] = rm * sm * tm;
  sf[1] = pcoords[0] * sm * tm;
  sf[2] = pcoords[0] * pcoords[1] * tm;
  sf[3] = rm * pcoords[1] * tm;
  sf[4] = pcoords[2];
}

//----------------------------------------------------------------------------
static inline void pyramidInterpolationDerivs(float pcoords[3],
                                              float derivs[15])
{
  // r-derivatives
  derivs[0] = -(pcoords[1] - 1.f) * (pcoords[2] - 1.f);
  derivs[1] = (pcoords[1] - 1.f) * (pcoords[2] - 1.f);
  derivs[2] = pcoords[1] - pcoords[1] * pcoords[2];
  derivs[3] = pcoords[1] * (pcoords[2] - 1.f);
  derivs[4] = 0.f;

  // s-derivatives
  derivs[5] = -(pcoords[0] - 1.f) * (pcoords[2] - 1.f);
  derivs[6] = pcoords[0] * (pcoords[2] - 1.f);
  derivs[7] = pcoords[0] - pcoords[0] * pcoords[2];
  derivs[8] = (pcoords[0] - 1.f) * (pcoords[2] - 1.f);
  derivs[9] = 0.f;

  // t-derivatives
  derivs[10] = -(pcoords[0] - 1.f) * (pcoords[1] - 1.f);
  derivs[11] = pcoords[0] * (pcoords[1] - 1.f);
  derivs[12] = -pcoords[0] * pcoords[1];
  derivs[13] = (pcoords[0] - 1.f) * pcoords[1];
  derivs[14] = 1.f;
}

static const uniform float PYRAMID_DIVERGED               = 1.e6;
static const uniform int PYRAMID_MAX_ITERATION            = 10;
static const uniform float PYRAMID_CONVERGED              = 1.e-04;
static const uniform float PYRAMID_OUTSIDE_CELL_TOLERANCE = 1.e-06;

static bool intersectAndSamplePyramid(const void *uniform userData,
                                      uniform uint64 id,
                                      uniform bool assumeInside,
                                      float &result,
                                      vec3f samplePos)
{
  const VKLUnstructuredVolume *uniform self =
      (const VKLUnstructuredVolume *uniform)userData;

  float pcoords[3] = {0.5, 0.5, 0.5};
  float derivs[15];
  float weights[5];

  // Get cell offset in index buffer
  const uniform uint64 cOffset             = getCellOffset(self, id);
  const uniform float determinantTolerance = self->iterativeTolerance[id];

  // Enter iteration loop
  bool converged = false;
  for (uniform int iteration = 0;
       !converged && (iteration < PYRAMID_MAX_ITERATION);
       iteration++) {
    unmasked
    {
      // Calculate element interpolation functions and derivatives
      pyramidInterpolationFunctions(pcoords, weights);
      pyramidInterpolationDerivs(pcoords, derivs);

      // Calculate newton functions
      vec3f fcol = make_vec3f(0.f, 0.f, 0.f);
      vec3f rcol = make_vec3f(0.f, 0.f, 0.f);
      vec3f scol = make_vec3f(0.f, 0.f, 0.f);
      vec3f tcol = make_vec3f(0.f, 0.f, 0.f);
      for (uniform int i = 0; i < 5; i++) {
        const uniform vec3f pt =
            get_vec3f(self->vertex, getVertexId(self, cOffset + i));
        fcol = fcol + pt * weights[i];
        rcol = rcol + pt * derivs[i];
        scol = scol + pt * derivs[i + 5];
        tcol = tcol + pt * derivs[i + 10];
      }

      fcol = fcol - samplePos;

      // Compute determinants and generate improvements
      const float d = det(make_LinearSpace3f(rcol, scol, tcol));
    }

    if (absf(d) < determinantTolerance) {
      return false;
    }

    const float d0 = det(make_LinearSpace3f(fcol, scol, tcol)) / d;
    const float d1 = det(make_LinearSpace3f(rcol, fcol, tcol)) / d;
    const float d2 = det(make_LinearSpace3f(rcol, scol, fcol)) / d;

    pcoords[0] = pcoords[0] - d0;
    pcoords[1] = pcoords[1] - d1;
    pcoords[2] = pcoords[2] - d2;

    // Convergence/divergence test - if neither, repeat
    if ((absf(d0) < PYRAMID_CONVERGED) & (absf(d1) < PYRAMID_CONVERGED) &
        (absf(d2) < PYRAMID_CONVERGED)) {
      converged = true;
    } else if ((absf(pcoords[0]) > PYRAMID_DIVERGED) |
               (absf(pcoords[1]) > PYRAMID_DIVERGED) |
               (absf(pcoords[2]) > PYRAMID_DIVERGED)) {
      return false;
    }
  }

  if (!converged) {
    return false;
  }

  const uniform float lowerlimit = 0.0 - PYRAMID_OUTSIDE_CELL_TOLERANCE;
  const uniform float upperlimit = 1.0 + PYRAMID_OUTSIDE_CELL_TOLERANCE;
  if (assumeInside || (pcoords[0] >= lowerlimit && pcoords[0] <= upperlimit &&
                       pcoords[1] >= lowerlimit && pcoords[1] <= upperlimit &&
                       pcoords[2] >= lowerlimit && pcoords[2] <= upperlimit)) {
    // Evaluation
    if (isValid(self->cellValue)) {
      result = get_float(self->cellValue, id);
    } else {
      float val = 0.f;
      for (uniform int i = 0; i < 5; i++) {
        val += weights[i] *
               get_float(self->vertexValue, getVertexId(self, cOffset + i));
      }
      result = val;
    }

    return true;
  }

  return false;