src/rcrt/bxdf/CookTorrance.cpp

Go to the documentation of this file.
00001 #include "CookTorrance.h"
00002 #include <stdexcept>
00003 #include "../loaders/conversion.hpp"
00004 
00005 using namespace std;
00006 
00007 namespace rcrt
00008 {
00009 
00010 CookTorrance::CookTorrance(const RGBColor& diff, const RGBColor& spec, const float& rough, const std::complex<float>& indOR)
00011         :BXDF(spec, diff, 0, BXDFType(REFLECTIVE)),ior(indOR),roughness(rough)
00012 {
00013         
00014 }
00015 
00016 CookTorrance::~CookTorrance()
00017 {
00018 }
00019 
00020 RGBColor CookTorrance::eval(const Vec3D& wOut, const Vec3D& wInc, const Vec3D& normal) const
00021 {
00022         return kd/M_PI + evalSpecular(wOut,wInc,normal);        
00023 }
00024 
00025 RGBColor CookTorrance::evalDiffuse(const Vec3D& wOut, const Vec3D& wInc, const Vec3D& normal) const
00026 {
00027         return kd/M_PI;
00028 }
00029 
00030 RGBColor CookTorrance::evalSpecular(const Vec3D& wOut, const Vec3D& wInc, const Vec3D& normal) const
00031 {
00032         Vec3D v;
00033         
00034         if(wInc == wOut * -1)//somehow this happens sometimes..
00035                 v = Vec3D(wInc.x()+0.00001,wInc.y()+0.00001,wInc.z()+0.00001);
00036         else
00037                 v = wInc;
00038         
00039         float nv = normal * wOut;
00040         float nl = normal * v;
00041 
00042         Vec3D h((wOut + v).normalize());
00043                 
00044         float vh = v * h;
00045 
00046         float nh = normal * h;
00047         //fixing very small values that may lead to division by zero
00048         if(nh < numeric_limits<float>::epsilon())
00049                 nh = numeric_limits<float>::epsilon();
00050         if(nl < numeric_limits<float>::epsilon())
00051                 nl = numeric_limits<float>::epsilon();
00052         if(nv < numeric_limits<float>::epsilon())
00053                 nv = numeric_limits<float>::epsilon();
00054         if(vh < numeric_limits<float>::epsilon())
00055                 vh = numeric_limits<float>::epsilon();
00056 
00057         // geometric term
00058         const float G = min(min(1.0f, (2.0f*nh*nv)/vh), (2.0f*nh*nl)/vh);
00059 
00060         float nh2 = nh * nh;
00061         if(nh2 < numeric_limits<float>::epsilon())
00062                 nh2 = numeric_limits<float>::epsilon();
00063         const float tan2alpha = 1.0f/nh2 - 1.0f;
00064 
00065         // Beckmann distribution function
00066         const float rough2 = roughness*roughness;
00067         const float D = exp(-tan2alpha/rough2) / (rough2 * (nh2 * nh2));
00068 
00069         const float F = fresnelTerm(vh, ior);
00070 
00071         // specular reflectance
00072         const float Rs = (F / M_PI) * (D / nl) * (G / nv);
00073         
00074         return ks * Rs;
00075 }
00076 
00077 
00078 bool CookTorrance::specular() const
00079 {
00080         return true;
00081 }
00082 
00083 bool CookTorrance::glossy() const
00084 {
00085         return true;
00086 }
00087 
00088 bool CookTorrance::diffuse() const
00089 {
00090         return true;
00091 }
00092 
00093 bool CookTorrance::fresnel() const
00094 {
00095         return true;
00096 }
00097 
00098 float CookTorrance::pdf(const Vec3D& wOut, const Vec3D& wInc, const Vec3D& normal) const
00099 {
00100         //Using Ward's sampling scheme, especially found in: 
00101         //Kelemen and Szirmay-Kalos: Microfacet Based BRDF Model
00102         float cosO = wOut * normal;
00103         if(cosO < 0) return 0;
00104                 
00105         Vec3D h((wOut + wInc).normalize());
00106         float calpha = normal * h;
00107         float r2 = roughness * roughness;
00108         //probability for the halfway vector
00109         float ph = 1.0f / (r2 * M_PI * powf(calpha, 3)) * exp(-powf(tan(calpha),2)/r2);
00110         float cbeta = h * wOut;
00111         //cout << " ph " << ph << " cbeta " << cbeta << endl;
00112         return ph / ( 4 * cbeta);       
00113 }
00114 
00115 }

Generated on Thu Jan 31 19:26:19 2008 for RenderingCompetitionRayTracer by  doxygen 1.5.3