src/CookTorranceShader.h

Go to the documentation of this file.
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;  //light dir
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                 //Color rhod = mColor.rgb().scaled(1/M_PI);
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                 //Color addto = intensity.rgb().scaled(cosLightNormal * (kd * color + ks * rhos));
00085                 //result += addto;
00086                 result += intensity.rgb().scaled(cosLightNormal * (mKd * mColor.rgb()  + mKs * rhos));
00087             }
00088         }
00089         
00090         // add Textures
00091         RGBAColor texturing(result,1.0f);
00092         std::vector<Texture*>::const_iterator it = mTextures.begin();
00093         for(; it!=mTextures.end(); ++it)
00094         {
00095             // get texture color
00096             const RGBAColor tex = (*it)->texel(ray.hit()->texCoord(ray));
00097             
00098             // combine texture color with the computed result
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 /*        const float c = LightDir.dot(Halfway);
00141         const float g = sqrtf( powf(nue_lambda,2) + powf(c,2) - 1.0f);
00142         const float F_lambda_firstterm = 0.5f * (powf(g-c, 2) / powf(g+c, 2) );
00143         const float F_lambda_secondterm = 1 + ( powf(c * (g+c) - 1.0f, 2) / powf(c * (g-c) - 1.0f, 2) );
00144         const float F_lambda = F_lambda_firstterm * F_lambda_secondterm;
00145         return F_lambda;
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

Generated on Fri Feb 1 00:01:42 2008 for Grayfall by  doxygen 1.5.1