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
00014 inline float CosTheta( const Vector& w )
00015 {
00016 return w.z;
00017 }
00018
00019 inline float SinTheta2( const Vector &w )
00020 {
00021 return std::max(0.f, 1.f - CosTheta(w) * CosTheta(w));
00022 }
00023
00024 inline float SinTheta( const Vector &w )
00025 {
00026 return sqrtf(SinTheta2(w));
00027 }
00028
00029 inline float CosPhi( const Vector &w )
00030 {
00031 float sintheta= SinTheta(w);
00032 if(sintheta == 0.f)
00033 return 1.f;
00034 return Clamp(w.x / sintheta, -1.f, 1.f);
00035 }
00036
00037 inline float SinPhi( const Vector &w )
00038 {
00039 float sintheta= SinTheta(w);
00040 if(sintheta == 0.f)
00041 return 0.f;
00042 return Clamp(w.y / sintheta, -1.f, 1.f);
00043 }
00044
00045
00046 inline bool SameHemisphere( const Vector &v, const Vector &w )
00047 {
00048 return (v.z * w.z > 0.f);
00049 }
00050
00051
00052 inline void Reflect( const Vector& w, const Vector& n, Vector& r )
00053 {
00054 r= 2.f * Dot(n, w) * n - w;
00055 }
00056
00057
00058 inline Vector Reflect( const Vector& w, const Vector& n )
00059 {
00060 return (2.f * Dot(n, w) * n - w);
00061 }
00062
00063
00064 inline float SampleUniform( Sampler& sampler, Vector& w )
00065 {
00066 const float u1= 2.f * M_PI * sampler.uniformFloat();
00067 const float u2= sampler.uniformFloat();
00068
00069 w= Vector(
00070 cosf(u1) * sqrtf(1.f - u2*u2),
00071 sinf(u1) * sqrtf(1.f - u2*u2),
00072 u2);
00073 return 1.f / (2.f * M_PI);
00074 }
00075
00076
00077 inline float pdfUniform( const Vector& w )
00078 {
00079 return 1.f / (2.f * M_PI);
00080 }
00081
00082
00083 inline float SampleCos( Sampler& sampler, Vector& w )
00084 {
00085 const float u1= 2.f * M_PI * sampler.uniformFloat();
00086 const float u2= sampler.uniformFloat();
00087
00088 w= Vector(
00089 cosf(u1) * sqrtf(1.f - u2),
00090 sinf(u1) * sqrtf(1.f - u2),
00091 sqrtf(u2));
00092 return CosTheta(w) / M_PI;
00093 }
00094
00095
00096 inline float pdfCos( const Vector& w )
00097 {
00098 return CosTheta(w) / M_PI;
00099 }
00100
00101
00102 inline float SampleCosPow( Sampler& sampler, const float n, Vector& w )
00103 {
00104 const float u1= 2.f * M_PI * sampler.uniformFloat();
00105 const float u2= powf(sampler.uniformFloat(), 1.f / (n + 1.f));
00106
00107 w= Vector(
00108 cosf(u1) * sqrtf(1.f - u2*u2),
00109 sinf(u1) * sqrtf(1.f - u2*u2),
00110 u2);
00111 return powf(CosTheta(w), n) * (n + 1.f) / (2.f * M_PI);
00112 }
00113
00114
00115 inline float pdfCosPow( const float n, const Vector& w )
00116 {
00117 return powf(CosTheta(w), n) * (n + 1.f) / (2.f * M_PI);
00118 }
00119
00120
00121
00122 class Brdf
00123 {
00124 Energy diffuse_color;
00125 Energy specular_color;
00126 float kd;
00127 float ks;
00128 float n;
00129
00130 public:
00131 Brdf( const float _kd, const float _ks, const float _n )
00132 :
00133 diffuse_color(1.f),
00134 specular_color(1.f),
00135 kd(_kd),
00136 ks(_ks),
00137 n(_n)
00138 {}
00139
00140 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 )
00141 :
00142 diffuse_color(diffuse),
00143 specular_color(specular),
00144 kd(_kd),
00145 ks(_ks),
00146 n(_n)
00147 {}
00148
00149
00150 Energy fKd( const Vector& wi, const Vector& wo ) const
00151 {
00152 if(CosTheta(wi) < 0.f || CosTheta(wo) < 0.f)
00153 return 0.f;
00154 return diffuse_color * kd / M_PI;
00155 }
00156
00157
00158 Energy fKs( const Vector& wi, const Vector& wo ) const
00159 {
00160 if(CosTheta(wi) < 0.f || CosTheta(wo) < 0.f)
00161 return 0.f;
00162
00163 const Vector h= Normalize(wi + wo);
00164
00165 return specular_color * ks * (n + 1.f) / (2.f * M_PI) * powf(CosTheta(h), n);
00166 }
00167
00168
00169 Energy f( const Vector& wi, const Vector& wo ) const
00170 {
00171 if(CosTheta(wi) < 0.f || CosTheta(wo) < 0.f)
00172 return 0.f;
00173
00174 const Vector h= Normalize(wi + wo);
00175
00176 return diffuse_color * kd / M_PI + specular_color * ks * (n + 1.f) / (2.f * M_PI) * powf(CosTheta(h), n);
00177 }
00178
00179
00180 float sample( Sampler& sampler, const Vector& wi, Vector& wo ) const
00181 {
00182 float u= sampler.uniformFloat();
00183 if(u < kd)
00184 {
00185
00186 float pkd= SampleCos(sampler, wo);
00187
00188
00189 Vector h= Normalize(wi + wo);
00190 float pks= pdfCosPow(n, h) / (4.f * Dot(wi, h));
00191
00192 return kd * pkd + ks * pks;
00193 }
00194
00195 else if(u < kd + ks)
00196 {
00197
00198 Vector h;
00199 float ph= SampleCosPow(sampler, n, h);
00200 wo= Reflect(wi, h);
00201 float pks= ph / (4.f * Dot(wi, h));
00202 if(CosTheta(wo) < 0.f)
00203
00204 return 0.f;
00205
00206
00207 float pkd= pdfCos(wo);
00208
00209 return kd * pkd + ks * pks;
00210 }
00211
00212
00213 wo= Vector(0.f, 0.f, 1.f);
00214 return 0.f;
00215 }
00216
00217
00218 float pdf( const Vector& wi, const Vector& wo ) const
00219 {
00220 if(CosTheta(wo) < 0.f)
00221 return 0.f;
00222
00223 float pkd= pdfCos(wo);
00224 Vector h= Normalize(wi + wo);
00225 float pks= pdfCosPow(n, h) / (4.f * Dot(wi, h));
00226
00227 return kd * pkd + ks * pks;
00228 }
00229
00230
00231 float rho( Sampler& sampler, const Vector& wo, const int samples= 100 ) const
00232 {
00233 return rhod() + rhos(sampler, wo, samples);
00234 }
00235
00236
00237 float rho( Sampler& sampler, const int samples= 100 ) const
00238 {
00239 return rhod() + rhos(sampler, samples);
00240 }
00241
00242
00243 float rhod( ) const
00244 {
00245
00246 return kd;
00247
00248 #if 0
00249
00250 Sampler sampler;
00251 const int samples= 1000;
00252 float r= 0.f;
00253 for(int i= 0; i < samples; i++)
00254 {
00255 Vector wo;
00256 float p= SampleCos(sampler, wo);
00257
00258 r= r + kd / M_PI * CosTheta(wo) / p;
00259 }
00260
00261 return r / (float) samples;
00262 #endif
00263 }
00264
00265
00266 float rhos( Sampler& sampler, const Vector& wo, const int samples= 100 ) const
00267 {
00268 float r= 0.f;
00269 for(int i= 0; i < samples; i++)
00270 {
00271 Vector h;
00272 float ph= SampleCosPow(sampler, n, h);
00273
00274 Vector w= Reflect(wo, h);
00275 if(CosTheta(w) < 0.f)
00276 continue;
00277 float p= ph / (4.f * Dot(wo, h));
00278
00279
00280 r= r + ks * (n + 1.f) / (2.f * M_PI) * powf(CosTheta(h), n) * CosTheta(w) / p;
00281 }
00282
00283 return r / (float) samples;
00284 }
00285
00286
00287 float rhos( Sampler& sampler, const int samples= 100 ) const
00288 {
00289 return rhos(sampler, Vector(0.f, 0.f, 1.f), samples);
00290 }
00291 };
00292
00293 }
00294
00295 #endif