예제 #1
0
bool Quadric::intersect(const Point3D &eye, const Point3D &_ray, HitReporter &hr) const
{
  Polynomial<2> x, y, z;
  const Vector3D ray = _ray - eye;
  x[0] = eye[0];
  x[1] = ray[0];
  y[0] = eye[1];
  y[1] = ray[1];
  z[0] = eye[2];
  z[1] = ray[2];

  const Polynomial<2> eqn = A * x * x + B * x * y + C * x * z
    + D * y * y + E * y * z + F * z * z + G * x + H * y + J * z + K;

  double ts[2];
  auto nhits = eqn.solve(ts);

  if(nhits > 0)
  {
    const Polynomial<2> ddx = 2 * A * x + B * y + C * z + G,
			ddy = 2 * D * y + B * x + E * z + H,
			ddz = 2 * F * z + C * x + E * y + J;

    for(int i = 0; i < nhits; i++)
    {
      // Figure out the normal.
      const double t = ts[i];
      const Point3D pt = eye + t * ray;
      if(!predicate(pt))
	continue;

      Vector3D normal(ddx.eval(t), ddy.eval(t), ddz.eval(t));

      // Figure out the uv.
      Point2D uv;
      Vector3D u, v;
      get_uv(pt, normal, uv, u, v);

      if(!hr.report(ts[i], normal, uv, u, v))
	return false;
    }
  }

  return true;
}
예제 #2
0
// This is basically the same as Quadric::intersect, but Quadric::intersect is
// too general to be fast, so we're reimplementing it here.
bool Sphere::intersect(const Point3D &eye, const Point3D &dst, HitReporter &hr) const
{
  Polynomial<2> x, y, z;
  const Vector3D ray = dst - eye;
  x[0] = eye[0];
  x[1] = ray[0];
  y[0] = eye[1];
  y[1] = ray[1];
  z[0] = eye[2];
  z[1] = ray[2];
  
  const Polynomial<2> eqn = x * x + y * y + z * z + (-1);

  double ts[2];
  auto nhits = eqn.solve(ts);

  if(nhits > 0)
  {
    for(int i = 0; i < nhits; i++)
    {
      const double t = ts[i];
      const Point3D pt = eye + t * ray;

      // The normal is just the intersection point in the sphere's coordinate
      // system. We can avoid the normalize since this is a unit sphere.
      Vector3D normal(pt - Point3D());

      // Figure out the uv.
      const double theta = atan2(-pt[2], pt[0]);
      const double y = pt[1];
      const Point2D uv(0.5 + theta / 2 / M_PI, 0.5 + y * 0.5);
      Vector3D u = Vector3D(pt[1], 0, -pt[0]);
      u.normalize();
      const Vector3D v = normal.cross(u);

      if(!hr.report(ts[i], normal, uv, u, v))
	return false;
    }
  }

  return true;
}
예제 #3
0
bool Cylinder::intersect(const Point3D &eye, const Point3D &dst, HitReporter &hr) const
{
  // Part 1: test for intersection with the non-planar surface using the
  // cylinder equation.
  Polynomial<2> x, y, z;
  const Vector3D ray = dst - eye;
  x[0] = eye[0];
  x[1] = ray[0];
  y[0] = eye[1];
  y[1] = ray[1];
  z[0] = eye[2];
  z[1] = ray[2];
  
  const Polynomial<2> eqn = x * x + y * y + (-1);

  double ts[2];
  auto nhits = eqn.solve(ts);

  if(nhits > 0)
  {
    for(int i = 0; i < nhits; i++)
    {
      const double t = ts[i];
      const Point3D pt = eye + t * ray;

      if(!predicate(pt))
        continue;

      const Vector3D normal(pt - Point3D(0, 0, pt[2]));

      // Figure out the uv.
      Vector3D u, v;
      Point2D uv;
      get_uv(pt, normal, uv, u, v);

      if(!hr.report(ts[i], normal, uv, u, v))
	return false;
    }
  }

  // Next, test intersection with the two planar circle surfaces.
  const int circles[] = {AAFACE_PZ, AAFACE_NZ};
  const double offsets[] = {1., -1.};

  for(int i = 0; i < NUMELMS(circles); i++)
  {
    const int face = circles[i];
    const int axis = face / 2;
    const double offset = offsets[i];
    const double t = axis_aligned_plane_intersect(eye, ray, axis, offset);
    if(t < numeric_limits<double>::max())
    {
      const Point3D p = eye + t * ray;
      if(axis_aligned_circle_contains(p, face, 1.))
      {
	Vector3D normal;
	normal[axis] = offset;
	const double _u = 0.25 * ((face == AAFACE_PZ ? 1 : 3) + p[0]);
	const double _v = 0.25 * (3 + p[1]);
	Point2D uv(_u, _v);
	Vector3D u(1, 0, 0);
	Vector3D v(0, 1, 0);
	if(!hr.report(t, normal, uv, u, v))
	  return false;
      }
    }
  }

  return true;
}
예제 #4
0
RootFinding::Roots RootFinding::solve(const Polynomial &p,const Polynomial &q)
{
	return RootFinding::Roots(p.solve(q));
}