Пример #1
0
boost::optional<Intersection> Triangle::intersect(Ray ray) {
	Eigen::Vector3f s1 = ray.dir.cross(d2);
	const float div = s1.dot(d1);
	if(div <= 0) {  // parallel or back
		return boost::optional<Intersection>();
	}

	const float div_inv = 1 / div;
		
	Eigen::Vector3f s  = ray.org - p0;
	const float a = s.dot(s1) * div_inv;
	if(a < 0 || a > 1) {
		return boost::optional<Intersection>();
	}
				
	Eigen::Vector3f s2 = s.cross(d1);
	const float b = ray.dir.dot(s2) * div_inv;
		
	if(b < 0 || a + b > 1) {
		return boost::optional<Intersection>();
	}

	const float t = d2.dot(s2) * div_inv;
	if(t < 0) {
		return boost::optional<Intersection>();
	}

	return boost::optional<Intersection>(Intersection(
		t,
		ray.at(t),
		normal,
		(1 - a - b) * uv0 + a * uv1 + b * uv2,
		(1 - a - b) * ir0 + a * ir1 + b * ir2,
		attribute));
}
Пример #2
0
bool Triangle::intersect(const Ray &ray, Intersection &intersection) const
{
	const double NdotRayDir = N.dot(ray.direction);

	if (NdotRayDir < 0.000001 && NdotRayDir > -0.000001) // no hit
		return false;

	intersection.t = (D - N.dot(ray.origin)) / (NdotRayDir);
	const Vector i = ray.at(intersection.t); // intersection point with plane

	// for an edge p1<->p2, we check to see if the cross product of that edge
	// vector (p2-p1) and the vector from p1 to the intersection point points
	// in the same direction as the normal vector
	if ((p2-p1).cross(i - p1).dot(N) >= 0 &&
		(p3-p2).cross(i - p2).dot(N) >= 0 &&
		(p1-p3).cross(i - p3).dot(N) >= 0)
	{
		// i is within the triangle
		intersection.primitive = const_cast<Triangle*>(this);

		if (NdotRayDir > 0)
			intersection.normal = -N;
		else
			intersection.normal = N;

		return true;
	}

	return false;
}
Пример #3
0
 void fillConicalDiffGeom(Diff_Geom &dg, const Ray &r, float t, bool in) const{
     Vector3D pt_inter = r.at(t);
     Vector3D dNdx, dNdy;
     Vector3D normal=computenormal(pt_inter);
     Vector3D dPpdx, dPpdy;
     r.propagateDifferentials(t, normal, dPpdx, dPpdy);
     computenormalDifferential(pt_inter, dPpdx, dPpdy, dNdx, dNdy);
     Vector3D dTdx, dTdy;
     float u, v;
     computeConicalTexInfo(pt_inter, normal, dPpdx, dPpdy, u, v, dTdx, dTdy);
     dg = Diff_Geom(pt_inter, normal, dNdx, dNdy, t, dPpdx, dPpdy, r.dDdx(), r.dDdy(), u, v, dTdx, dTdy, in);
 }
Пример #4
0
	void EntitiesEditor::computeCursor(int2 start, int2 end, bool floor_mode) {
		float2 height_off = worldToScreen(int3(0, 0, 0));

		start += m_view.pos();
		  end += m_view.pos();

		Ray ray = screenRay(start);

		Flags::Type flags = Flags::all;
		if(floor_mode)
			flags = flags & ~(Flags::wall_tile | Flags::object_tile);

		auto isect = m_tile_map.trace(ray, -1, flags | Flags::visible);
		float3 pos = isect.first == -1? (float3)asXZ(screenToWorld(start)) : ray.at(isect.second);

		m_cursor_pos = (float3)round(pos);
		m_selection = IRect(min(start, end), max(start, end));
	}
Пример #5
0
Color Scene::trace(const Ray &ray)
{
    // Find hit object and distance
    Hit min_hit(std::numeric_limits<double>::infinity(),Vector());
    Object *obj = NULL;
    for (unsigned int i = 0; i < objects.size(); ++i) {
        Hit hit(objects[i]->intersect(ray));
        if (hit.t<min_hit.t) {
            min_hit = hit;
            obj = objects[i];
        }
    }

    // No hit? Return background color.
    if (!obj) return Color(0.0, 0.0, 0.0);

    Material *material = obj->material;            //the hit objects material
    Point hit = ray.at(min_hit.t);                 //the hit point
    Vector N = min_hit.N;                          //the normal at hit point
    Vector V = -ray.D;                             //the view vector


    /****************************************************
    * This is where you should insert the color
    * calculation (Phong model).
    *
    * Given: material, hit, N, V, lights[]
    * Sought: color
    *
    * Hints: (see triple.h)
    *        Triple.dot(Vector) dot product
    *        Vector+Vector      vector sum
    *        Vector-Vector      vector difference
    *        Point-Point        yields vector
    *        Vector.normalize() normalizes vector, returns length
    *        double*Color        scales each color component (r,g,b)
    *        Color*Color        dito
    *        pow(a,b)           a to the power of b
    ****************************************************/

    Color color = material->color;                  // place holder

    return color;
}
Пример #6
0
bool Mesh::faceIntersection(
    const Ray& ray, HitRecord* hitRecord, const Mesh::Face& face) {
  // Get a point on the plane
  Vector3D norm;
  double t;
  {
    const auto& p0 = m_verts[face[0]];
    const auto& p1 = m_verts[face[1]];
    const auto& p2 = m_verts[face[face.size()-1]];
    norm = (p1 - p0).cross(p2 - p0);
    auto rayNorm = ray.dir.dot(norm);

    // Parallel
    if (isZero(rayNorm)) return false;

    t = (p0 - ray.start).dot(norm) / rayNorm;
    // No intersection
    if (t < 0 || isZero(t)) {
      return false;
    }
  }

  // Intersection point
  auto planePt = ray.at(t);
  // Now check if planePt is "left" of everything
  for (size_t i = 0; i < face.size(); ++i) {
    // Go over points in order
    const auto& p1 = m_verts[face[i]];
    const auto& p2 = m_verts[face[(i + 1) % face.size()]];
    // from p1 to p2
    const auto side = p2 - p1;
    // cross from p1 to plane pt and dot against normal
    auto k = norm.dot(side.cross(planePt - p1));
    if (!isZero(k) && k < 0) {
      // Zero means on the side; negative means opposite dir from norm
      return false;
    }
  }

  // Update if this is a better t value
  return hitRecord->update(norm, planePt, t);
}
Пример #7
0
bool Mesh::intersects(const Ray& ray,
                HitRecord* hitRecord,
                const Matrix4x4& inverseTransform) {
  // New ray
  const auto a = inverseTransform * ray.start;
  const auto b = inverseTransform * ray.other;
  const Ray newRay(a, b);

  HitRecord boundingRecord;
  HitRecord* boundingPtr;
  if (BOUNDING_BOX_RENDER) {
    boundingPtr = hitRecord;
  }
  else {
    boundingPtr = &boundingRecord;
  }
  // First, check for intersection against our bounding box
  if (!boundingCube.intersects(ray, boundingPtr, boundingCubeInverse * inverseTransform)) {
    return false;
  }
  else if (BOUNDING_BOX_RENDER) {
    return true;
  }

  // Note: This is not implemented correctly, since faceIntersection
  // checks if the face was intersected *and* was a better t value
  bool hit = false;
  // For each polygon, check for polygon intersection lol...
  for (const auto& face : m_faces) {
    if (faceIntersection(newRay, hitRecord, face)) {
      // haha, use real ray
      hitRecord->point = ray.at(hitRecord->t);
      hitRecord->norm = inverseTransform.transpose() * hitRecord->norm;
      hitRecord->norm.normalize();
      hit = true;
    }

  }
  return hit;
}
Пример #8
0
bool Cylinder::intersects(const Ray& ray,
                          HitRecord* hitRecord,
                          const Matrix4x4& inverseTransform) const {
  // New ray
  const auto p1 = inverseTransform * ray.start;
  const auto p2 = inverseTransform * ray.other;
  const auto dir = p2 - p1;

  double t = solveIntersection(p1, dir);
  if (t < 0) return false;

  auto localPoint = p1 + t * dir;
  Vector3D localNorm(0, 0, 0);
  if (isZero(localPoint[2] + 1)) {
    localNorm = Vector3D(0, 0, -1);
  }
  else if (isZero(localPoint[2] - 1)) {
    localNorm = Vector3D(0, 0, 1);
  }
  else {
    // Not on one of the tops: Just like a circle
    localNorm = Vector3D(localPoint[0], localPoint[1], 0);
  }

  // t is unchanged by this
  // Remember to use the *original* intersection point
  auto point = ray.at(t);

  // To get the appropriate normal vector, we must also transpose
  // the inverse transform
  auto norm = inverseTransform.transpose() * localNorm;
  norm.normalize();

  // We will return whether or not this intersection was
  // better than whatever was already stored there
  return hitRecord->update(norm, point, t);
}
Пример #9
0
bool AABB::intersectsRay( const Ray& ray ) const
{
  // if the start point OR the end point is in the AABB, then it's a hit.
  // For the BOOLEAN check where you don't want the hit point, we use an OR (vs an AND)
  bool rayStartInside = containsPoint( ray.start ) ;
  if( rayStartInside || containsPoint( ray.end ) )
    return true ; // I don't have to get you the exact point.
  
  Vector3f t ;

  if( rayStartInside )
    for( int i = 0 ; i < 3 ; i++ )
      if( ray.dir.elts[i] > 0 )
        t.elts[i] = ( max.elts[i] - ray.start.elts[i] ) / ray.dir.elts[i] ;
      else
        t.elts[i] = ( min.elts[i] - ray.start.elts[i] ) / ray.dir.elts[i] ;
  else
    for( int i = 0 ; i < 3 ; i++ )
      if( ray.dir.elts[i] > 0 )
        t.elts[i] = ( min.elts[i] - ray.start.elts[i] ) / ray.dir.elts[i] ;
      else
        t.elts[i] = ( max.elts[i] - ray.start.elts[i] ) / ray.dir.elts[i] ;
  
  int tIndex ;
  if( rayStartInside )  tIndex = t.minIndex() ;
  else  tIndex = t.maxIndex() ;
  if( isBetweenOrdered( t.elts[tIndex], 0, ray.len ) )
  {
    Vector3f pt = ray.at( t.elts[tIndex] ) ;
    int o1 = OTHERAXIS1(tIndex) ;
    int o2 = OTHERAXIS2(tIndex) ;
    return isBetweenOrdered( pt.elts[o1], min.elts[o1], max.elts[o1] ) &&
           isBetweenOrdered( pt.elts[o2], min.elts[o2], max.elts[o2] ) ;
  }
  
  return false ;
}
Пример #10
0
bool Triangle::doesIntersect (const Ray &ray) const
{
	const double NdotRayDir = N.dot(ray.direction);

	if (NdotRayDir < 0.000001 && NdotRayDir > -0.000001) // no hit
		return false;

	const double t = (D - N.dot(ray.origin)) / (NdotRayDir);
	const Vector i = ray.at(t); // intersection point with plane

	if (t < 0)
		return false;

	if ((p2-p1).cross(i - p1).dot(N) >= 0 &&
		(p3-p2).cross(i - p2).dot(N) >= 0 &&
		(p1-p3).cross(i - p3).dot(N) >= 0)
	{
		// i is within the triangle

		return true;
	}

	return false;
}
Пример #11
0
bool Torus::intersects(const Ray& ray,
                       HitRecord* hitRecord,
                       const Matrix4x4& inverseTransform) const {
  // New ray
  const auto p1 = inverseTransform * ray.start;
  const auto p2 = inverseTransform * ray.other;
  Ray localRay(p1, p2);
  double t = solveIntersection(localRay);
  if (!isValid(t)) return false;

  Point3D localPoint = localRay.at(t);
  Point3D globalPoint = ray.at(t);

  // Get the norm. See: http://www.emeyex.com/site/projects/raytorus.pdf
  double k = Vector3D(localPoint).length2() - tubeRadius*tubeRadius - 1;
  Vector3D localNorm(
    4 * localPoint[0] * k,
    4 * localPoint[1] * k,
    4 * localPoint[2] * k + 8 * localPoint[2]
  );
  auto norm = inverseTransform.transpose() * localNorm;
  norm.normalize();
  return hitRecord->update(norm, globalPoint, t);
}
Пример #12
0
std::set<const Model*> UniformGrid::getModels(const Ray& ray) const {
  std::set<const Model*> models;

  Point3D nextT(0, 0, 0);

  // The point *within* the grid where the ray first intersected it
  Point3D rayStartPoint(0, 0, 0);

  if (!inGrid(ray.start)) {
    const auto& sp = startPoint;
    // Not in the grid: We will use a cube the sz of whole grid to find
    // the point of entry into the grid
    auto gridCubeInverse = (translationMatrix(sp[0], sp[0], sp[0]) *
                           gridSizeScaleMatrix).invert();
    HitRecord hr;
    if (!utilityCube.intersects(ray, &hr, gridCubeInverse)) {
      // Does not intersect the grid even
      return models;
    }
    nextT[0] = hr.t;
    nextT[1] = hr.t;
    nextT[2] = hr.t;
    rayStartPoint = ray.at(hr.t);
  }
  else {
    rayStartPoint = ray.start;
  }

  // Place in the grid we are currently stepping through
  CellCoord gridCoord = coordAt(rayStartPoint);

  Vector3D dir(
      std::abs(ray.dir[0]), std::abs(ray.dir[1]), std::abs(ray.dir[2]));

  // These values are in units of t: how far we must go to travel a whole cell
  Vector3D dt(
    isZero(dir[0]) ? 0 : cellSize / dir[0],
    isZero(dir[1]) ? 0 : cellSize / dir[1],
    isZero(dir[2]) ? 0 : cellSize / dir[2]
  );
  {
    // The bottom left corner of the cell we are starting in
    Point3D gsp = pointAt(gridCoord); // "Grid start point"

    // Determine how far, in units of t, we have to go in any direction
    // to reach the next cell
    // If we are going "forwards" in a coordinate then we need to travel to
    // gsp + cellSize. If we are going "backwards" in a coordinate then we need
    // to travel to only gsp.
    for (int i = 0; i < 3; ++i) {
      if (isZero(dir[i])) {
        nextT[i] = -1;
        continue;
      }
      if (ray.dir[i] < 0) {
        nextT[i] += (rayStartPoint[i] - gsp[i]) / dir[i];
      }
      else {
        nextT[i] += (gsp[i] + cellSize - rayStartPoint[i]) / dir[i];
      }
    }
  }

  // Which direction in the grid to move when we hit a "next" value
  CellCoord incs(
    (ray.dir[0] > 0) ? 1 : -1,
    (ray.dir[1] > 0) ? 1 : -1,
    (ray.dir[2] > 0) ? 1 : -1
  );

  // Check if a coord is still valid
  auto coordOk = [&] (int coord) -> bool {
    return 0 <= coord && coord < sideLength;
  };
  auto smaller = [] (double a, double b) -> bool {
    return (b < 0) || a <= b;
  };

  while (coordOk(gridCoord.x) && coordOk(gridCoord.y) && coordOk(gridCoord.z)) {
    for (const Model* model : cells[indexFor(gridCoord)].models) {
      models.insert(model);
    }

    for (int i = 0; i < 3; ++i) {
      if (nextT[i] < 0) continue;
      const auto a = nextT[(i + 1) % 3];
      const auto b = nextT[(i + 2) % 3];
      if (smaller(nextT[i], a) && smaller(nextT[i], b)) {
        nextT[i] += dt[i];
        gridCoord[i] += incs[i];
        break;
      }
    }
  }

  return models;
}
Пример #13
0
bool AABB::intersects( const Ray& ray, Vector& pt )
{
  // Rays starting and ending in an octree node must be considered
  // to hit the node.
  // if the start point OR the end point is in the AABB, then it's a hit.
  if( containsIn( ray.startPos ) || containsIn( ray.getEndPoint() ) )
  {
    //generateDebugLines( Vector(0,1,0) ) ;//green is RAY STARTED INSIDE
    return true ; 
  }
  
  Vector tmins, tmaxes ;

  // These are red in the profiler.
  tmins = (min - ray.startPos) / ray.direction ;
  tmaxes = (max - ray.startPos) / ray.direction ;
  
  Vector* sols[2] = { &tmins, &tmaxes } ;
  int solS=0, solI=0 ;
  
  real smallestT = HUGE ; // smallest valid t ("so far"). put at inf so first time everything smaller than it.
  Vector closestRaypoint ; // smallest rayPoint (associated with "smallest t so far")

  for( int s = 0 ; s < 2 ; s++ )
  {
    Vector& candSols = *sols[s] ;
    
    // i walks xyz
    for( int i = 0 ; i < 3 ; i++ )
    {
      real& t = candSols.e[i] ; // candidate t
      
      // validity:  0 <= t <= length
      if( BetweenIn( t, 0, ray.length ) )
      {
        Vector raypoint = ray.at( t ) ;

        // AND ON FACE
        // o1 and o2 are the indices of the OTHER faces,
        // if i==0, o1=1, o2=2
        int o1 = ( i + 1 ) % 3 ; // if( i==0 ) o1=1, o2=2; 
        int o2 = ( i + 2 ) % 3 ; // else if( i == 1) o1=2, o2=0;

        if( InRect( raypoint.e[ o1 ],raypoint.e[ o2 ], 
          min.e[o1], min.e[o2],
          max.e[o1], max.e[o2] ) )
        {
          // this one wins, if it's smallest so far
          if( t < smallestT )
          {
            smallestT = t ;
            closestRaypoint = raypoint ;
            // record what face it was
            solS = s ;
            solI = i ;
          }
        }
      }
    }
  }

  // now here, it's possible smallestT was unassigned,
  // which means it'll still be HUGE
  if( smallestT == HUGE )
  {
    // no solution
    ///generateDebugLines( Vector(.2,.2,.2) ) ;//total miss
    return false ;
  }
  else
  {
    // there was an intersection.
    ///generateDebugLines( Vector(1,0,0) ) ;//red means it was a hit
    pt = closestRaypoint ;
    return true ;
  }
}
Пример #14
0
bool AABB::intersects( const Ray& ray )
{
  // VERY IMPORTANT CHECK: If the ray starts inside
  // the box, then it's a hit.  This was important for octrees.
  if( containsIn( ray.startPos ) || containsIn( ray.getEndPoint() ) )
    return true ; 

  #define TECH 0
  #if TECH==0
  // the algorithm says, find 3 t's,
  Vector t ;

  // LARGEST t is the only only we need to test if it's on the face.
  for( int i = 0 ; i < 3 ; i++ )
  {
    if( ray.direction.e[i] > 0 ) // CULL BACK FACE
      t.e[i] = ( min.e[i] - ray.startPos.e[i] ) / ray.direction.e[i] ;
    else
      t.e[i] = ( max.e[i] - ray.startPos.e[i] ) / ray.direction.e[i] ;
  }

  int mi = t.maxIndex() ;
  if( BetweenIn( t.e[mi], 0, ray.length ) )
  {
    Vector pt = ray.at( t.e[mi] ) ;

    // check it's in the box in other 2 dimensions
    int o1 = ( mi + 1 ) % 3 ; // i=0: o1=1, o2=2, i=1: o1=2,o2=0 etc.
    int o2 = ( mi + 2 ) % 3 ;

    return BetweenIn( pt.e[o1], min.e[o1], max.e[o1] ) &&
           BetweenIn( pt.e[o2], min.e[o2], max.e[o2] ) ;
  }

  return false ;
  #elif TECH==1

  // This culls the back faces first, and gives you the answer with the largest valid t
  for( int i = 0 ; i < 3 ; i++ )
  {
    int o1 = ( i + 1 ) % 3 ; // i=0: o1=1, o2=2, i=1: o1=2,o2=0 etc.
    int o2 = ( i + 2 ) % 3 ;

    // min.x (NX) is possible, PX won't be hit. (unless you're inside the box.)
    if( ray.direction.e[i] > 0 ) // CULL BACK FACE
    {
      real t = ( min.e[i] - ray.startPos.e[i] ) / ray.direction.e[i] ;

      // 1. CHECK VALID T
      if( BetweenIn( t, 0, ray.length ) )
      {
        // 2. CHECK IN BOX
        Vector pt = ray.at( t ) ;
        if( BetweenIn( pt.e[o1], min.e[o1], max.e[o1] ) && BetweenIn( pt.e[o2], min.e[o2], max.e[o2] ) )
          return true ;  // it's valid in the box
      }
    }
    else if( ray.direction.e[i] < 0 ) // max.x (PX) is possible
    {
      real t = ( max.e[i] - ray.startPos.e[i] ) / ray.direction.e[i] ;
      if( BetweenIn( t, 0, ray.length ) ) // valid t
      {
        Vector pt = ray.at( t ) ;
        if( BetweenIn( pt.e[o1], min.e[o1], max.e[o1] ) && BetweenIn( pt.e[o2], min.e[o2], max.e[o2] ) )
          return true ;  // it's valid in the box
      }
    }
  }

  return false ; // no hit.
  #elif TECH==2
  // This solves ALL 6 solutions and finds the shortest t.
  // Rays starting and ending in an octree node must be considered
  // to hit the node.
  // if the start point OR the end point is in the AABB, then it's a hit.
  
  
  // These are red in the profiler.
  Vector tmins = (min - ray.startPos) / ray.direction ;
  Vector tmaxes = (max - ray.startPos) / ray.direction ;
  
  Vector* sols[2] = { &tmins, &tmaxes } ;
  
  for( int s = 0 ; s < 2 ; s++ )
  {
    Vector& candSols = *sols[s] ;
    
    // i walks xyz
    for( int i = 0 ; i < 3 ; i++ )
    {
      real& t = candSols.e[i] ; // candidate t
      
      // validity:  0 <= t <= length
      if( BetweenIn( t, 0, ray.length ) )
      {
        Vector raypoint = ray.at( t ) ;

        // AND ON FACE
        // o1 and o2 are the indices of the OTHER faces,
        // if i==0, o1=1, o2=2
        int o1 = ( i + 1 ) % 3 ; // if( i==0 ) o1=1, o2=2; 
        int o2 = ( i + 2 ) % 3 ; // else if( i == 1) o1=2, o2=0;

        if( InRect( raypoint.e[ o1 ],raypoint.e[ o2 ], 
          min.e[o1], min.e[o2],
          max.e[o1], max.e[o2] ) )
        {
          // the box got hit, any side
          return true ;
        }
      }
    }
  }

  // No hit
  return false ;

  #endif
}
Пример #15
0
// Moeller-Trumbore
bool Triangle::hit(const Ray& ray, const Ray_Tracer* rt,
                    float t_min, float t_max, Ray_Hit& rh, bool shadow) const {

    // Absolute Triangle Vertex Positions
    V3& v0 = m->verts[inds[0]];
    V3& v1 = m->verts[inds[1]];
    V3& v2 = m->verts[inds[2]];

    // Two edges of triangle
    V3 e0, e1;
    e0 = v1 - v0;
    e1 = v2 - v0; 

    V3 p = ray.s.cross(e1);
    float deter = e0.dot(p);

    if (deter  > -EPSILON && deter < EPSILON)
        return false; 

    V3 t = ray.o - v0;
    
    // Store the inverse to reduce divisions
    float inv_deter = 1.0 / deter;
    float u = t.dot(p) * inv_deter;

    if (u < 0.0 || u > 1.0)
        return false;

    V3 q = t.cross(e0);
    float v = ray.s.dot(q) * inv_deter;

    if (v < 0.0 || u + v > 1.0)
        return false;

    float t_inter = e1.dot(q) * inv_deter;

    if (t_inter < t_min || t_inter > t_max) {
        //std::cout << "Cull: " << t_inter << '\t' <<t_min<< '\t' <<t_max<<  std::endl;
        return false;
    }

    rh.t = t_inter;
    rh.col = 0.2*m->mat.col;
    rh.shape = m;

    if (shadow || ray.depth >= rt->depth_limit)
        return true;

/*
    if (is_light) {     
        rh.col = Color(1.0, 1.0, 1.0);
        return true;
    }
*/

    V3 int_loc = ray.at(t_inter);
    // Shadow
    for (Shape* light : rt->lights) {

        // BIG ASSUMPTION THAT ALL LIGHTS ARE SPHERES
        Sphere* sph = static_cast<Sphere*>(light);

        // Make ray from intersection to light
        V3 int_to_light = sph->c - int_loc; 
        float dist_to_light = int_to_light.norm();
        int_to_light.normalize();
        Ray shadow_ray(int_loc + EPSILON*int_to_light, int_to_light, ray.depth + 1);
        Ray_Hit shadow_hit;
        if (rt->kd->hit_helper(true, rt->kd->root, shadow_ray, rt,
                EPSILON, dist_to_light, shadow_hit, true, 0)) {
            if (!shadow_hit.shape->is_light) {
                continue;
            }
        }

        float inner = int_to_light.dot(normal);
        if (inner > 0.0) {
            rh.col += sph->mat.col *inner* m->mat.diff * m->mat.col;
        }
    }

    // Reflection 
    V3 refl_dir = ray.s - 2.0f * (normal.dot(ray.s)) * normal;
    Ray refl_ray(int_loc + EPSILON*refl_dir, refl_dir, ray.depth + 1);
    Ray_Hit refl_hit;
    if (rt->kd->hit_helper(true, rt->kd->root, refl_ray, rt,
            EPSILON, FLT_MAX, refl_hit, false, 0)) {
    //if (rt->trace(refl_ray, EPSILON, FLT_MAX, refl_hit, false)) {
        rh.col += m->mat.refl*refl_hit.col * refl_hit.shape->mat.col;
    }

    return true;  
}
Пример #16
0
bool AABB::intersect(const Ray& ray, float& t, glm::vec3& normal, uint64_t moxelIndex)
{
   float normalDirection[3] = {1.0f,1.0f,1.0f};
   normal = glm::vec3(0.0f,0.0f,0.0f);
   //cout << "AABB: ";
   //print();
   //cout << "Ray: ";
   //ray.print();
   // If the ray starts inside the box, or ends inside
   if (contains(ray.position))
   {
      return false; 
   }

   // the algorithm says, find 3 t's,
   glm::vec3 tVals;

   // LARGEST t is the only one we need to test if it's on the face.
   for (int i = 0 ; i < 3 ; i++)
   {
      if (ray.direction[i] == 0)
      {
         tVals[i] = -FLT_MAX;
      }
      else if(ray.direction[i] > 0) // CULL BACK FACE
      {
         tVals[i] = ( mins[i] - ray.position[i] ) / ray.direction[i];
         
         // If the ray direction is positive, it will hit the more negative AABB side which makes 
         // the normal point in the negative direction
         normalDirection[i] = -1.0f; 
      }
      else
      {
         tVals[i] = ( maxs[i] - ray.position[i] ) / ray.direction[i];

         // If the ray direction is positive, it will hit the more positive AABB side which makes 
         // the normal point in the positive direction
         normalDirection[i] = 1.0f; 
      }
   }

   // cout << "tVals: ";
   // for (int i = 0; i < 3; ++i)
   // {
   //    cout << "(" << i << ": " << tVals[i] << ")  ";
   // }
   // cout << endl;

   // Get the max index
   float maxValue = tVals[0];
   int maxIndex = 0;
   if (tVals[1] > maxValue)
   {
      maxValue = tVals[1];
      maxIndex = 1;
   }
   
   if (tVals[2] > maxValue)
   {
      maxValue = tVals[2];
      maxIndex = 2;
   }

   t = maxValue;
   normal[maxIndex] = normalDirection[maxIndex];

   if (tVals[maxIndex] > 0.0f)
   {
      glm::vec3 pt = ray.at(tVals[maxIndex]);

      // check it's in the box in other 2 dimensions
      int o1 = ( maxIndex + 1 ) % 3; // i=0: o1=1, o2=2, i=1: o1=2,o2=0 etc.
      int o2 = ( maxIndex + 2 ) % 3;

      return inRange(pt[o1], mins[o1], maxs[o1]) && inRange(pt[o2], mins[o2], maxs[o2]) ;
   }

   return false ; // the ray did not hit the box.
}
Пример #17
0
void Scene::jiggle(Ray& ray){
  Point pjig = ray.at(pow(2,-32));
  ray = Ray(pjig,ray.D);
}
Пример #18
0
pair<int, float> Grid::trace(const Ray &ray, float tmin, float tmax, int ignored_id, int flags) const {
	float3 p1 = ray.at(tmin), p2 = ray.at(tmax);
	int2 pos = worldToGrid((int2)p1.xz()), end = worldToGrid((int2)p2.xz());
	
	//TODO: verify for rays going out of grid space
	if(!isInsideGrid(pos) || !isInsideGrid(end))
		return make_pair(-1, constant::inf);

	// Algorithm idea from: RTCD by Christer Ericson
	int dx = end.x > pos.x? 1 : end.x < pos.x? -1 : 0;
	int dz = end.y > pos.y? 1 : end.y < pos.y? -1 : 0;

	float cell_size = (float)node_size;
	float inv_cell_size = 1.0f / cell_size;
	float lenx = fabs(p2.x - p1.x);
	float lenz = fabs(p2.z - p1.z);

	float minx = float(node_size) * floorf(p1.x * inv_cell_size), maxx = minx + cell_size;
	float minz = float(node_size) * floorf(p1.z * inv_cell_size), maxz = minz + cell_size;
	float tx = (p1.x > p2.x? p1.x - minx : maxx - p1.x) / lenx;
	float tz = (p1.z > p2.z? p1.z - minz : maxz - p1.z) / lenz;

	float deltax = cell_size / lenx;
	float deltaz = cell_size / lenz;

	int out = -1;
	float out_dist = tmax + constant::epsilon;

	while(true) {
		int node_id = nodeAt(pos);
		const Node &node = m_nodes[node_id];

		if(flagTest(node.obj_flags, flags) && intersection(ray, node.bbox) < out_dist) {
			const Object *objects[node.size];
			int count = extractObjects(node_id, objects, ignored_id, flags);

			for(int n = 0; n < count; n++) {
				float dist = intersection(ray, objects[n]->bbox);
				if(dist < out_dist) {
					out_dist = dist;
					out = objects[n] - &m_objects[0];
				}
			}	
			
			if(node.is_dirty)
				updateNode(node_id);
		}

		if(tx <= tz || dz == 0) {
			if(pos.x == end.x)
				break;
			tx += deltax;
			pos.x += dx;
		}
		else {
			if(pos.y == end.y)
				break;
			tz += deltaz;
			pos.y += dz;
		}
		float ray_pos = tmin + max((tx - deltax) * lenx, (tz - deltaz) * lenz);
		if(ray_pos >= out_dist)
			break;
	}

	return make_pair(out, out_dist);
}
Пример #19
0
Color Scene::trace(const Ray &ray, int steps,double eta1)
{
    // Find hit object and distance
    Hit min_hit(std::numeric_limits<double>::infinity(),Vector());
    Object *obj = NULL;
    for (unsigned int i = 0; i < objects.size(); ++i) {
        Hit hit(objects[i]->intersect(ray));
        if (hit.t<min_hit.t) {
            min_hit = hit;
            obj = objects[i];
        }
    }

    // No hit? Return background color.
    if (!obj) return Color(0.0, 0.0, 0.0);

    Material *material = obj->material;            //the hit objects material
    Point hit = ray.at(min_hit.t);                 //the hit point
    Vector N = min_hit.N;                          //the normal at hit point
    Vector V = -ray.D;                             //the view vector

    /****************************************************
    * This is where you should insert the color
    * calculation (Phong model).
    *
    * Given: material, hit, N, V, lights[]
    * Sought: color
    *
    * Hints: (see triple.h)
    *        Triple.dot(Vector) dot product
    *        Vector+Vector      vector sum
    *        Vector-Vector      vector difference
    *        Point-Point        yields vector
    *        Vector.normalize() normalizes vector, returns length
    *        double*Color        scales each color component (r,g,b)
    *        Color*Color        dito
    *        pow(a,b)           a to the power of b
    ****************************************************/

    // extract and/or declare variables
    // for lighting calculations
    Color ambient = Color(1.0,1.0,1.0); // ambient colour
    Color base = material->color; // material colour
    double ka = material->ka; // ambient intensity;
    double kd = material->kd; // diffuse intensity
    double ks = material->ks; // specular intensity
    double e = material->n; // exponent of specular highlight size
    double reflect = material->reflect; // reflect coefficient
    double refract = material->refract; // refraction coefficient
    double eta2 = material->eta; // refraction index

    if(eta1 == eta2){
      eta2 = AIR_ETA;
    }

    // get reflected ray
    Vector vec_ref = ray.D - (2.0 *(ray.D.dot(N))*N); // reflect ray direction
    Ray ray_ref(hit,vec_ref); //reflect ray
    // jiggle the ray
    jiggle(ray_ref);

    // hack
    Vector frac_n;
    if(ray.D.dot(N) < 0.0){
      frac_n = N;
    }else{
      frac_n = -N;
    }

    // get refracted ray
    bool frac_flag;
    Vector frac_dir = fractf(eta1,eta2,ray.D,frac_n); // direction of refraction

    Ray ray_frac(hit,frac_dir); // ray going out of the material
    if(frac_dir.length_2() > 0.0 && refract > 0.0){
      frac_flag = true;
    }else{
      frac_flag = false;
    }

    // jiggle the ray
    jiggle(ray_frac);

    Color c_ref; // colour of reflected ray
    Color c_frac; // colour of refracted ray
    // recursively trace reflected/refracted rays up to steps times
    if(steps > 0){
      if(reflect > 0.0) c_ref = trace(ray_ref,steps-1,eta1);
      if(frac_flag) c_frac = trace(ray_frac, steps-1,eta2);
    }

    Color color = ka * base * ambient; // set ambient colour
    for(unsigned int i = 0;i<lights.size();i++){
      bool shaded = false; // flag if the current light cast a shadow
      Vector L = hit - lights[i]->position; // vector of light direction
      Vector SL = lights[i]->position - hit; // vector of shadow feeler
      L.normalize();
      SL.normalize();

      // get shadow feelers
      Ray feeler = Ray(hit,SL);
      //jiggle Ray
      jiggle(feeler);
      // test to see if object is in shadow
      if(shadows){
      for(unsigned int j = 0;j<objects.size();j++){
        Hit test(objects[j]->intersect(feeler));
        if(test.t >= 0.0)  {
          shaded = true;
          break;
        }
      }
    }

      if(!shaded){
        Color lc = lights[i]->color; // colour of light

        double lnDot = L.dot(N); // dot product of light

        Vector R = L - (2.0*N*lnDot); // reflection vector
        R.normalize();
        double rvDot = R.dot(V) ;

        color += (kd*base*lc*max(0.0,lnDot)) + (ks*lc*pow(max(0.0,rvDot),e));
      }
    }

    color += reflect*c_ref + refract*c_frac;

    return color;
}
Пример #20
0
    /**
     * @brief intersect a geometric object.
     * @param ray_ the ray
     * @param p_diff_geom_ the result of the intersection
     * @return true if the ray intersects the geometry. Modifies the ray_.max_t() value, intersect only if the intersection
     * is before ray_.max_t()
     * @todo Factorize code shared by Box3D::clip()
     *
     * Adapted from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrLine3Box3.cpp
     */
    bool intersect (Ray& ray_, Diff_Geom * p_diff_geom_) const {
        float t0 = -ray_.ray_epsilon();
        float t1 = ray_.max_t();

        // Convert linear component to box coordinates.
        Vector3D diff = ray_.ori() - m_center;
        Vector3D BOrigin(
            diff.dot(m_axis[0]),
            diff.dot(m_axis[1]),
            diff.dot(m_axis[2])
        );
        Vector3D BDirection(
            ray_.dir().dot(m_axis[0]),
            ray_.dir().dot(m_axis[1]),
            ray_.dir().dot(m_axis[2])
        );

        float saveT0 = t0, saveT1 = t1;
        bool notAllClipped;
        unsigned char updated;
        int nt0, nt1;
        notAllClipped = clip(+BDirection.x(), -BOrigin.x()-m_extent[0], t0, t1, updated);
        if (updated == 1)
            nt0 = 0;
        else if (updated == 2)
            nt1 = 0;
        notAllClipped = notAllClipped && clip(-BDirection.x(), +BOrigin.x()-m_extent[0], t0, t1, updated);
        if (updated == 1)
            nt0 = 1;
        else if (updated == 2)
            nt1 = 1;
        notAllClipped = notAllClipped && clip(+BDirection.y(), -BOrigin.y()-m_extent[1], t0, t1, updated);
        if (updated == 1)
            nt0 = 2;
        else if (updated == 2)
            nt1 = 2;
        notAllClipped = notAllClipped && clip(-BDirection.y(), +BOrigin.y()-m_extent[1], t0, t1, updated);
        if (updated == 1)
            nt0 = 3;
        else if (updated == 2)
            nt1 = 3;
        notAllClipped = notAllClipped && clip(+BDirection.z(), -BOrigin.z()-m_extent[2], t0, t1, updated);
        if (updated == 1)
            nt0 = 4;
        else if (updated == 2)
            nt1 = 4;
        notAllClipped = notAllClipped && clip(-BDirection.z(), +BOrigin.z()-m_extent[2], t0, t1, updated);
        if (updated == 1)
            nt0 = 5;
        else if (updated == 2)
            nt1 = 5;


        if (notAllClipped && (t0 != saveT0 || t1 != saveT1)) {

             if ( (t0 > ray_.ray_epsilon() ) && (t0 < ray_.max_t()) ){
                Vector3D normal = m_axis[nt0/2];
                if (nt0%2)
                    normal = -normal;
                p_diff_geom_->set_pos(ray_.at(t0));
                p_diff_geom_->set_normal(normal);
                p_diff_geom_->set_t(t0);
                ray_.set_max_t(t0);
                return true;
            } else if ( (t1 > ray_.ray_epsilon()) && (t1 < ray_.max_t()) ){
                 Vector3D normal = m_axis[nt1/2];
                 if (nt1%2)
                     normal = -normal;
                 p_diff_geom_->set_pos(ray_.at(t1));
                 p_diff_geom_->set_normal(normal);
                 p_diff_geom_->set_t(t1);
                 ray_.set_max_t(t1);
                 return true;
             } else
                return false;
        } else {
            return false;
        }
    }
Пример #21
0
    int get_clip_points(Ray& ray_, Diff_Geom ipoints[2], float t[2]) const{
        int numintersection = 0;
        Vector3D E = ray_.ori() - m_vertex;
        float AdD = m_axis.dot(ray_.dir());
        float cosSqr = m_costheta*m_costheta;
        float AdE = m_axis.dot(E);
        float DdE = ray_.dir().dot(E);
        float EdE = E.dot(E);
        float c2 = AdD*AdD-cosSqr;
        float c1 = AdD*AdE - cosSqr*DdE;
        float c0 = AdE*AdE - cosSqr*EdE;
        float dot;
        Vector3D zero;

        if (std::fabs(c2)>0) {
            float discr = c1*c1 - c0*c2;
            float invC2 = 1.f/c2;
            if (discr < 0) {
                // No intersection
                return  0;
            } else if (discr > 0) {
                // two distinct intersections
                float root = std::sqrt(discr);
                // entry point
                t[numintersection] = (-c1 + root) * invC2;
                E = ray_.at(t[numintersection]) - m_vertex;
                dot = E.dot(m_axis);
                if ( (dot > 0) && (dot <= m_height))
                {
                    fillConicalDiffGeom(ipoints[numintersection], ray_, t[numintersection], true);
                    ++numintersection;
                }
                // exit point
                t[numintersection] = (-c1 - root) * invC2;
                E = ray_.at(t[numintersection]) - m_vertex;
                dot = E.dot(m_axis);
                if ( (dot > 0)  && (dot <= m_height))
                {
                    fillConicalDiffGeom(ipoints[numintersection], ray_, t[numintersection], false);
                    ++numintersection;
                }
                return numintersection;
          } else {
                // one reapeated intersection : ray is tangent to the cone
                // may be return 0 instead of an intersection ?
                return 0;
                t[numintersection] = -c1 * invC2;
                E = ray_.at(t[numintersection]) - m_vertex;
                dot = E.dot(m_axis);
                if ( (dot > 0) && (dot <= m_height)) {
                    fillConicalDiffGeom(ipoints[numintersection], ray_, t[numintersection], true);
                    ++numintersection;
                }
                return numintersection;
           }
        } else if (std::fabs(c1) > 0) {
            // the ray is on the boundary of the cone
            // we consider no intersection
            // TODO : check this for CSG
            return 0;
        } else {
            //return false;
            // Cone contains ray V+tD
            // The ray intersect the cone exactly at its vertex :(
            // TODO : manage this particular case in another function
            ipoints[numintersection].set_pos(m_vertex);
            ipoints[numintersection].set_normal(-m_axis);

            ipoints[numintersection].set_u(1.f);
            ipoints[numintersection].set_v(0.f);

            E = ray_.ori() - m_vertex;
            t[numintersection] = ( (E.dot(ray_.dir())<0) ? std::sqrt(EdE) : -std::sqrt(EdE) ) ;
            ipoints[numintersection].set_t(t[numintersection]);
            ipoints[numintersection].set_in(true);
            ipoints[numintersection].set_u(0.f);
            ipoints[numintersection].set_v(1.f);

            // todo : compute here normal derivatives (according to x and y directions on the image plane)
            ipoints[numintersection].set_dNdx(zero);
            ipoints[numintersection].set_dNdy(zero);

            ++numintersection;
             // check with cap plane
            Plane cap(m_vertex + m_axis * m_height, m_axis);
            IntervalSet capset;
            if (cap.clip(ray_, capset)) {
                if (capset.bounds()[0].t < t[numintersection-1]) {
                    t[numintersection] = t[numintersection-1];
                    ipoints[numintersection] = ipoints[numintersection-1];
                    --numintersection;
                } else {
                    capset.bounds()[0].data->set_in(false);
                }
                ipoints[numintersection] = *(capset.bounds()[0].data);
                // TODO : update u, v dTdx and dTdy
                ipoints[numintersection].set_u(ipoints[numintersection].u()/(PSCALE*m_radius));
                ipoints[numintersection].set_v(ipoints[numintersection].v()/(PSCALE*m_radius));
                ipoints[numintersection].set_dTdx(ipoints[numintersection].dTdx()* (1.f/(PSCALE*m_radius)));
                ipoints[numintersection].set_dTdy(ipoints[numintersection].dTdy()* (1.f/(PSCALE*m_radius)));
                delete capset.bounds()[0].data;
                delete capset.bounds()[1].data;
                return 2;
            } else {
                // must never reach this point !
                assert(false);
                return 0;
            }
        }
    }
Пример #22
0
Hit Box::intersect(const Ray &ray)
{	
    /****************************************************
    * RT1.1: INTERSECTION CALCULATION
	* t is the distance between the ray origin and the closest face of the box
    ****************************************************/

	/* Mathematic Method 
	* We consider a cube like the intersection of 3 slabs
	* We first start to calculate the distance between the ray and the 2D slab on x,y of the cube
	* Then repeat it for z
	*/
    double t, tentry, texit, tyentry, tyexit, tzentry, tzexit; 

	/* A box is defined with two point: the minimum and maximum exent points (min and max) */
	/* extents[0] = min extent of the box & extents[1] = max extent of the box*/
	Point extents[2] = {min,max};
	
	/* First we start in 2D 
	* Exemple for tentry initialized with txentry:
	* ray.O.x + txentry*ray.D.x = min.x (= extents[0].x) if ray.D.x >= 0
	* <=> tentryx = (min.x - ray.O.x)/ ray.D.x
	* or
	* ray.O.x + txentry*ray.D.x = max.x (= extents[1].x) if ray.D.x < 0
	* <=> tentryx = (max.x - ray.O.x)/ ray.D.x
	*/
    tentry = (extents[(ray.D.x < 0.0 && ray.D.x != -0.0)].x - ray.O.x) / ray.D.x; 
    texit = (extents[1-(ray.D.x < 0.0 && ray.D.x != -0.0)].x - ray.O.x) / ray.D.x; 
    tyentry = (extents[(ray.D.y < 0.0 && ray.D.y != -0.0)].y - ray.O.y) / ray.D.y; 
    tyexit = (extents[1-(ray.D.y < 0.0 && ray.D.y != -0.0)].y - ray.O.y) / ray.D.y; 
 
	/* Case where there is no Hit*/
    if ((tentry > tyexit) || (tyentry > texit)){ 
        return Hit::NO_HIT();
	}	
	/* Case where the entry point is on y */
    if (tyentry > tentry) {
        tentry = tyentry; 
	}
	/* Case where the exit point is on y */
	if (tyexit < texit) { 
        texit = tyexit; 
    }
 
	/* The we compare tentry and texit with the 3rd dimension */
    tzentry = (extents[(ray.D.z < 0.0 && ray.D.z != -0.0)].z - ray.O.z)  / ray.D.z; 
    tzexit = (extents[1-(ray.D.z < 0.0 && ray.D.z != -0.0)].z - ray.O.z)  / ray.D.z; 
	
	/* Case where there is no Hit*/
    if ((tentry > tzexit) || (tzentry > texit)) 
        return Hit::NO_HIT();
		
	/* Case where the entry point is on z */
    if (tzentry > tentry) {
        tentry = tzentry;
	}
	/* Case where the exit point is on z */
    if (tzexit < texit) {
        texit = tzexit; 
    }
	
	/* Choose t according to the tentry and texit cases*/
	if (tentry <= 0){
		t = texit;
	}
	else{
		t = tentry;
	}	
			

    /****************************************************
    * RT1.2: NORMAL CALCULATION
    ****************************************************/
	Vector N;
	Point a,b;
	Vector v;
	Point center = Point((min.x + max.x)/2.0,(min.y + max.y)/2.0,(min.z + max.z)/2.0);
	Point hit = ray.at(t);
	double side_x = fabs(max.x - min.x)/2.0;
	double side_y = fabs(max.y - min.y)/2.0;
	double side_z = fabs(max.z - min.z)/2.0;
	
	if (hit.y  <= center.y - side_y + 0.1 && hit.y  >= center.y - side_y - 0.1) {
		// Face 6
		a = Point(center.x,center.y - side_y,center.z);
		//cout << "6";
	}
	else if ( hit.y  <= center.y + side_y + 0.1 && hit.y  >= center.y + side_y - 0.1) {
		// Face 3
		a = Point(center.x,center.y + side_y,center.z);
		//cout << "3";
	}
	else if (hit.x  <= center.x - side_x + 0.1 && hit.x  >= center.x - side_x - 0.1) {
		// Face 5
		a = Point(center.x- side_x,center.y,center.z);
		//cout << "5";
	}
	else if ( hit.x  <= center.x + side_x + 0.1 && hit.x  >= center.x + side_x - 0.1) {
		// Face 2
		a = Point(center.x+ side_x,center.y ,center.z);
		//cout << "2";
	}
	else if (hit.z  <= center.z - side_z + 0.1 && hit.z  >= center.z - side_z - 0.1) {
		// Face 4
		a = Point(center.x,center.y,center.z- side_z);
		//cout << "4";
	}
	else if (hit.z  <= center.z + side_z + 0.1 && hit.z  >= center.z + side_z - 0.1) {
		// Face 1
		a = Point(center.x,center.y,center.z+ side_z);
		//cout << "1";
	}
	else {
		int x = center.x + side_x;
		cout << "?- " << hit.x << " c: " << (int)(x) <<"-";
		cout << ((int) (hit.x) >= (int)(x)) <<"-";
	}
	v = hit - a;
	b = center + v;
	N = (hit - b).normalized();
	
	
	
	/* Choose of the good direction 
	if (N.dot(ray.D) > 0){
		N = -N;
	}*/

	//cout << "x :" <<  hit.x <<" y :" <<  hit.y <<" z :" <<  hit.z << "\n" ;

    return Hit(t,N);
}
Пример #23
0
// ----------------------------------------------------- tracePhong ------------------------------------------------------------------ //
Color Scene::tracePhongGooch(const Ray &ray, int recursionDepth){
    // Find hit object and distance
    Hit min_hit(std::numeric_limits<double>::infinity(),Vector());
    Object *obj = NULL;
    for (unsigned int i = 0; i < objects.size(); ++i) {
        Hit hit(objects[i]->intersect(ray));
        if (hit.t<min_hit.t) {
            min_hit = hit;
            obj = objects[i];
        }
    }

    // No hit? Return background color.
    if (!obj) return Color(0.0, 0.0, 0.0);

    Material *material = obj->material;            //the hit objects material
    Point hit = ray.at(min_hit.t);                 //the hit point
    Vector N = min_hit.N;                          //the normal at hit point
    Vector V = -ray.D;                             //the view vector


    /****************************************************
    * This is where you should insert the color
    * calculation (Phong model).
    *
    * Given: material, hit, N, V, lights[]
    * Sought: color
    *
    * Hints: (see triple.h)
    *        Triple.dot(Vector) dot product
    *        Vector+Vector      vector sum
    *        Vector-Vector      vector difference
    *        Point-Point        yields vector
    *        Vector.normalize() normalizes vector, returns length
    *        double*Color        scales each color component (r,g,b)
    *        Color*Color        dito
    *        pow(a,b)           a to the power of b
    ****************************************************/

    Color color;

    //For each light
	for(unsigned int i = 0; i < lights.size(); i++){
		bool isShadow = false;

		if (rendermode == phong) //Ambiant
			color += lights[i]->color * material->color * material->ka;

		//Shadow
		if(Shadow){
			//Ray from light to object
			Ray light(lights[i]->position, hit - lights[i]->position);

			//Hit from light to nearest object
			Hit minHit = findMinHit(light);

			//Hit from current object to light
			Hit currentHit(obj->intersect(light));

			//
			if (minHit.t < currentHit.t) isShadow = true;
		}
		//No Shadow -> Calculate colors
		if(!isShadow){

			//The light vector
			Vector L = lights[i]->position - hit;L.normalize();
			//The R vector (required for specular shading)
			Vector R = (-1*L) + 2 * (L.dot(N)) * N;

			if (rendermode == phong) //Diffuse
				if (material->texture){
					color += (max(0.0,N.dot(L)) * lights[i]->color) * obj->calcTexture(hit) * material->kd;
				} else { 
					color += (max(0.0,N.dot(L)) * lights[i]->color) * material->color * material->kd;
				}
			if (rendermode == gooch && ray.D.dot(N)<-0.2){
				Color kCool = Color(0.0,0.0,kBlue) + alpha * (lights[i]->color * material->color * material->kd);
				Color kWarm = Color(kYellow,kYellow,0.0) + beta * (lights[i]->color * material->color * material->kd);
				color += (kCool *(1 - N.dot(L))/2) + (kWarm * (1 + N.dot(L))/2);
			}

			//Specular		+ dot(R,V)^n LightColor ks
			color += pow(max(0.0,R.dot(V)), material->n) * lights[i]->color * material->ks;
		}
	}

	//Reflection
	if(recursionDepth <= maxRecursionDepth && ray.D.dot(N)<-0.2){
		Color buffer(0.0, 0.0, 0.0);

		//The reflected direction
		Vector reflectV((V + 2*(-N.dot(V))*N));

		for (unsigned int i=0; i<4; i++){

			//The reflected ray
			Ray reflect(hit + 0.001 * N, -reflectV);

			//Calculate reflection through recursion
			buffer += material->ks*tracePhongGooch(reflect, recursionDepth+1);
			reflectV.x += 0.01 * cos(0.5);
			reflectV.y += 0.01 * sin(0.5);
		}

		//Color = average buffer value
		color += buffer/4;
	}

    return color;
}
Пример #24
0
    /**
     * @brief get_clip_points
     * @param ray_
     * @param ipoints
     * @param t
     * @return the number of clipping position on the ray (0 to 2)
     */
    int get_clip_points(Ray& ray_, Diff_Geom ipoints[2], float t[2]) const{
        int numintersection = 0;
        Vector3D E = ray_.ori() - m_vertex;
        float AdD = m_axis.dot(ray_.dir());
        float cosSqr = m_costheta*m_costheta;
        float AdE = m_axis.dot(E);
        float DdE = ray_.dir().dot(E);
        float EdE = E.dot(E);
        float c2 = AdD*AdD-cosSqr;
        float c1 = AdD*AdE - cosSqr*DdE;
        float c0 = AdE*AdE - cosSqr*EdE;
        float dot;
        if (std::fabs(c2)>0) {
            float discr = c1*c1 - c0*c2;
            float invC2 = 1.f/c2;
            if (discr < 0) {
                // No intersection
                return  0;
            } else if (discr > 0) {
                // two distinct intersections
                float root = std::sqrt(discr);
                // entry point
                t[numintersection] = (-c1 + root) * invC2;
                ipoints[numintersection].set_pos(ray_.at(t[numintersection]));
                E = ipoints[numintersection].pos() - m_vertex;
                dot = E.dot(m_axis);
                if ( (dot > 0) && (dot <= m_height))
                {
                    Vector3D normal=compute_normal(ipoints[numintersection].pos());
                    ipoints[numintersection].set_normal(normal);
                    ipoints[numintersection].set_t(t[numintersection]);
                    ++numintersection;
                }

                // exit point
                t[numintersection] = (-c1 - root) * invC2;
                ipoints[numintersection].set_pos(ray_.at(t[numintersection]));
                E = ipoints[numintersection].pos() - m_vertex;
                dot = E.dot(m_axis);
                if ( (dot > 0)  && (dot <= m_height))
                {
                    Vector3D normal=compute_normal(ipoints[numintersection].pos());
                    ipoints[numintersection].set_normal(normal);
                    ipoints[numintersection].set_t(t[numintersection]);
                    ++numintersection;
                }

                return numintersection;
          } else {
                // one reapeated intersection : ray is tangent to the cone
                // may be return 0 instead of an intersection ?
                return 0;
                t[numintersection] = -c1 * invC2;
                ipoints[numintersection].set_pos(ray_.at(t[numintersection]));
                E = ipoints[numintersection].pos() - m_vertex;
                dot = E.dot(m_axis);
                if ( (dot > 0) && (dot <= m_height)) {
                    Vector3D normal=compute_normal(ipoints[numintersection].pos());
                    ipoints[numintersection].set_normal(normal);
                    ipoints[numintersection].set_t(t[numintersection]);
                    ++numintersection;
                }
                return numintersection;
           }
        } else if (std::fabs(c1) > 0) {
            // the ray is on the boundary of the cone
            // we consider no intersection
            // TODO : check this for CSG
            return 0;
        } else {
            //return false;
            // Cone contains ray V+tD
            // The ray intersect the cone exactly at its vertex :(
            ipoints[numintersection].set_pos(m_vertex);
            ipoints[numintersection].set_normal(-m_axis);
            E = ray_.ori() - m_vertex;
            t[numintersection] = ( (E.dot(ray_.dir())<0) ? std::sqrt(EdE) : -std::sqrt(EdE) ) ;
            ipoints[numintersection].set_t(t[numintersection]);
            ++numintersection;
            // TODO compute cap plane intersection

            // check with cap plane
            Plane cap(m_vertex + m_axis * m_height, m_axis);
            IntervalSet capset;
            if (cap.clip(ray_, capset)) {
                if (capset.bounds()[0].t < t[numintersection-1]) {
                    t[numintersection] = t[numintersection-1];
                    ipoints[numintersection] = ipoints[numintersection-1];
                    --numintersection;
                }
                ipoints[numintersection] = *(capset.bounds()[0].data);
                delete capset.bounds()[0].data;
                delete capset.bounds()[1].data;
                return 2;
            } else {
                // must never reach this point !
                assert(false);
                return 0;
            }
        }
    }
Пример #25
0
    /**
     * @brief clip a ray by a Box3D.
     * @param ray_ the ray to clip
     * @param bounds ray sorted bounds of the resulting clipping segment.
     * @return  true if ray was clipped. bounds parameter is filld by this method
     *
     * For simple convex objects, there is two values in  bounds that represent in and out events.
     * An in event is whe the ray enters the geometry, an out is when the ray leaves the geometry.
     *
     * @todo Factorize code shared by Box3D::intersect()
     *
     * Adapted from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrLine3Box3.cpp
     *
     */
    bool clip(Ray& ray_, IntervalSet &bounds) const {
        float t0 = std::numeric_limits<float>::min();
        float t1 = std::numeric_limits<float>::max();

        // Convert linear component to box coordinates.
        Vector3D diff = ray_.ori() - m_center;
        Vector3D BOrigin(
            diff.dot(m_axis[0]),
            diff.dot(m_axis[1]),
            diff.dot(m_axis[2])
        );
        Vector3D BDirection(
            ray_.dir().dot(m_axis[0]),
            ray_.dir().dot(m_axis[1]),
            ray_.dir().dot(m_axis[2])
        );

        float saveT0 = t0, saveT1 = t1;
        bool notAllClipped;
        unsigned char updated;
        int nt0, nt1;
        notAllClipped = clip(+BDirection.x(), -BOrigin.x()-m_extent[0], t0, t1, updated);
        if (updated == 1)
            nt0 = 0;
        else if (updated == 2)
            nt1 = 0;
        notAllClipped = notAllClipped && clip(-BDirection.x(), +BOrigin.x()-m_extent[0], t0, t1, updated);
        if (updated == 1)
            nt0 = 1;
        else if (updated == 2)
            nt1 = 1;
        notAllClipped = notAllClipped && clip(+BDirection.y(), -BOrigin.y()-m_extent[1], t0, t1, updated);
        if (updated == 1)
            nt0 = 2;
        else if (updated == 2)
            nt1 = 2;
        notAllClipped = notAllClipped && clip(-BDirection.y(), +BOrigin.y()-m_extent[1], t0, t1, updated);
        if (updated == 1)
            nt0 = 3;
        else if (updated == 2)
            nt1 = 3;
        notAllClipped = notAllClipped && clip(+BDirection.z(), -BOrigin.z()-m_extent[2], t0, t1, updated);
        if (updated == 1)
            nt0 = 4;
        else if (updated == 2)
            nt1 = 4;
        notAllClipped = notAllClipped && clip(-BDirection.z(), +BOrigin.z()-m_extent[2], t0, t1, updated);
        if (updated == 1)
            nt0 = 5;
        else if (updated == 2)
            nt1 = 5;

        if (notAllClipped && (t0 != saveT0 || t1 != saveT1)) {
            if (t1 > t0) {

                Vector3D normal = m_axis[nt0/2];
                if (nt0%2)
                    normal = -normal;
                Diff_Geom *in = new Diff_Geom(ray_.at(t0), normal, t0);

                normal = m_axis[nt1/2];
                if (nt1%2)
                    normal = -normal;
                Diff_Geom *out = new Diff_Geom(ray_.at(t1), normal, t1);
                bounds.add(in, out);
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
Пример #26
0
// no one needs teh intersection point for the aabb,
// it's just a boolean check
//bool intersects( const Ray& ray, Intersection* intn ) ;
bool AABB::intersectsRay( const Ray& ray, Vector3f& pt ) const
{
  bool rayStartInside = containsPoint( ray.start ) ;

  // Rays starting and ending in an octree node must be considered
  // to hit the node.
  // This is the behavior you USUALLY want.
  if( rayStartInside && containsPoint( ray.end ) )
  {
    pt=ray.start;
    return true ; 
  }
  
  // the algorithm says, find 3 t's,
  Vector3f t ;

  if( rayStartInside )
  {
    for( int i = 0 ; i < 3 ; i++ )
    {
      if( ray.dir.elts[i] > 0 ) // RAY GOING + and we are inside the box.. CULL BACK FACE (mins)
      {
        t.elts[i] = ( max.elts[i] - ray.start.elts[i] ) / ray.dir.elts[i] ;
      }
      else // RAY GOING - and we are inside the box.. so cull the MAXES
      {
        t.elts[i] = ( min.elts[i] - ray.start.elts[i] ) / ray.dir.elts[i] ;
      }
    }
  }
  else
  {
    // LARGEST t is the only only we need to test if it's on the face.
    for( int i = 0 ; i < 3 ; i++ )
    {
      if( ray.dir.elts[i] > 0 ) // RAY GOING +.. CULL BACK FACE (maxes)
      {
        //    ^ |
        //   /  |
        //  *   |
        // -----+-------
        //      |
        // A ray with ray.dir.x>0 means IT WOULD HIT MINFACES FIRST.
        // __BUT__, if the ray STARTS AFTER THE MINFACE (ray.start.x > min.x)
        // THEN THE RAY STARTED INSIDE THE BOX.  to still detect the intersection
        // you would use the MAX FACE in that case
        t.elts[i] = ( min.elts[i] - ray.start.elts[i] ) / ray.dir.elts[i] ;
      }
      else // RAY GOING -.. so cull the MINS
      {
        // IF RAY LEFT OF MAXFACE, USE MINFACE
        t.elts[i] = ( max.elts[i] - ray.start.elts[i] ) / ray.dir.elts[i] ;
      }
      
      // The above code works fine for when you are between min/max in 2 dimensions or less,
      // because the detected hits for those dimensions will be BEHIND THE RAY START
      // so it's kind of like "using a loophole".. if you are between max/min in 2 dimensions,
      // THEN YOU CAN ONLY HIT THE BOX IN THE DIMENSION YOU ARE __NOT__ between max/min in,
      // unless you're already inside the box, which is hte cases handled above.
    }
  }
  
  // The right answer will be 
  int tIndex ;
  if( rayStartInside )  tIndex = t.minIndex() ;
  else  tIndex = t.maxIndex() ;
  
  if( isBetweenOrdered( t.elts[tIndex], 0, ray.len ) )
  {
    pt = ray.at( t.elts[tIndex] ) ;

    // check it's in the box in other 2 dimensions
    int o1 = OTHERAXIS1(tIndex) ; // i=0: o1=1, o2=2, i=1: o1=2,o2=0 etc.
    int o2 = OTHERAXIS2(tIndex) ;

    return isBetweenOrdered( pt.elts[o1], min.elts[o1], max.elts[o1] ) &&
           isBetweenOrdered( pt.elts[o2], min.elts[o2], max.elts[o2] ) ;
  }
  
  return false ;
}