gKitGL
Triangle.h
00001 
00002 #ifndef _GK_TRIANGLE_H
00003 #define _GK_TRIANGLE_H
00004 
00005 #include "Geometry.h"
00006 #include "Transform.h"
00007 #include "Sampler.h"
00008 
00009 namespace gk {
00010 
00011 
00012 //! representation d'un triangle 'geometrique'.
00013 struct Triangle
00014 {
00015     Point a, b, c;
00016     float area;
00017     
00018     //! constructeur par defaut.
00019     Triangle( ) {}
00020     
00021     //! construit un triangle connaissant ses 3 sommets.
00022     Triangle( const Point& a, const Point& b, const Point& c )
00023         :
00024         a(a),  b(b), c(c),
00025         area(getArea())
00026     {}
00027     
00028     //! destructeur.
00029     ~Triangle( ) {}
00030     
00031     //! calcule l'aire du triangle.
00032     float getArea( ) const
00033     {
00034         Vector ab(a, b);
00035         Vector ac(a, c);
00036         
00037         return .5f * Cross(ab, ac).Length();
00038     }
00039     
00040     //! calcule la normale du triangle.
00041     Normal getNormal( ) const
00042     {
00043         Vector ab(a, b);
00044         Vector ac(a, c);
00045         if(area < 0.000001f)
00046             return Normal();
00047         
00048         return Normal( Normalize(Cross(ab, ac)) );
00049     }
00050     
00051     //! changement de repere du vecteur 'v' global, renvoie le vecteur dans le repere local (bitangent, tangent, normal).
00052     Vector local( const Vector& v ) const
00053     {
00054         // construit le changement de repere
00055         Vector t= Normalize( Vector(a, b) );
00056         Vector n= Normalize( Cross(t, Vector(a, c)) );
00057         Vector b= Cross(t, n);
00058         
00059         // repere de l'objet
00060         return Vector( Dot(v, b), Dot(v, t), Dot(v, n) );
00061     }
00062 
00063     //! changement de repere du vecteur 'v' local, renvoie le vecteur dans le repere global.
00064     Vector world( const Vector& v ) const
00065     {
00066         // construit le changement de repere
00067         Vector t= Normalize( Vector(a, b) );
00068         Vector n= Normalize( Cross(t, Vector(a, c)) );
00069         Vector b= Cross(t, n);
00070         
00071         // repere global
00072         return v.x * b + v.y * t + v.z * n;
00073     }
00074     
00075     //! calcule la boite englobante du triangle.
00076     BBox getBBox( ) const
00077     {
00078         BBox bbox(a, b);
00079         bbox.Union(c);
00080         return bbox;
00081     }
00082     
00083     //! renvoie un triangle transforme par 't'.
00084     Triangle transform( const Transform& t )
00085     {
00086         return Triangle( t(a), t(b), t(c) );
00087     }
00088     
00089     //! intersection avec un rayon.
00090     //! renvoie faux s'il n'y a pas d'intersection valide, une intersection peut exister mais peut ne pas se trouver dans l'intervalle [0 htmax] du rayon. \n
00091     //! renvoie vrai + les coordonnees barycentriques (ru, rv) du point d'intersection + sa position le long du rayon (rt). \n
00092     //! convention barycentrique : t(u, v)= (1 - u - v) * a + u * b + v * c \n
00093     //! utiliser Mesh::getUVNormal() et Mesh::getUVTexCoord() pour interpoler les attributs du point d'intersection. \n
00094     //! ou PNTriangle::getUVNormal(). \n
00095     
00096     
00097     /*! le parametre  htmax permet de trouver tres facilement l'intersection la plus proche de l'origine du rayon.
00098     \code
00099         float t= ray.tmax;      // ou t= HUGE_VAL; la plus grande distance le long du rayon.
00100         // rechercher le triangle le plus proche de l'origine du rayon
00101         for(int i= 0; i < n; i++)
00102         {
00103             float rt;
00104             float ru, rv;
00105             if(triangle[i].Intersect(ray, t, rt, ru, rv))
00106                 t= rt;
00107         }
00108     \endcode
00109     */
00110     
00111     bool Intersect( const Ray &ray, const float htmax, 
00112         float &rt, float &ru, float&rv ) const
00113     {
00114         /* begin calculating determinant - also used to calculate U parameter */
00115         Vector ac(a, c);
00116         const Vector pvec= Cross(ray.d, ac);
00117         
00118         /* if determinant is near zero, ray lies in plane of triangle */
00119         Vector ab(a, b);
00120         const float det= Dot(ab, pvec);
00121         if (det > -EPSILON && det < EPSILON)
00122             return false;
00123         
00124         const float inv_det= 1.0f / det;
00125         
00126         /* calculate distance from vert0 to ray origin */
00127         const Vector tvec(a, ray.o);
00128         
00129         /* calculate U parameter and test bounds */
00130         const float u= Dot(tvec, pvec) * inv_det;
00131         if(u < 0.0f || u > 1.0f)
00132             return false;
00133         
00134         /* prepare to test V parameter */
00135         const Vector qvec= Cross(tvec, ab);
00136         
00137         /* calculate V parameter and test bounds */
00138         const float v= Dot(ray.d, qvec) * inv_det;
00139         if(v < 0.0f || u + v > 1.0f)
00140             return false;
00141         
00142         /* calculate t, ray intersects triangle */
00143         rt= Dot(ac, qvec) * inv_det;
00144         ru= u;
00145         rv= v;
00146         
00147         // ne renvoie vrai que si l'intersection est valide (comprise entre tmin et tmax du rayon)
00148         //~ return (rt < htmax && rt > ray.tmin);
00149         return (rt < htmax && rt > RAY_EPSILON);
00150     }
00151     
00152     //! renvoie un point a l'interieur du triangle connaissant ses coordonnees barycentriques.
00153     //! convention p(u, v)= (1 - u - v) * a + u * b + v * c
00154     Point getUVPoint( const float u, const float v ) const
00155     {
00156         const float w= 1.f - u - v;
00157         return a * w + b * u + c * v;
00158     }
00159 
00160     //! choisit un point aleatoirement a la surface du triangle et renvoie la probabilite de l'avoir choisi.
00161     //! \param u1, u2 valeurs aleatoires entre [0 .. 1] utilisées pour le tirage aleatoire.
00162     float sampleUniform( const float u1, const float u2, Point& p ) const
00163     {
00164         float s= sqrtf(u1);
00165         float t= u2;
00166         float u= 1.f - s;
00167         float v= (1.f - t) * s;
00168         float w= t * s;
00169         
00170         p= Point(u * a + v * b + w * c);
00171         return 1.f / area;
00172     }
00173 
00174     //! choisit un point aleatoirement a la surface du triangle et renvoie la probabilite de l'avoir choisi.
00175     float sampleUniform( Sampler& sampler, Point& p ) const
00176     {
00177         return sampleUniform(sampler.uniformFloat(), sampler.uniformFloat(), p);
00178     }
00179 
00180     //! choisit une position aleatoirement a la surface du triangle et renvoie la probabilite de l'avoir choisie.
00181     float sampleUniformUV( const float u1, const float u2, float &u, float& v ) const
00182     {
00183         float s= sqrtf(u1);
00184         float t= u2;
00185         u= 1.f - s;
00186         v= (1.f - t) * s;
00187         return 1.f / area;
00188     }
00189     
00190     //! choisit une position aleatoirement a la surface du triangle et renvoie la probabilite de l'avoir choisie.
00191     float sampleUniformUV( Sampler& sampler, float &u, float &v ) const
00192     {
00193         return sampleUniformUV(sampler.uniformFloat(), sampler.uniformFloat(), u, v);
00194     }
00195     
00196     //! renvoie la probabilite de choisir le point p aleatoirement.
00197     //! remarque: le point doit appartenir au triangle.
00198     float pdfUniform( const Point& p ) const
00199     {
00200         return 1.f / area;
00201     }
00202 };
00203 
00204 }
00205 #endif
 All Classes Namespaces Functions Variables Typedefs Enumerator Friends