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)
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
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
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
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
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
00101
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
00109 float ph = 1.0f / (r2 * M_PI * powf(calpha, 3)) * exp(-powf(tan(calpha),2)/r2);
00110 float cbeta = h * wOut;
00111
00112 return ph / ( 4 * cbeta);
00113 }
00114
00115 }