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