Esempio n. 1
0
// compute a ray-sphere intersection using the geometric solution
bool Sphere_intersect(const Sphere *e,const Vec3 *rayorig, const Vec3 *raydir, Real *t0, Real *t1)
{ Vec3 l;
  Real tca, d2, thc;
  Vec3_subs(&l,&e->center,rayorig);
  tca = Vec3_dot(&l,raydir);
  if (tca < 0) return false;
  d2 = Vec3_dot(&l,&l) - tca * tca;
  if (d2 > e->radius2) return false;
  thc = sqrt(e->radius2 - d2);
  if (t0 != NULL && t1 != NULL) {
    *t0 = tca - thc;
    *t1 = tca + thc;
  }

  return true;
}
Esempio n. 2
0
File: sphere.c Progetto: fmota/ray
// Adapted from Jacco Bikker's raytracing tutorial.
// TODO: come up with a reasonable explanation for this algorithm.
float Sphere_intersect(Sphere* self, Vec3 origin, Vec3 dir) {
    Vec3 v = Vec3_sub(origin, self->center);
    float b = -Vec3_dot(v, dir);
    float det = b*b - Vec3_dot(v, v) + self->radius*self->radius;
    if (det > 0.0f) {
        det = sqrtf(det);
        float i1 = b - det;
        float i2 = b + det;
        if (i2 > 0.0f) {
            if (i1 < 0.0f)
                return -i2; // hit from the inside
            else
                return i1; // hit from the outside
        }
    }
    return 0.0f; // miss
}
Esempio n. 3
0
/*
 * ***************************************************************************
 * Routine:  Aprx_partInert
 *
 * Purpose:  Partition the domain using inertial bisection.
 *           Partition sets of points in R^d (d=2 or d=3) by viewing them
 *           as point masses of a rigid body, and by then employing the
 *           classical mechanics ideas of inertia and Euler axes.
 *
 * Notes:    We first locate the center of mass, then change the coordinate
 *           system so that the center of mass is located at the origin.
 *           We then form the (symmetric) dxd inertia tensor, and then find
 *           the set of (real) eigenvalues and (orthogonal) eigenvectors.
 *           The eigenvectors represent the principle inertial rotation axes,
 *           and the eigenvalues represent the inertial strength in those
 *           principle directions.  The smallest inerial component along an
 *           axis represents a direction along which the rigid body is most
 *           "line-like" (assuming all the points have the same mass).
 *
 *           For our purposes, it makes sense to using the axis (eigenvector)
 *           corresponding to the smallest inertia (eigenvalue) as the line to
 *           bisect with a line (d=2) or a plane (d=3).  We know the center of
 *           mass, and once we also have this particular eigenvector, we can
 *           effectively bisect the point set into the two regions separated
 *           by the line/plane simply by taking an inner-product of the
 *           eigenvector with each point (or rather the 2- or 3-vector
 *           representing the point).  A positive inner-product represents one
 *           side of the cutting line/plane, and a negative inner-product
 *           represents the other side (a zero inner-product is right on the
 *           cutting line/plane, so we arbitrarily assign it to one region or
 *           the other).
 *
 * Author:   Michael Holst
 * ***************************************************************************
 */
VPUBLIC int Aprx_partInert(Aprx *thee, int pcolor,
    int numC, double *evec, simHelper *simH)
{
    int i, j, k, lambdaI;
    double rad, sca, lambda, normal, caxis[3];
    Mat3 I, II, V, D;

    Vnm_print(0,"Aprx_partInert: WARNING: assuming single-chart manifold.\n");
    Vnm_print(0,"Aprx_partInert: [pc=%d] partitioning:\n", pcolor);

    /* form the inertia tensors */
    Mat3_eye(I);
    Mat3_init(II, 0.);
    for (i=0; i<numC; i++) {

        /* get vector length (squared!) */
        rad = 0.;
        for (j=0; j<3; j++) {
            rad += ( simH[i].bc[j] * simH[i].bc[j] );
        }

        /* add contribution to the inertia tensor */
        for (j=0; j<3; j++) {
            for (k=0; k<3; k++) {
                II[j][k] += ( simH[i].mass *
                    (I[j][k]*rad - simH[i].bc[j]*simH[i].bc[k]) );
            }
        }
    }

    /* find the d-principle axes, and isolate the single axis we need */
    /* (the principle axis we want is the one with SMALLEST moment) */
    sca = Mat3_nrm8(II);
    Mat3_scal(II, 1./sca);
    (void)Mat3_qri(V, D, II);
    lambda  = VLARGE;
    lambdaI = -1;
    for (i=0; i<3; i++) {
        if ( VABS(D[i][i]) < lambda ) {
            lambda  = VABS(D[i][i]);
            lambdaI = i;
        }
    }
    VASSERT( lambda > 0. );
    VASSERT( lambda != VLARGE );
    VASSERT( lambdaI >= 0 );
    for (i=0; i<3; i++) {
        caxis[i] = V[i][lambdaI];
    }
    normal = Vec3_nrm2(caxis);
    VASSERT( normal > 0. );
    Vec3_scal(caxis,1./normal);

    /* decompose points based on bisecting principle axis with a line or */
    /* plane; we do this using an inner-product test with normal vec "caxis" */
    normal = 0;
    for (i=0; i<numC; i++) {
        evec[i] = Vec3_dot( simH[i].bc, caxis );
        normal += (evec[i]*evec[i]);
    }
    normal = VSQRT( normal );

    /* normalize the final result */
    for (i=0; i<numC; i++) {
        evec[i] = evec[i] / normal;
    }

    return 0;
}
Esempio n. 4
0
// This is the main trace function. It takes a ray as argument (defined by its origin
// and direction). We test if this ray intersects any of the geometry in the scene.
// If the ray intersects an object, we compute the intersection point, the normal
// at the intersection point, and shade this point using this information.
// Shading depends on the surface property (is it transparent, reflective, diffuse).
// The function returns a color for the ray. If the ray intersects an object that
// is the color of the object at the intersection point, otherwise it returns
// the background color.
void trace(Vec3 *v,const Vec3 *rayorig, const Vec3 *raydir, 
  const unsigned size, const Sphere *spheres, const int depth)
{
  //if (raydir.length() != 1) std::cerr << "Error " << raydir << std::endl;
  Real tnear = INFINITY;
  const Sphere *sphere = NULL;
  unsigned i, j;
  Vec3 surfaceColor, phit, nhit, aux;
  Real bias;
  bool inside;
  // find intersection of this ray with the sphere in the scene
  for (i = 0; i < size; ++i) {
    Real t0 = INFINITY, t1 = INFINITY;
    if (Sphere_intersect(&spheres[i], rayorig, raydir, &t0, &t1)) {
      if (t0 < 0) t0 = t1;
      if (t0 < tnear) {
        tnear = t0;
        sphere = &spheres[i];
      }
    }
  }
  // if there's no intersection return black or background color
  if (!sphere) {
    Vec3_new1(v,2);
    return;
  }
  Vec3_new0(&surfaceColor); // color of the ray/surfaceof the object intersected by the ray
  // phit = rayorig + raydir * tnear; // point of intersection
  Vec3_axpy(&phit,tnear,raydir,rayorig);
  Vec3_subs(&nhit, &phit, &sphere->center); // normal at the intersection point
  Vec3_normalize(&nhit); // normalize normal direction
  // If the normal and the view direction are not opposite to each other 
  // reverse the normal direction. That also means we are inside the sphere so set
  // the inside bool to true. Finally reverse the sign of IdotN which we want
  // positive.
  bias = 1e-4; // add some bias to the point from which we will be tracing
  inside = false;
  if (Vec3_dot(raydir,&nhit) > 0) Vec3_minus(&nhit), inside = true;
  if ((sphere->transparency > 0 || sphere->reflection > 0) && depth < MAX_RAY_DEPTH) {
    Real facingratio = -Vec3_dot(raydir,&nhit);
    // change the mix value to tweak the effect
    Real fresneleffect = mix(pow(1 - facingratio, 3), 1, 0.1); 
    // compute reflection direction (not need to normalize because all vectors
    // are already normalized)
    Vec3 refldir, reflection, refraction;
    // refldir = raydir - nhit * 2 * raydir.dot(nhit);
    Vec3_axpy(&refldir, -2 * Vec3_dot(raydir, &nhit), &nhit, raydir);
    Vec3_normalize(&refldir);
    Vec3_axpy(&aux, bias, &nhit, &phit);
    trace( &reflection, &aux, &refldir, size, spheres, depth + 1);
    Vec3_new0(&refraction);
    // if the sphere is also transparent compute refraction ray (transmission)
    if (sphere->transparency) {
      Real ior = 1.1, eta = (inside) ? ior : 1 / ior; // are we inside or outside the surface?
      Real cosi = -Vec3_dot(&nhit,raydir);
      Real k = 1 - eta * eta * (1 - cosi * cosi);
      Vec3 refrdir;
      // refrdir = raydir * eta + nhit * (eta *  cosi - sqrt(k));
      refrdir = nhit; Vec3_scale(&refrdir, eta *  cosi - sqrt(k));
      Vec3_axpy(&refrdir, eta, raydir, &refrdir);
      Vec3_normalize(&refrdir);
      Vec3_axpy(&aux, -bias, &nhit, &phit);
      trace(&refraction, &aux, &refrdir, size, spheres, depth + 1);
    }
    // the result is a mix of reflection and refraction (if the sphere is transparent)
    //surfaceColor = (reflection * fresneleffect + 
    //  refraction * (1 - fresneleffect) * sphere->transparency) * sphere->surfaceColor;
    surfaceColor = refraction;
    Vec3_scale(&surfaceColor, (1 - fresneleffect) * sphere->transparency);
    Vec3_axpy(&surfaceColor, fresneleffect, &reflection, &surfaceColor);
    Vec3_prod(&surfaceColor, &surfaceColor, &sphere->surfaceColor);
  }
  else {
    // it's a diffuse object, no need to raytrace any further
    for (i = 0; i < size; ++i) {
      if (spheres[i].emissionColor.x > 0) {
        // this is a light
        Vec3 transmission, lightDirection;
        Vec3_new1(&transmission, 1);
        Vec3_subs(&lightDirection, &spheres[i].center, &phit);
        Vec3_normalize(&lightDirection);
        for (j = 0; j < size; ++j) {
          if (i != j) {
            Real t0, t1;
            Vec3_axpy(&aux, bias, &nhit, &phit);
            if (Sphere_intersect(&spheres[j], &aux, &lightDirection, &t0, &t1)) {
// Truco para suavizar sombras
if (spheres[j].transparency == 0.0) {
              Vec3_new0(&transmission);
              break;
} else {
  Vec3_scale(&transmission, spheres[j].transparency);
  Vec3_prod(&transmission, &transmission, &spheres[j].surfaceColor);
}
            }
          }
        }
        //surfaceColor += sphere->surfaceColor * transmission * 
        //  std::max(T(0), nhit.dot(lightDirection)) * spheres[i]->emissionColor;
        Vec3_prod(&aux, &sphere->surfaceColor, &transmission);
        Vec3_prod(&aux, &aux, &spheres[i].emissionColor);
        Vec3_axpy(&surfaceColor, max(0.0, Vec3_dot(&nhit, &lightDirection)), &aux, &surfaceColor);
      }
    }
  }

  Vec3_add(v, &surfaceColor, &sphere->emissionColor);
}