00001 #ifndef COOKTORRANCESHADER_H
00002 #define COOKTORRANCESHADER_H
00003
00004 #include "Shader.h"
00005
00009 class CookTorranceShader : public Shader
00010 {
00011 public:
00022 CookTorranceShader(Scene * scene,
00023 RGBAColor color,
00024 float ka,
00025 float kd,
00026 float ks,
00027 float slope = 0.12f,
00028 float lambda = 0.2f )
00029 : Shader(scene),
00030 mColor(color),
00031 mKa(ka),
00032 mKd(kd),
00033 mKs(ks),
00034 mSlope(slope),
00035 mLambda(lambda)
00036 {
00037 }
00038
00041 virtual RGBAColor shade(const Ray & ray) const
00042 {
00043 typedef Vec3f Color;
00044
00045 const Vec3f origin = ray.org() + ray.t() * ray.dir();
00046 Vec3f normal = this->normal(ray);
00047 if (ray.dir().dot(normal) > 0.0f)
00048 normal = -normal;
00049
00050
00051 const Vec3f ViewDir = (-ray.dir() ).normal();
00052 const Color ambientColor = mKa * mColor.rgb();
00053 const Color ambientIntensity(1,1,1);
00054
00055 Color result = ambientColor.scaled(ambientIntensity);
00056
00057 for(unsigned int i = 0; i < mScene->lightsCount(); i++)
00058 {
00059 for (unsigned int j = 0; j < mScene->getLight(i)->numberOfRays(); j++)
00060 {
00061 Vec3f LightDir;
00062 const RGBAColor intensity = mScene->getLight(i)->illuminate(LightDir,origin,j);
00063 const Vec3f Halfway = ( LightDir + ViewDir).normal();
00064
00065 const float cosLightNormal = LightDir.dot(normal);
00066 if(cosLightNormal <= 0)
00067 continue;
00068
00069
00070
00071 float rhos;
00072 const float D = distribution(normal, Halfway);
00073
00074 const float G = geometry(normal, Halfway, LightDir, ViewDir);
00075
00076 const float F = fresnel(Halfway, LightDir);
00077 rhos = ( F * D * G ) / ( M_PI * normal.dot(ViewDir) * normal.dot(LightDir) );
00078
00079 if(isnan(rhos))
00080 {
00081 LOG("RHOS IS NAN. Most likely Fresnel term is NAN, change the nue_lambda term");
00082 rhos = 0.0f;
00083 }
00084
00085
00086 result += intensity.rgb().scaled(cosLightNormal * (mKd * mColor.rgb() + mKs * rhos));
00087 }
00088 }
00089
00090
00091 RGBAColor texturing(result,1.0f);
00092 std::vector<Texture*>::const_iterator it = mTextures.begin();
00093 for(; it!=mTextures.end(); ++it)
00094 {
00095
00096 const RGBAColor tex = (*it)->texel(ray.hit()->texCoord(ray));
00097
00098
00099 texturing.scale(tex);
00100 }
00101 return texturing;
00102
00103 }
00104
00105 private:
00108 const float distribution(const Vec3f & normal, const Vec3f & Halfway) const
00109 {
00110 const float beta = acosf( normal.dot(Halfway) );
00111 const float firstterm = (1.0f/ ( 4.0f * powf(mSlope,2) * powf(cosf(beta),4) ) );
00112 const float secondterm = exp( - powf(tanf(beta) / mSlope ,2));
00113 return firstterm * secondterm;
00114 }
00115
00118 const float geometry(const Vec3f & normal, const Vec3f & Halfway, const Vec3f & LightDir, const Vec3f & ViewDir) const
00119 {
00120 const float G_b = ( 2.0f* normal.dot(Halfway)* normal.dot(ViewDir) ) / ( ViewDir.dot(Halfway) );
00121 const float G_s = ( 2.0f* normal.dot(Halfway)* normal.dot(LightDir) ) / ( ViewDir.dot(Halfway) );
00122 return std::min(1.0f, std::min(G_b, G_s) );
00123 }
00124
00127 const float fresnel(const Vec3f & Halfway, const Vec3f & LightDir) const
00128 {
00129
00130
00131 const float theta_i = acosf(LightDir.dot(Halfway));
00132 const float theta_t = asinf(mLambda * sinf(theta_i) );
00133 const float firstterm = 0.5f * (powf(sinf(theta_i - theta_t),2) ) / (powf(sinf(theta_i + theta_t),2) );
00134 const float secondterm = 1.0f + ( powf(cosf(theta_i + theta_t),2) / (powf(cosf(theta_i - theta_t),2)));
00135
00136
00137 return firstterm * secondterm;
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147 }
00148
00149
00150 RGBAColor mColor;
00151 float mKa;
00152 float mKd;
00153 float mKs;
00154 float mSlope;
00155 float mLambda;
00156 };
00157
00158 #endif