Example #1
0
bool Sphere::intersect(const Ray& ray, Hit& hit) const
{
  float a = (ray.direction.normalized()).dot(ray.direction.normalized());
  float b = 2.0f * (ray.direction.normalized()).dot(ray.origin - mCenter);
  float c = (ray.origin - mCenter).dot(ray.origin - mCenter) - (mRadius * mRadius);

  float discriminant = b * b - 4 * a * c;

  if (discriminant > 0) {

    float s1 = (- b + sqrtf(discriminant)) / 2 * a;
    float s2 = (- b - sqrtf(discriminant)) / 2 * a;

    // Tester le chemin le plus court ?
    if (s1 > 0) {
      if (s1 < s2 && hit.t() > s1) {
        hit.setT(s1);
	hit.setIntersection(ray.direction * s1);
      }
    }

    if (s2 > 0) {
      if (s2 < s1 && hit.t() > s2) {
        hit.setT(s2);
	hit.setIntersection(ray.direction * s2);
      }
    }
  }
  else if (discriminant = 0) {
    float s = - b / 2 * a;

    if (hit.t() > s) {
      hit.setT(s);
      hit.setIntersection(ray.direction * s);
    }
  }
  else {
    return false;
  }

  return true;
}
Example #2
0
bool Cylindre::intersect(const Ray& ray, Hit& hit) const
{

	/*bool top = topdisque()->intersect(ray,hit);
	bool bottom = bottomdisque()->intersect(ray,hit);
	return top || bottom;
*/
	// Determination de l'intersection

	// J'appelle I le point intersection s'il existe, O le point d'origine du rayon, D sa direction, R1 et R1 les rayons du cylindre, h sa hauteur
	// C l'origine du repere basé à la base du cylindre

	// on place le ray dans le répère associé au cylindre
	Ray ray_associe_cylindre(frame().coordinatesOf(ray.start()), frame().transformOf(ray.direction()));
	
	Vec I;
	Vec O = ray_associe_cylindre.start();
	const Vec& D = ray_associe_cylindre.direction();
	float R1,R2;

	
	R1 = bottomradius_;
	R2 = topradius_;
	

	float h = height_;

#ifdef DEBUG_INTERSEC
	std::cout << "TENTATIVE d'intersection du rayon :\n" << ray << "avec le cylindre\n" << *this << std::endl;
#endif
	
#ifdef DEBUG_INTERSEC
	std::cout << "rayon dans l'espace du cylindre : \n" << ray_associe_cylindre << std::endl;
#endif


// on vérifie que le ray pointe vers le cylindre
	if ( (frame().position() - ray.start())*ray.direction() < 0){
		
#ifdef DEBUG_INTERSEC
		std::cout << "PAS D'INTERSECTION : direction pointant en arrière" << std::endl;
#endif
		return false;
	}




	// On se place dans les coordonnées du cylindre pour tous les calculs et on a les équations suivantes :
	// Ix = Ox + tDx
	// Iy = Oy + tDy
	// Iz = Oz + tDz
	// Ix² + Iy² = (Iz/h*(R2-R1)+R1)² <=> Ix² + Iy² = Iz²/h²*(R2-R1)²   +  R1² +  2*(R2-R1)*R1*Iz/h

	// on remplace Ix, Iy et Iz dans la 4e equation pour obtenir une equation du 2nd degré en t
	// (Dx² + Dy² - Dz²*(R2-R1)²/h²)*t² + (2OxDx + 	2OyDy - (2OzDz)/h²*(R2-R1)² - 2Dz*(R2-R1)/h)*t + (Ox²+Oy²-Oz²/h²*(R2-R1)²-R1²-2*(R2-R1)*Oz/h = 0

	float a, b ,c;
	if (R1>R2){
		a = D.x*D.x + D.y*D.y -D.z*D.z*(R2-R1)*(R2-R1)/(h*h);
		b = 2*O.x*D.x+2*O.y*D.y - (2*O.z*D.z)*(R2-R1)*(R2-R1)/(h*h) - 2*D.z*R1*(R2-R1)/h;
		c = O.x*O.x+O.y*O.y-O.z*O.z*(R2-R1)*(R2-R1)/(h*h)-2*R1*(R2-R1)*O.z/h -R1*R1;
	}else
	{
		a = D.x*D.x + D.y*D.y -D.z*D.z*(R2-R1)*(R2-R1)/(h*h);
		b = 2*O.x*D.x+2*O.y*D.y - (2*O.z*D.z)*(R2-R1)*(R2-R1)/(h*h) - 2*D.z*R1*(R2-R1)/h;
		c = O.x*O.x+O.y*O.y-O.z*O.z*(R2-R1)*(R2-R1)/(h*h)-2*R1*(R2-R1)*O.z/h -R1*R1;
	
	}
	float delta = b*b-4*a*c;

#ifdef DEBUG_INTERSEC
		cout << "a : " << a << endl << "b : " << b << endl << "c :" << c << endl << "delta : " << delta << endl;
#endif

	

	if (delta < 0)
	{
#ifdef DEBUG_INTERSEC
		cout << "delta est négatif, il n'y a pas de solution" << endl;
#endif
		// pas de solution, il faut vérifier maintenant si on intersecte les disques supérieur ou inférieur
		bool inter_topdisque = topdisque_->intersect(ray,hit);
		bool inter_bottomdisque = bottomdisque_->intersect(ray,hit);
		return (inter_topdisque || inter_bottomdisque);
	}

	
	if (delta > 0)
	{
#ifdef DEBUG_INTERSEC
		cout << "delta est positif, il y a deux solutions" << endl;
#endif
		// deux solutions, le rayon entre et sort par la robe du cylindre
		float t;
		if (a == 0)
		{
			t = -c/b;
		}
		else{
			t = (-b-sqrt(delta))/(2*a);
		}	

		if ( t < 0 ){
#ifdef DEBUG_INTERSEC
			cout << "t < 0 " << endl;
			cout << "PAS D'INTERSECTION avec la robe du cylindre" << endl;
#endif
			return false;
		}
		
		// on calcule le point d'intersection	
		I.x = O.x + t*D.x;
		I.y = O.y + t*D.y;
		I.z = O.z + t*D.z;

#ifdef DEBUG_INTERSEC
		cout <<"I : " << I << endl;
#endif
	

		if (I.z < 0 || I.z > h)
		{
#ifdef DEBUG_INTERSEC
		cout << "t vaut : " << t << endl << "I.z vaut : " << I.z << endl;
		//cout << "PAS D'INTERSECTION avec la robe du cylindre" << endl;
#endif
		bool top = topdisque()->intersect(ray,hit);
		bool bottom = bottomdisque()->intersect(ray,hit);
		return top || bottom;
		}
		

		// on calcule la normale en ce point, dans les coordonnées du cylindre toujours

		float theta = 0;
		Vec normale;
		normale.x = I.x;
		normale.y = I.y;
		normale.z = 0;

		if (normale.norm() == 0)
		{
			cout << "la norme de la normale est nulle" << endl;
		}
	
		if (R1>=R2){
			theta = atan((R1-R2)/h);
			normale = normale * (1/normale.norm())*cos(theta);
			normale = normale + Vec(0,0,sin(theta));
		}
		else
		{
			theta = atan(h/(R2-R1));
			normale = normale * (1/normale.norm())*sin(theta);
			normale = normale - Vec(0,0,cos(theta));
		}
	
		if ( hit.time() > t){
			hit.setTime(t);
			Vec locale = frame().inverseTransformOf(I);
			hit.setIntersection(locale);
			hit.setNormal(frame().inverseTransformOf(normale));
			hit.setMaterial(material());
			computeUV(hit);
#ifdef DEBUG_INTERSEC
			displayIntersectionDebug(ray,hit,O,I,t);
#endif
			topdisque()->intersect(ray,hit);
			bottomdisque()->intersect(ray,hit);
			return true;
		}else{
			return false;
		}

	}
	
	if (delta ==0)
	{
#ifdef DEBUG_INTERSEC
		cout << "delta est nul, il y a une solution" << endl;
#endif
		// une solution, regarder si on intersecte les disques et comparer les time obtenu pour trouver le plus petit
		float t;
		if (a==0)
		{
			t = -c/b;
		} 
		else 
		{
			t=(-b/(2*a));
		}
		

		if (t<0)
		{
			//l'objet est derrière moi
#ifdef DEBUG_INTERSEC
			cout << "On est à l'intérieur de l'objet" << endl; 
#endif
			return false;
		}
		// on calcule le point d'intersection	
		I.x = O.x + t*D.x;
		I.y = O.y + t*D.y;
		I.z = O.z + t*D.z;

		// on calcule la normale en ce point, dans les coordonnées du cylindre toujours

		float theta;
		Vec normale;
		theta = atan((R1-R2)/h);
		normale.x = I.x;
		normale.y = I.y;
		normale.z = 0;

		if (normale.norm() == 0)
		{
			cout << "la norme de la normale est nulle" << endl;
		}

		normale = normale * (1/normale.norm())*cos(theta);

		normale = normale + Vec(0,0,sin(theta));

		if ( hit.time() > t){
			hit.setTime(t);
			hit.setIntersection(frame().inverseCoordinatesOf(I));
			hit.setNormal(frame().inverseCoordinatesOf(normale));
			hit.setMaterial(material());
			computeUV(hit);
#ifdef DEBUG_INTERSEC
			displayIntersectionDebug(ray,hit,O,I,t);
#endif
			topdisque()->intersect(ray,hit);
			bottomdisque()->intersect(ray,hit);
			return true;
		}else{
			return false;
		}

		
	}	  	

#ifdef DEBUG
	cerr << "Erreur lors du calcul de l'intersection d'un objet avec un rayon" << endl;
#endif
	return false;

}
Example #3
0
bool Plane::intersect(const Ray& ray, Hit& hit) const
{
#ifdef DEBUG_INTERSEC
	std::cout << "TENTATIVE d'intersection du rayon :\n" << ray << "avec le plan\n" << *this << std::endl;
#endif
	// on place le ray dans le répère associé au plan
	Ray ray_associe_plan(frame().coordinatesOf(ray.start()),
			     frame().transformOf(ray.direction()));
	
#ifdef DEBUG_INTERSEC
	std::cout << "rayon dans l'espace du plan : \n" << ray_associe_plan << std::endl;
#endif
	// on vérifie que le ray pointe vers le plan
	if ( ( ray_associe_plan.start().z <= 0 && ray_associe_plan.direction().z <= 0 )
	     || 
	     ( ray_associe_plan.start().z >= 0 && ray_associe_plan.direction().z >= 0 )
		)
	{
#ifdef DEBUG_INTERSEC
		std::cout << "PAS D'INTERSECTION" << std::endl;
#endif
		return false;
	}
	// on détermine le t de l'intersection dans la formule
	// zstart + t*zdir = 0
	float t = -ray_associe_plan.start().z/ray_associe_plan.direction().z;

	if ( hit.time() < t ){
#ifdef DEBUG_INTERSEC
		std::cout << "PAS D'INTERSECTION : " << t << " > " << hit.time() << std::endl;
#endif
		return false;
	}


#ifdef DEBUG_INTERSEC
	std::cout << "Intersection au temps : " << t << std::endl;
#endif
	// Calcul des coordonnées de l'intersection dans le plan et
	// rejet si on dépasse
	float u,v;
	u = ray_associe_plan.start().x+t*ray_associe_plan.direction().x;
	if ( width_ > 0 && (u > width_/2.0 || u < -width_/2.0) ){
#ifdef DEBUG_INTERSEC
		std::cout << "PAS D'INTERSECTION : u = " << u << ", width = " << width_ << std::endl;
#endif
		return false;
	}
	v = ray_associe_plan.start().y+t*ray_associe_plan.direction().y;
	if ( height_ > 0 && (v > height_/2.0 || v < -height_/2.0) ){
#ifdef DEBUG_INTERSEC
		std::cout << "PAS D'INTERSECTION : v = " << v << ", height = " << height_ << std::endl;
#endif
		return false;
	}
	qglviewer::Vec inter_plan = qglviewer::Vec(u,v,0);

#ifdef DEBUG_INTERSEC
	std::cout << "INTERSECTION d'un rayon avec le plan \n"<< *this << "\tau temps : " << t << std::endl;
#endif
 	hit.setTime(t);
	hit.setIntersection(frame().inverseCoordinatesOf(inter_plan));
	if ( ray_associe_plan.start().z <= 0 ){
		hit.setNormal(frame().inverseTransformOf(qglviewer::Vec(0,0,-1)));
	}else{
		hit.setNormal(frame().inverseTransformOf(qglviewer::Vec(0,0,1)));		
	}
	hit.setMaterial(material());
	
	// On envoie les coordonnées de la texture (entre 0 et 1 si la
	// partie est finie)
	if ( width_ > 0 ){
		u = u/width_ + 0.5;
	}
	if ( height_ > 0 ){
		v = v/height_ + 0.5;
	}
#ifdef DEBUG_INTERSEC
	std::cout << "Coordonnées de textures ("<< u << "," << v << ")" << std::endl;
#endif
	hit.setCoord(u,v);
	
	return true;
#ifdef DEBUG
	cerr << "Erreur lors du calcul de l'intersection d'un objet avec un rayon" << endl;
#endif
	return false;
}