gKitGL
|
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