gKitGL
Brdf.h
00001 
00002 #ifndef _BRDF_H
00003 #define _BRDF_H
00004 
00005 #include <cstdlib>
00006 #include <cmath>
00007 
00008 #include "Geometry.h"
00009 #include "Sampler.h"
00010 
00011 namespace gk {
00012 
00013 inline float Square( const float x )
00014 {
00015     return x*x;
00016 }
00017 
00018 inline float Cube( const float x )
00019 {
00020     return x*x*x;
00021 }
00022 
00023     
00024 //! repere local de la brdf.
00025 inline float CosTheta( const Vector& w )
00026 {
00027     return w.z;
00028 }
00029 
00030 inline float SinTheta2( const Vector &w )
00031 {
00032     return std::max(0.f, 1.f - CosTheta(w) * CosTheta(w));
00033 }
00034 
00035 inline float SinTheta( const Vector &w )
00036 {
00037     return sqrtf(SinTheta2(w));
00038 }
00039 
00040 inline float CosPhi( const Vector &w )
00041 {
00042     float sintheta= SinTheta(w);
00043     if(sintheta == 0.f) 
00044         return 1.f;
00045     return Clamp(w.x / sintheta, -1.f, 1.f);
00046 }
00047 
00048 inline float SinPhi( const Vector &w )
00049 {
00050     float sintheta= SinTheta(w);
00051     if(sintheta == 0.f) 
00052         return 0.f;
00053     return Clamp(w.y / sintheta, -1.f, 1.f);
00054 }
00055 
00056 //! renvoie vrai si v et w sont du meme cote de la surface.
00057 inline bool SameHemisphere( const Vector &v, const Vector &w )
00058 {
00059     return (v.z * w.z > 0.f);
00060 }
00061 
00062 //! r= direction miroir de w par rapport a n.
00063 inline void Reflect( const Vector& w, const Vector& n, Vector& r )
00064 {
00065     r= 2.f * Dot(n, w) * n - w;
00066 }
00067 
00068 //! renvoie la direction miroir de w par rapport a n.
00069 inline Vector Reflect( const Vector& w, const Vector& n )
00070 {
00071     return (2.f * Dot(n, w) * n - w);
00072 }
00073 
00074 
00075 //! genere une direction w dans l'hemisphere. pdf = constante.
00076 inline float SampleUniform( const float r1, const float r2, Vector& w )
00077 {
00078     const float u1= 2.f * M_PI * r1;
00079     const float u2= r2;
00080     
00081     w= Vector(
00082         cosf(u1) * sqrtf(1.f - u2*u2), 
00083         sinf(u1) * sqrtf(1.f - u2*u2), 
00084         u2);
00085     return 1.f / (2.f * M_PI);
00086 }
00087 
00088 //! genere une direction w dans l'hemisphere. pdf = constante.
00089 inline float SampleUniform( Sampler& sampler, Vector& w )
00090 {
00091     float r1= sampler.uniformFloat();
00092     float r2= sampler.uniformFloat();
00093     return SampleUniform(r1, r2, w);
00094 }
00095 
00096 //! renvoie la probabilite de generer la direction w pour une pdf = constante.
00097 inline float pdfUniform( const Vector& w )
00098 {
00099     return 1.f / (2.f * M_PI);
00100 }
00101 
00102 //! genere une direction w dans l'hemisphere. pdf= cos theta / pi.
00103 inline float SampleCos( Sampler& sampler, Vector& w )
00104 {
00105     const float u1= 2.f * M_PI * sampler.uniformFloat();
00106     const float u2= sampler.uniformFloat();
00107     
00108     w= Vector(
00109         cosf(u1) * sqrtf(1.f - u2), 
00110         sinf(u1) * sqrtf(1.f - u2), 
00111         sqrtf(u2));
00112     return CosTheta(w) / M_PI;
00113 }
00114 
00115 //! renvoie la probabilite de generer la direction w pour une pdf = cos theta / pi
00116 inline float pdfCos( const Vector& w )
00117 {
00118     return CosTheta(w) / M_PI;
00119 }
00120 
00121 //! genere une direction w dans l'hemisphere. pdf = cos**n theta * (n+1) / (2*pi).
00122 inline float SampleCosPow( Sampler& sampler, const float n, Vector& w )
00123 {
00124     const float u1= 2.f * M_PI * sampler.uniformFloat();
00125     const float u2= powf(sampler.uniformFloat(), 1.f / (n + 1.f));
00126     
00127     w= Vector(
00128         cosf(u1) * sqrtf(1.f - u2*u2),
00129         sinf(u1) * sqrtf(1.f - u2*u2),
00130         u2);
00131     return powf(CosTheta(w), n) * (n + 1.f) / (2.f * M_PI);
00132 }
00133 
00134 //! renvoie la probabilite de generer la direction w pour une pdf= cos**n theta * (n+1) / (2*pi).
00135 inline float pdfCosPow( const float n, const Vector& w )
00136 {
00137     return powf(CosTheta(w), n) * (n + 1.f) / (2.f * M_PI);
00138 }
00139 
00140 
00141 //! representation d'une brdf blinn phong, comportements diffus + lobe glossy
00142 //! \todo utiliser un modele qui conserve l'energie < 1, cf "an anisotropic phong brdf model", avec un terme kd variable.
00143 
00144 class Brdf
00145 {
00146     Energy diffuse_color;
00147     Energy specular_color;
00148     float kd;
00149     float ks;
00150     float n;
00151     
00152 public:
00153     Brdf( const float _kd, const float _ks, const float _n )
00154         :
00155         diffuse_color(1.f),
00156         specular_color(1.f),
00157         kd(_kd),
00158         ks(_ks),
00159         n(_n)
00160     {}
00161         
00162     Brdf( const float _kd, const Energy& diffuse= gk::Energy(1.f), const float _ks= 0.f, const Energy& specular= Energy(0.f), const float _n= 0.f )
00163         :
00164         diffuse_color(diffuse),
00165         specular_color(specular),
00166         kd(_kd),
00167         ks(_ks),
00168         n(_n)
00169     {}
00170     
00171     //! renvoie l'evaluation du comportement diffus de la brdf.
00172     Energy fKd( const Vector& wi, const Vector& wo ) const
00173     {
00174         if(CosTheta(wi) < 0.f || CosTheta(wo) < 0.f)
00175             return 0.f;
00176         return diffuse_color * kd / M_PI;
00177     }
00178     
00179     //! renvoie l'evaluation du comportement glossy de la brdf.
00180     Energy fKs( const Vector& wi, const Vector& wo ) const
00181     {
00182         if(CosTheta(wi) < 0.f || CosTheta(wo) < 0.f)
00183             return 0.f;
00184         
00185         const Vector h= Normalize(wi + wo);
00186         //~ return ks / M_PI * (n + 1.f) / (2.f * M_PI) * powf(CosTheta(h), n);
00187         return specular_color * ks * (n + 1.f) / (2.f * M_PI) * powf(CosTheta(h), n) / (4.f * Dot(wo, h));
00188     }
00189     
00190     //! renvoie l'evaluation de la brdf pour le couple de directions wi, wo (repere local, orientes tels que Dot(wi, n) > 0 et Dot(wo, n) > 0).
00191     Energy f( const Vector& wi, const Vector& wo ) const
00192     {
00193         if(CosTheta(wi) < 0.f || CosTheta(wo) < 0.f)
00194             return 0.f;
00195         
00196         const Vector h= Normalize(wi + wo);
00197         //~ return kd / M_PI + ks / M_PI * (n + 1.f) / (2.f * M_PI) * powf(CosTheta(h), n);
00198         return diffuse_color * kd / M_PI + specular_color * ks * (n + 1.f) / (2.f * M_PI) * powf(CosTheta(h), n) / (4.f * Dot(wo, h));
00199     }
00200     
00201     float sampleKd( Sampler& sampler, const Vector& wi, Vector& wo ) const
00202     {
00203         // diffus
00204         float pkd= SampleUniform(sampler, wo);
00205         
00206         return kd * pkd;
00207     }
00208     
00209     float sampleKs( Sampler& sampler, const Vector& wi, Vector& wo ) const
00210     {
00211         Vector h;
00212         float ph= SampleCosPow(sampler, n, h);
00213         wo= Reflect(wi, h);
00214         float pks= ph / (4.f * Dot(wi, h));
00215         if(CosTheta(wo) < 0.f)
00216             // wo est sous la surface, il ne peut pas etre genere, ni pas le comportement diffus, ni par le comportement glossy
00217             return 0.f;
00218         
00219         return ks * pks;
00220     }
00221     
00222     //! genere une direction wo, dependante de wi.
00223     float sample( Sampler& sampler, const Vector& wi, Vector& wo ) const
00224     {
00225         float u= sampler.uniformFloat();
00226         if(u <= kd)
00227         {
00228             // diffus
00229             float pkd= SampleUniform(sampler, wo);
00230             
00231             // calcule la probabilite que l'autre comportement ait genere cette direction
00232             Vector h= Normalize(wi + wo);
00233             float pks= pdfCosPow(n, h) / (4.f * Dot(wi, h));
00234             
00235             return kd * pkd + ks * pks;
00236         }
00237         
00238         else if(u <= kd + ks)
00239         {
00240             // glossy
00241             Vector h;
00242             float ph= SampleCosPow(sampler, n, h);
00243             wo= Reflect(wi, h);
00244             float pks= ph / (4.f * Dot(wi, h));
00245             if(CosTheta(wo) < 0.f)
00246                 // wo est sous la surface, il ne peut pas etre genere, ni pas le comportement diffus, ni par le comportement glossy
00247                 return 0.f;
00248             
00249             // calcule la probabilite que l'autre comportement ait genere cette direction
00250             float pkd= pdfUniform(wo);
00251             
00252             return kd * pkd + ks * pks;
00253         }
00254         
00255         // absorption 1 - kd - ks
00256         wo= Vector(0.f, 0.f, 1.f);
00257         return 0.f;
00258     }
00259     
00260     float pdfKd( const Vector& wi, const Vector& wo ) const
00261     {
00262         if(CosTheta(wo) < 0.f)
00263             return 0.f;
00264         
00265         float pkd= pdfUniform(wo);
00266         return kd * pkd;
00267     }
00268     
00269     float pdfKs( const Vector& wi, const Vector& wo ) const
00270     {
00271         if(CosTheta(wo) < 0.f)
00272             return 0.f;
00273         
00274         Vector h= Normalize(wi + wo);
00275         float pks= pdfCosPow(n, h) / (4.f * Dot(wi, h));
00276         return ks * pks;
00277     }
00278     
00279     //! renvoie la probabilite de choisir wo, connaissant wi (repere local, orientes tels que Dot(wi, n) > 0 et Dot(wo, n) > 0).
00280     float pdf( const Vector& wi, const Vector& wo ) const
00281     {
00282         if(CosTheta(wo) < 0.f)
00283             return 0.f;
00284         
00285         float pkd= pdfUniform(wo);
00286         Vector h= Normalize(wi + wo);
00287         float pks= pdfCosPow(n, h) / (4.f * Dot(wi, h));
00288         
00289         return kd * pkd + ks * pks;
00290     }
00291     
00292     //! evalue rho / reflectance, connaissant wo (repere local, oriente tel que Dot(wo, n) > 0).
00293     float rho( Sampler& sampler, const Vector& wo, const int samples= 100 ) const
00294     {
00295         return rhod() + rhos(sampler, wo, samples);
00296     }
00297 
00298     //! evalue rho / reflectance (incidence normale == valeur max).
00299     float rho( Sampler& sampler, const int samples= 100 ) const
00300     {
00301         return rhod() + rhos(sampler, samples);
00302     }
00303 
00304     //! renvoie rho diffus / reflectance.
00305     float rhod( ) const
00306     {
00307         // par definition.
00308         return kd; 
00309         
00310     #if 0
00311         // verification de la definition
00312         Sampler sampler;
00313         const int samples= 1000;
00314         float r= 0.f;
00315         for(int i= 0; i < samples; i++)
00316         {
00317             Vector wo;
00318             float p= SampleCos(sampler, wo);
00319             
00320             r= r + kd / M_PI * CosTheta(wo) / p;
00321         }
00322         
00323         return r / (float) samples;
00324     #endif
00325     }
00326 
00327     //! evalue rho / reflectance glossy, pour une direction wo (repere local, oriente tel que Dot(wo, n) > 0).
00328     float rhos( Sampler& sampler, const Vector& wo, const int samples= 100 ) const
00329     {
00330         float r= 0.f;
00331         for(int i= 0; i < samples; i++)
00332         {
00333             Vector h;
00334             float ph= SampleCosPow(sampler, n, h);
00335             
00336             Vector w= Reflect(wo, h);
00337             if(CosTheta(w) < 0.f)
00338                 continue;
00339             float p= ph / (4.f * Dot(wo, h));
00340             
00341             //~ r= r + ks / M_PI * (n + 1.f) / (2.f * M_PI) * powf(CosTheta(h), n) * CosTheta(w) / p;
00342             r= r + ks * (n + 1.f) / (2.f * M_PI) * powf(CosTheta(h), n) / (4.f * Dot(wo, h)) * CosTheta(w) / p;
00343         }
00344         
00345         return r / (float) samples;
00346     }
00347 
00348     //! evalue rho / reflectance speculaire max (incidence normale).
00349     float rhos( Sampler& sampler, const int samples= 100 ) const
00350     {
00351         return rhos(sampler, Vector(0.f, 0.f, 1.f), samples);
00352     }
00353 };
00354 
00355 }
00356 
00357 #endif
 All Classes Namespaces Functions Variables Typedefs Enumerator Friends