RNRgb R3DirectionalLight::
SpecularReflection(const R3Brdf& brdf, const R3Point& eye, 
    const R3Point& point, const R3Vector& normal) const
{
    // Check if light is active
    if (!IsActive()) return RNblack_rgb;

    // Get material properties
    const RNRgb& Sc = brdf.Specular();
    RNScalar s = brdf.Shininess();

    // Get light properties
    const RNRgb& Ic = Color();
    RNScalar I = Intensity();
    R3Vector L = -(Direction());

    // Compute geometric stuff
    RNScalar NL = normal.Dot(L);
    if (RNIsNegativeOrZero(NL)) return RNblack_rgb;
    R3Vector R = (2.0 * NL) * normal - L;
    R3Vector V = eye - point;
    V.Normalize();
    RNScalar VR = V.Dot(R);
    if (RNIsNegativeOrZero(VR)) return RNblack_rgb;

    // Return specular component of reflection
    return (I * pow(VR,s)) * Sc * Ic;
}
RNRgb R3PointLight::
Reflection(const R3Brdf& brdf, const R3Point& eye, 
    const R3Point& point, const R3Vector& normal) const
{
    // Check if light is active
    if (!IsActive()) return RNblack_rgb;

    // Get material properties
    const RNRgb& Dc = brdf.Diffuse();
    const RNRgb& Sc = brdf.Specular();
    RNScalar s = brdf.Shininess();

    // Get light properties
    RNScalar I = IntensityAtPoint(point);
    R3Vector L = DirectionFromPoint(point);
    const RNRgb& Ic = Color();

    // Compute geometric stuff
    RNScalar NL = normal.Dot(L);
    if (RNIsNegativeOrZero(NL)) return RNblack_rgb;
    R3Vector R = (2.0 * NL) * normal - L;
    R3Vector V = eye - point;
    V.Normalize();
    RNScalar VR = V.Dot(R);

    // Compute diffuse reflection
    RNRgb rgb = (I * NL) * Dc * Ic;

    // Compute specular reflection
    if (RNIsPositive(VR)) rgb += (I * pow(VR,s)) * Sc * Ic;

    // Return total reflection
    return rgb;
}
// compute intersection between a sphere and a ray
R3Intersection ComputeIntersection(R3Sphere *sphere, R3Ray &ray)
{
  R3Intersection i;
  bool in_front_of_center = false;
  bool internal = false;

  R3Vector l = sphere->Center() - ray.Start();
  double tca = l.Dot(ray.Vector());
  if (tca < 0) // case where ray originates within sphere and points away from its center
  {
    tca = -tca;
    in_front_of_center = true;
    internal = true;
  }
  double d2 = l.Dot(l) - tca * tca;
  double r2 = sphere->Radius() * sphere->Radius();
  if (d2 > r2) // case where ray misses sphere entirely
  {
    i.hit = false;
    return i;
  }
  double thc = sqrt(r2 - d2);
  double t;
  if (!in_front_of_center)
  {
    t = tca - thc;
    if (t < 0)
    {
      t = tca + thc;
      internal = true;
    }
  }
  else
  {
    t = thc - tca;
  }

  if (t < 0)
  {
    i.hit = false;
    return i;
  }

  R3Point p = ray.Point(t);
  R3Vector n = p - sphere->Center();
  n.Normalize();
  if (internal)
    n = -n;

  // populate intersection data
  i.hit = true;
  i.normal = n;
  i.position = p;
  i.t = t;

  return i;
}
// compute the ray reflected from the incoming ray r at intersection i
R3Ray GetReflectedRay(R3Intersection i, R3Ray r)
{
  // add offset to point to ensure the same intersection is not found again due to floating point error
  R3Point offset = i.position + i.normal * EPSILON;
  R3Vector v = -r.Vector();
  return R3Ray(offset, 2 * v.Dot(i.normal) * i.normal - v);
}
Exemple #5
0
double R3Distance(const R3Line& line1, const R3Line& line2)
{
  // Return distance from line to line (Riddle p. 905)
  R3Vector v = line1.Vector();
  v.Cross(line2.Vector());
  return v.Dot(line1.Point() - line2.Point());
}
Exemple #6
0
double R3Distance(const R3Point& point, const R3Ray& ray)
{
  // Check if start point is closest
  R3Vector v = point - ray.Start();
  double dir = v.Dot(ray.Vector());
  if (dir < 0) return v.Length();

  // Return distance from point to ray line
  return R3Distance(point, ray.Line());
}
// compute ray refracted from incoming ray r using Snell's Law
// NOTE: I assume that refracting objects will always be non-intersecting and that all intersections passed into this function
// will be from empty space with an IOR of 1 to the interior of a shape
R3Ray GetRefractedRay(R3Intersection i, R3Ray r, double ior, R3Scene *scene)
{
  // this time push the point inside the object
  R3Point internal_offset = i.position - i.normal * EPSILON;

  // calculate the ray that will be cast through the object
  R3Vector v = -r.Vector();
  double cos_vn = v.Dot(i.normal);
  R3Vector internal_vec = i.normal * (cos_vn / ior - sqrt(1 - (1 - cos_vn * cos_vn) / (ior * ior))) - v / ior;
  R3Ray trans_ray(internal_offset, internal_vec);

  // cast this ray and determine it's exit point from the refracting object
  R3Intersection exit_i = ComputeIntersection(scene, scene->Root(), trans_ray, numeric_limits<double>::infinity());
  assert (exit_i.hit);

  // calculate the refracted exit ray and 
  R3Point external_offset = exit_i.position - exit_i.normal * EPSILON;
  v = -trans_ray.Vector();
  cos_vn = v.Dot(exit_i.normal);
  R3Vector external_vec = exit_i.normal * (cos_vn * ior - sqrt(1 - (1 - cos_vn * cos_vn) * (ior * ior))) - v * ior;
  return R3Ray(external_offset, external_vec);
}
Exemple #8
0
int IntersectSphere(R3Sphere *s, R3Ray r, R3Point *position, R3Vector *normal, double *t) {
	R3Vector l = s->Center() - r.Start();
	double tca = l.Dot(r.Vector());
	if(tca < 0) return 0;

	double d2 = l.Dot(l) - tca*tca;
	if(d2 > s->Radius() * s->Radius()) return 0;

	double thc = sqrt(s->Radius() * s->Radius() - d2);
	*t = thc > 0 ? tca - thc : tca + thc;
	if(*t < 0) {
		*t = thc > 0 ? tca + thc : tca - thc;
	}
	if(*t < 0) {
		return 0;
	}
	
	*position = r.Start() + *t * r.Vector();
	*normal = *position - s->Center();
	normal->Normalize();

	return 1;
}
Exemple #9
0
void R3Matrix::Rotate(const R3Vector& from, const R3Vector& to)
{
    // rotate matrix that takes direction of vector "from" -> "to"
    // This is a quickie hack -- there's got to be a better way
    double d1 = from.Length();
    if (d1 == 0) return;
    double d2 = to.Length();
    if (d2 == 0) return;
    double cosine = from.Dot(to) / (d1 * d2);
    double radians = acos(cosine);
    R3Vector axis = from % to;
    axis.Normalize();
    Rotate(axis, radians);
}
Exemple #10
0
double R3Distance(const R3Ray& ray, const R3Segment& segment)
{
  // There's got to be a better way ???

  // Get vectors in more convenient form
  const R3Vector v1 = ray.Vector();
  const R3Vector v2 = segment.Vector();

  // Compute useful intermediate values
  const double v1v1 = 1.0;  // v1.Dot(v1);
  const double v2v2 = 1.0;  // v2.Dot(v2);
  double v1v2 = v1.Dot(v2);
  double denom = v1v2*v1v2 - v1v1*v2v2;

  // Check if ray and segment are parallel
  if (denom == 0) {
    // Not right ???
    // Look at directions of vectors, then check relative starts and stops
    return R3Distance(segment.Line(), ray.Line());
  }
  else {
    // Find closest points
    const R3Vector p1 = ray.Start().Vector();
    const R3Vector p2 = segment.Start().Vector();
    double p1v1 = v1.Dot(p1);
    double p2v2 = v2.Dot(p2);
    double p1v2 = v2.Dot(p1);
    double p2v1 = v1.Dot(p2);
    double ray_t = (v1v2*p2v2 + v2v2*p1v1 - v1v2*p1v2 - v2v2*p2v1) / denom;
    double segment_t = (v1v2*p1v1 + v1v1*p2v2 - v1v2*p2v1 - v1v1*p1v2) / denom;
    R3Point ray_point = (ray_t <= 0.0) ? ray.Start() : ray.Point(ray_t);
    R3Point segment_point = (segment_t <= 0.0) ? segment.Start() : 
      (segment_t >= segment.Length()) ? segment.End() : segment.Ray().Point(segment_t);
    double distance = R3Distance(ray_point, segment_point);
    return distance;
  }
}
// Compute the luminance for a light at a specific point
R3Rgb ComputeLuminance(R3Light *light, R3Point &point)
{
  R3Rgb il(0, 0, 0, 1);

  switch (light->type)
  {
    // quadratic attenuation factor
    case R3_POINT_LIGHT:
    {
      double d = (light->position - point).Length();
      double att = light->constant_attenuation + light->linear_attenuation * d + light->quadratic_attenuation * d * d;
      il = light->color / att;
      break;
    }
    // constant luminance
    case R3_DIRECTIONAL_LIGHT:
    {
      il = light->color;
      break;
    }
    // quadratic attenuation with directional falloff
    case R3_SPOT_LIGHT:
    {
      R3Vector l = (point - light->position);
      l.Normalize();
      double cost = l.Dot(light->direction);
      if (acos(cost) <= light->angle_cutoff)
      {
        double d = (light->position - point).Length();
        double att = light->constant_attenuation + light->linear_attenuation * d + light->quadratic_attenuation * d * d;
        il = light->color * pow(cost, light->angle_attenuation) / att;
      }
      break;
    }
    // not implemented
    case R3_AREA_LIGHT:
      break;
    case R3_NUM_LIGHT_TYPES:
      break;
  }

  return il;
}
Exemple #12
0
RNRgb R3PointLight::
DiffuseReflection(const R3Brdf& brdf, 
    const R3Point& point, const R3Vector& normal) const
{
    // Check if light is active
    if (!IsActive()) return RNblack_rgb;

    // Get material properties
    const RNRgb& Dc = brdf.Diffuse();

    // Get light properties
    const RNRgb& Ic = Color();
    RNScalar I = IntensityAtPoint(point);
    R3Vector L = DirectionFromPoint(point);

    // Compute geometric stuff
    RNScalar NL = normal.Dot(L);
    if (RNIsNegativeOrZero(NL)) return RNblack_rgb;

    // Return diffuse component of reflection
    return (I * NL) * Dc * Ic;
}
Exemple #13
0
RNBoolean R3Perpendicular(const R3Vector& vector1, const R3Vector& vector2)
{
    // Normalized vectors ???
    // Return whether vector1 and vector2 are perpendicular
    return RNIsZero(vector1.Dot(vector2));
}
// compute intersection between a triangle face and a ray
R3Intersection ComputeIntersection(R3MeshFace *tri, R3Ray &ray, double min_t)
{
  assert (tri->vertices.size() == 3);

  R3Intersection i;

  R3Point t1 = tri->vertices[0]->position;
  R3Point t2 = tri->vertices[1]->position;
  R3Point t3 = tri->vertices[2]->position;

  // intersect ray with triangle's plane
  R3Plane plane = tri->plane;
  double t = -(ray.Start().Vector().Dot(plane.Normal()) + plane.D()) 
    / (ray.Vector().Dot(plane.Normal()));

  // early return if not closer than minimum intersection for the mesh
  if (t > min_t || t < 0)
  {
    i.hit = false;
    return i;
  }


  // check if intersection is within triangle using barycentric coordinate method
  R3Point p = ray.Point(t);

  R3Vector v;

  v = t2 - t1;
  v.Cross(t3 - t1);
  double area = v.Length() / 2;

  v = t2 - t1;
  v.Cross(p - t1);
  if (v.Dot(plane.Normal()) < 0)
  {
    i.hit = false;
    return i;
  }
  double a = v.Length() / (2 * area);

  v = p - t1;
  v.Cross(t3 - t1);
  if (v.Dot(plane.Normal()) < 0)
  {
    i.hit = false;
    return i;
  }
  double b = v.Length() / (2 * area);

  if (a <= 1 && a >= 0 && b <= 1 && b >= 0 && a + b <= 1)
  {
    i.hit = true;
    if (ray.Vector().Dot(plane.Normal()) < 0)
    {
      i.normal = plane.Normal();
    }
    else
    {
      i.normal = -plane.Normal();
    }
    i.position = p;
    i.t = t;
    return i;
  } 
  else
  {
    i.hit = false;
    return i;
  }
}
// Compute the radiance emitted back along a given ray from a given intersection
R3Rgb ComputeRadiance(R3Scene *scene, R3Ray &ray, R3Intersection &intersection, int depth, int max_depth, int distrib)
{
  R3Rgb il(0, 0, 0, 1);
  R3Material *mat = intersection.node->material;
  // add a small epsilon normal to the intersection point so light and secondary rays don't intersect with the same surface
  R3Point offset_intersection_pos = intersection.position + intersection.normal * EPSILON;
  // v = a unit vector pointing from the intersection to the ray origin
  R3Vector v = -ray.Vector();

  // if we are not using distributed ray tracing...
  if (distrib == 0)
  {
    // include lighting from all scene lights
    for (int i = 0; i < scene->NLights(); i++)
    {
      R3Light *light = scene->Light(i);

      // l = a unit vector pointing from the intersection to a light
      // d = the distance between the intersection and a light
      R3Vector l;
      double d;
      if (light->type == R3_DIRECTIONAL_LIGHT)
      {
        l = -light->direction;
        d = numeric_limits<double>::infinity();
      }
      else
      {
        l = (light->position - intersection.position);
        l.Normalize();
        d = (light->position - intersection.position).Length();
      }

      // construct a ray from the intersection toward the light
      R3Ray light_ray(offset_intersection_pos, l);

      // compute a shadow intersection and if one exists (that is between the intersection and the light), ignore the light
      R3Intersection shadow_intersection = ComputeIntersection(scene, scene->Root(), light_ray, d);
      if (shadow_intersection.hit && shadow_intersection.t < d)
        continue;

      // compute the luminance of the light at the intersection position
      R3Rgb light_il = ComputeLuminance(light, intersection.position);

      // evaluate the Phong BRDF equations for diffuse and specular reflection
      double cos_nl = l.Dot(intersection.normal);

      // r = l reflected across the intersection normal
      R3Vector r = 2 * cos_nl * intersection.normal - l; 
      double cos_vr = v.Dot(r);
      // if the light is shining on the front of the surface, include diffuse lighting
      // if the light is also less than 90 degrees from the camera vector, include specular lighting
      if (cos_nl > 0)
      {
        il += light_il * mat->kd * cos_nl;
        if (cos_vr > 0)
          il += light_il * mat->ks * pow(cos_vr, mat->shininess);
      }
    }
  }
  else // if we ARE using distributed...
  {
    if (depth < max_depth)
    {
      int nrays = 0;
      R3Rgb dist_il(0, 0, 0, 1);
      while (nrays < distrib)
      {
        // randomly sample outgoing directions using random variables with normal distributions
        double u1 = (double)rand()/RAND_MAX;
        double u2 = (double)rand()/RAND_MAX;
        double u3 = (double)rand()/RAND_MAX;
        double u4 = (double)rand()/RAND_MAX;

        double s1 = sqrt(-2 * log(u1));
        double rx = s1 * cos(2 * 3.14159 * u2);
        double ry = s1 * sin(2 * 3.14159 * u2);
        double s2 = sqrt(-2 * log(u3));
        double rz = s2 * cos(2 * 3.14159 * u4);

        R3Vector l(rx, ry, rz);
        l.Normalize();

        // check if vector is in the right hemisphere
        if (l.Dot(intersection.normal) < 0)
          continue;

        // generate a random ray and recursively compute the radiance it contributes
        R3Ray rray(offset_intersection_pos, l);
        R3Rgb rgb = ComputeRadiance(scene, rray, depth + 1, max_depth, distrib);
        
        // evaluate the Phong BRDF equations for diffuse and specular reflection
        double cos_nl = l.Dot(intersection.normal);

        // r = l reflected across the intersection normal
        R3Vector r = 2 * cos_nl * intersection.normal - l; 
        double cos_vr = v.Dot(r);
        // if the light is shining on the front of the surface, include diffuse lighting
        // if the light is also less than 90 degrees from the camera vector, include specular lighting
        if (cos_nl > 0)
        {
          dist_il += rgb * mat->kd * cos_nl;
          if (cos_vr > 0)
            dist_il += rgb * mat->ks * pow(cos_vr, mat->shininess);
        }

        nrays++;
      }

      il += dist_il / nrays;
    }
  }

  // if the material has a specular component and the maximum depth hasn't been reached, reflect the camera ray from the
  // intersection surface and recusively evaluate its radiance
  if (!mat->ks.IsBlack() && depth < max_depth)
  {
    R3Ray spec_ray = GetReflectedRay(intersection, ray);
    R3Rgb spec = ComputeRadiance(scene, spec_ray, depth + 1, max_depth, distrib);
    il += spec * mat->ks;
  }

  // add refraction component for both distributed and non-distributed techniques
  if (!mat->kt.IsBlack() && depth < max_depth)
  {
    R3Ray trans_ray = GetRefractedRay(intersection, ray, mat->indexofrefraction, scene);
    R3Rgb trans = ComputeRadiance(scene, trans_ray, depth + 1, max_depth, distrib);
    il += trans * mat->kt;
  }

  // add ambient and emission components
  il += mat->emission;
  il += mat->ka * scene->ambient;

  return il;
}
Exemple #16
0
double R3SquaredDistance(const R3Point& point1, const R3Point& point2)
{
  // Return length of vector between points
  R3Vector v = point1 - point2;
  return v.Dot(v);
}