예제 #1
0
bool Sphere::intersectLocal(ray& r, isect& i) const
{
    Vec3d v = -r.getPosition();
    double b = v * r.getDirection();
    double discriminant = b*b - v*v + 1;

    if( discriminant < 0.0 ) {
        return false;
    }

    discriminant = sqrt( discriminant );
    double t2 = b + discriminant;

    if( t2 <= RAY_EPSILON ) {
        return false;
    }

    i.obj = this;
    i.setMaterial(this->getMaterial());

    double t1 = b - discriminant;

    if( t1 > RAY_EPSILON ) {
        i.t = t1;
        i.N = r.at( t1 );
        i.N.normalize();
    } else {
        i.t = t2;
        i.N = r.at( t2 );
        i.N.normalize();
    }

    return true;
}
예제 #2
0
// Intersect ray r with the triangle abc.  If it hits returns true,
// and puts the t parameter, barycentric coordinates, normal, object id,
// and object material in the isect object
bool TrimeshFace::intersectLocal( const ray& r, isect& i ) const
{
  const Vec3d& a = parent->vertices[ids[0]];
  const Vec3d& b = parent->vertices[ids[1]];
  const Vec3d& c = parent->vertices[ids[2]];

  // tangent vectors
  Vec3d t1 = b - a;
  Vec3d t2 = c - a;
  
  Vec3d n = crossProd(t1,t2);

  double D = -n*a;

  // if the surface is parallel to the ray there is no intersection
  if(r.getDirection()*n == 0)
  {
    return false;
  }  

  double t = -(n*r.getPosition() + D)/(n*r.getDirection() );
  if (t <= RAY_EPSILON)
    return false;

  // point of intersection with the same plane (doesn't mean intersection with triangle) p(t)=p+t*d
  Vec3d p = r.at(t);

  // triangle area
  double A = n.length()/2.0;

  // barycentric coords
  double wa = crossProd(c-b, p-b).length() / (2.0*A);
  double wb = crossProd(a-c, p-c).length() / (2.0*A);
  double wc = crossProd(b-a, p-a).length() / (2.0*A);

  if((wa >= 0.0) && (wb >= 0.0) && (wc >= 0.0) && (wa+wb+wc-1.0 <= 0.00001)) {
    i.setT(t);
    i.setBary(wa, wb, wc);
    if (parent->normals.size() == 0) {
      i.setN(n);
    } else {
      Vec3d inter_n = wa*parent->normals[ids[0]] + wb*parent->normals[ids[1]]
                    + wc*parent->normals[ids[2]];
      inter_n.normalize();
      i.setN(inter_n);
    }
    i.setObject(this);
    if (parent->materials.size() == 0) {
      i.setMaterial(this->getMaterial() );
    } else {
      Material inter_m = wa*(*parent->materials[ids[0]]);
      inter_m += wb*(*parent->materials[ids[1]]);
      inter_m += wc*(*parent->materials[ids[2]]);
      i.setMaterial(inter_m);
    }
    return true;
  }

  return false;
}
예제 #3
0
//Test
bool Square::intersectLocal(ray& r, isect& i) const
{
	Vec3d p = r.getPosition();
	Vec3d d = r.getDirection();

	if( d[2] == 0.0 ) {
		return false;
	}

	double t = -p[2]/d[2];

	if( t <= RAY_EPSILON ) {
		return false;
	}

	Vec3d P = r.at( t );

	if( P[0] < -0.5 || P[0] > 0.5 ) {	
		return false;
	}

	if( P[1] < -0.5 || P[1] > 0.5 ) {	
		return false;
	}

	i.obj = this;
	i.setMaterial(this->getMaterial());
	i.t = t;
	if( d[2] > 0.0 ) {
		i.N = Vec3d( 0.0, 0.0, -1.0 );
	} else {
		i.N = Vec3d( 0.0, 0.0, 1.0 );
	}

    i.setUVCoordinates( Vec2d(P[0] + 0.5, P[1] + 0.5) );
	return true;
}
예제 #4
0
// Get any intersection with an object.  Return information about the 
// intersection through the reference parameter.
bool Scene::intersect( const ray& r, isect& i ) const {
	double tmin = 0.0;
	double tmax = 0.0;
	bool have_one = false;
	typedef vector<Geometry*>::const_iterator iter;
	for( iter j = objects.begin(); j != objects.end(); ++j ) {
		isect cur;
		if( (*j)->intersect( r, cur ) ) {
			if( !have_one || (cur.t < i.t) ) {
				i = cur;
				have_one = true;
			}
		}
	}
	if( !have_one ) i.setT(1000.0);
	// if debugging,
	intersectCache.push_back( std::make_pair(r,i) );
	return have_one;
}
예제 #5
0
//Test
// now the object is in the local coordinate rather than the global
bool Square::intersectLocal( const ray& r, isect& i ) const
{
	// get the parameters of the ray 
	Vec3d p = r.getPosition();
	Vec3d d = r.getDirection();

	// if the ray is perpendicular to the z-axis
	if( d[2] == 0.0 ) {
		return false;
	}

	// calculate the value of t
	double t = -p[2]/d[2];

	// if the intersection is too close to the source
	// then we don't count that as a intersection
	if( t <= RAY_EPSILON ) {
		return false;
	}

	
	Vec3d P = r.at( t );

	if( P[0] < -0.5 || P[0] > 0.5 ) {	
		return false;
	}

	if( P[1] < -0.5 || P[1] > 0.5 ) {	
		return false;
	}

	i.obj = this;
	i.t = t;
	if( d[2] > 0.0 ) {
		i.N = Vec3d( 0.0, 0.0, -1.0 );
	} else {
		i.N = Vec3d( 0.0, 0.0, 1.0 );
	}

    i.setUVCoordinates( Vec2d(P[0] + 0.5, P[1] + 0.5) );
	return true;
}
예제 #6
0
bool Trimesh::intersectLocal(const ray&r, isect&i) const
{
  double tmin = 0.0;
  double tmax = 0.0;
  typedef Faces::const_iterator iter;
  bool have_one = false;
  for( iter j = faces.begin(); j != faces.end(); ++j ) {
    isect cur;
    if( (*j)->intersectLocal( r, cur ) )
    {
      if( !have_one || (cur.t < i.t) )
      {
        i = cur;
        have_one = true;
      }
    }
  }
  if( !have_one ) i.setT(1000.0);
  return have_one;
}
예제 #7
0
// Apply the phong model to this point on the surface of the object, returning
// the color of that point.
Vec3d Material::shade(Scene *scene, const ray& r, const isect& i) const
{
  const Material& m = i.getMaterial();

  Vec3d I = m.ke(i) + prod(m.ka(i) ,scene->ambient());
  Vec3d R = 2*(-r.getDirection() * i.N)*i.N +r.getDirection();

  for ( vector<Light*>::const_iterator litr = scene->beginLights(); 
  		litr != scene->endLights(); 
  		++litr )
  {
  		Vec3d atten = (*litr)->distanceAttenuation(r.at(i.t)) * (*litr)->shadowAttenuation(r,r.at(i.t));
      I += prod(atten,(m.kd(i)*max((i.N * (*litr)->getDirection(r.at(i.t)) ), 0.0) + m.ks(i) * max(((scene->getCamera().getEye() - r.at(i.t)) *R),0.0)));
  }

  // You will need to call both the distanceAttenuation() and
  // shadowAttenuation() methods for each light source in order to
  // compute shadows and light falloff.

  return I;
}
예제 #8
0
vec3f RayTracer::traceRay( Scene *scene, const ray& r, 
	const vec3f& thresh, int depth, isect& i, vector<const SceneObject*>& stack )
{
	if( depth>=0
		&& thresh[0] > threshold - RAY_EPSILON && thresh[1] > threshold - RAY_EPSILON && thresh[2] > threshold - RAY_EPSILON
		&& scene->intersect( r, i ) ) {
		// YOUR CODE HERE

		// An intersection occured!  We've got work to do.  For now,
		// this code gets the material for the surface that was intersected,
		// and asks that material to provide a color for the ray.  

		// This is a great place to insert code for recursive ray tracing.
		// Instead of just returning the result of shade(), add some
		// more steps: add in the contributions from reflected and refracted
		// rays.
		
		const Material& m = i.getMaterial();
		vec3f color = m.shade(scene, r, i);
		//calculate the reflected ray
		vec3f d = r.getDirection();
		vec3f position = r.at(i.t);
		vec3f direction = d - 2 * i.N * d.dot(i.N);
		ray newray(position, direction);
		if(!m.kr.iszero()) {
			vec3f reflect = m.kr.multiply(traceRay(scene, newray, thresh.multiply(m.kr), depth-1, stack).clamp());
			color += reflect;
		}

		//calculate the refracted ray
		double ref_ratio;
		double sin_ang = d.cross(i.N).length();
		vec3f N = i.N;
		//Decide going in or out
		const SceneObject *mi = NULL, *mt = NULL;
		int stack_idx = -1;
		vector<const SceneObject*>::reverse_iterator itr;
		//1 use the normal to decide whether to go in or out
		//0: travel through, 1: in, 2: out
		char travel = 0;
		if(i.N.dot(d) <= -RAY_EPSILON) {
			//from outer surface in
			//test whether the object has two face
			ray test_ray(r.at(i.t) + d * 2 * RAY_EPSILON, -d);
			isect test_i;
			if(i.obj->intersect(r, test_i) && test_i.N.dot(N) > -RAY_EPSILON) {
				//has interior
				travel = 1;
			}
		}
		else {
			travel = 2;
		}

		if(travel == 1) {
			if(!stack.empty()) {
				mi = stack.back();
			}
			mt = i.obj;
			stack.push_back(mt);
		}
		else if(travel == 2) {
			//if it is in our stack, then we must pop it
			for(itr = stack.rbegin(); itr != stack.rend(); ++itr) {
				if(*itr == i.obj) {
					mi = *itr;
					vector<const SceneObject*>::iterator ii = itr.base() - 1;
					stack_idx = ii - stack.begin();
					stack.erase(ii);
					break;
				}
			}
			if(!stack.empty()) {
				mt = stack.back();
			}
		}

		if(N.dot(d) >= RAY_EPSILON) {
			N = -N;
		}
		
		ref_ratio = (mi?(mi->getMaterial().index):1.0) / (mt?(mt->getMaterial().index):1.0);

		if(!m.kt.iszero() && (ref_ratio < 1.0 + RAY_EPSILON || sin_ang < 1.0 / ref_ratio + RAY_EPSILON)) {
			//No total internal reflection
			//We do refraction now
			double c = N.dot(-d);
			direction = (ref_ratio * c - sqrt(1 - ref_ratio * ref_ratio * (1 - c * c))) * N + ref_ratio * d;
			newray = ray(position, direction);
			vec3f refraction = m.kt.multiply(traceRay(scene, newray, thresh.multiply(m.kt), depth-1, stack).clamp());
			color += refraction;
		}

		if(travel == 1) {
			stack.pop_back();
		}
		else if(travel == 2) {
			if(mi) {
				stack.insert(stack.begin() + stack_idx, mi);
			}
		}

		return color;

	} else {
		// No intersection.  This ray travels to infinity, so we color
		// it according to the background color, which in this (simple) case
		// is just black.
		if(m_bBackground && bg) {
			double u, v;
			angleToSphere(r.getDirection(), u, v);
			//Scale to [0, 1];
			u /= 2 * M_PI;
			v /= M_PI;
			int tx = int(u * bg_width), ty = bg_height - int(v * bg_height);
			return vec3f(bg[3 * (ty * bg_width + tx)] / 255.0, bg[3 * (ty * bg_width + tx) + 1] / 255.0, bg[3 * (ty * bg_width + tx) + 2] / 255.0);
		}
		else {
			return vec3f( 0.0, 0.0, 0.0 );
		}
	}
}
예제 #9
0
bool Box::intersectLocal( const ray& r, isect& i ) const
{

        Vec3d p = r.getPosition();
        Vec3d d = r.getDirection();

        int it;
        double x, y, t, bestT; 
        int mod0, mod1, mod2, bestIndex;

        bestT = HUGE_DOUBLE;
        bestIndex = -1;

        for(it=0; it<6; it++){ 
                mod0 = it%3;

                if(d[mod0] == 0){
                        continue;
                }
                
                t = ((it/3) - 0.5 - p[mod0]) / d[mod0];                 

                if(t < RAY_EPSILON || t > bestT){
                        continue;
                }

                mod1 = (it+1)%3;
                mod2 = (it+2)%3;
                x = p[mod1]+t*d[mod1];
                y = p[mod2]+t*d[mod2];
                
                if(     x<=0.5 && x>=-0.5 &&
                        y<=0.5 && y>=-0.5)
                {
                        if(bestT > t){
                                bestT = t;
                                bestIndex = it;
                        }
                }                       
                
        }

        if(bestIndex < 0) return false;
        
        i.setT(bestT);
        i.setObject(this);

		Vec3d intersect_point = r.at(i.t);

		int i1 = (bestIndex + 1) % 3;
		int i2 = (bestIndex + 2) % 3;

        if(bestIndex < 3)
		{
                i.setN(Vec3d(-double(bestIndex == 0), -double(bestIndex == 1), -double(bestIndex == 2)));
				i.setUVCoordinates( Vec2d(	0.5 - intersect_point[ min(i1, i2) ], 
											0.5 + intersect_point[ max(i1, i2) ] ) );
		}
        else
		{
                i.setN(Vec3d(double(bestIndex==3), double(bestIndex == 4), double(bestIndex == 5)));
				i.setUVCoordinates( Vec2d(	0.5 + intersect_point[ min(i1, i2) ],
											0.5 + intersect_point[ max(i1, i2) ] ) );

		}
        return true;

}
예제 #10
0
bool Cone::intersectLocal(ray& r, isect& i) const
{
	bool ret = false;
	const int x = 0, y = 1, z = 2;	// For the dumb array indexes for the vectors

	Vec3d normal;
	
	Vec3d R0 = r.getPosition();
	Vec3d Rd = r.getDirection();
	double pz = R0[2];
	double dz = Rd[2];
	
	double a = Rd[x]*Rd[x] + Rd[y]*Rd[y] - beta_squared * Rd[z]*Rd[z];

	if( a == 0.0) return false;		// We're in the x-y plane, no intersection

	double b = 2 * (R0[x]*Rd[x] + R0[y]*Rd[y] - beta_squared * ((R0[z] + gamma) * Rd[z]));
	double c = -beta_squared*(gamma + R0[z])*(gamma + R0[z]) + R0[x] * R0[x] + R0[y] * R0[y];

	double discriminant = b * b - 4 * a * c;
	
	double farRoot, nearRoot, theRoot = RAY_EPSILON;
	bool farGood, nearGood;
	
	if(discriminant <= 0) return false;		// No intersection

	discriminant = sqrt(discriminant);

	// We have two roots, so calculate them
	nearRoot = (-b + discriminant) / ( 2 * a );
	farRoot = (-b - discriminant) / ( 2 * a );
	
	// This is confusing, but it figures out which
	// root is closer and puts into theRoot
	nearGood = isGoodRoot(r.at(nearRoot));
	if(nearGood && (nearRoot > theRoot))
	{
		theRoot = nearRoot;
		normal = Vec3d((r.at(theRoot))[x], (r.at(theRoot))[y], -2.0 * beta_squared * (r.at(theRoot)[z] + gamma));
	}
	farGood = isGoodRoot(r.at(farRoot));
	if(farGood && ( (nearGood && farRoot < theRoot) || farRoot > RAY_EPSILON) ) 
	{
		theRoot = farRoot;
		normal = Vec3d((r.at(theRoot))[x], (r.at(theRoot))[y], -2.0 * beta_squared * (r.at(theRoot)[z] + gamma));
	}

	// In case we are _inside_ the _uncapped_ cone, we need to flip the normal.
	// Essentially, the cone in this case is a double-sided surface
	// and has _2_ normals
	if( !capped && (normal * r.getDirection()) > 0 )
		normal = -normal;

	// These are to help with finding caps
	double t1 = (-pz)/dz;
	double t2 = (height-pz)/dz;
	
	Vec3d p( r.at( t1 ) );
	
	if(capped) {
		if( p[0]*p[0] + p[1]*p[1] <=  b_radius*b_radius)
		{
			if(t1 < theRoot && t1 > RAY_EPSILON)
			{
				theRoot = t1;
				if( dz > 0.0 ) {
					// Intersection with cap at z = 0.
					normal = Vec3d( 0.0, 0.0, -1.0 );
				} else {
					normal = Vec3d( 0.0, 0.0, 1.0 );
				}
			}
		}
		Vec3d q( r.at( t2 ) );
		if( q[0]*q[0] + q[1]*q[1] <=  t_radius*t_radius)
		{
			if(t2 < theRoot && t2 > RAY_EPSILON)
			{
				theRoot = t2;
				if( dz > 0.0 ) {
					// Intersection with interior of cap at z = 1.
					normal = Vec3d( 0.0, 0.0, 1.0 );
				} else {
					normal = Vec3d( 0.0, 0.0, -1.0 );
				}
			}
		}
	}
	
	if(theRoot <= RAY_EPSILON) return false;
	
	i.setT(theRoot);
	normal.normalize();
	i.setN(normal);
	i.obj = this;
	i.setMaterial(this->getMaterial());
	return true;
	
	return ret;
}