00001 #ifndef REFRACTIVESHADER_H
00002 #define REFRACTIVESHADER_H
00003
00004 #include "Shader.h"
00005 #include "Scene.h"
00006 #include "Texture.h"
00007 #include "Ray.h"
00008 #include "Vec3f.h"
00009 #include "defines.h"
00010
00011
00017 class RefractiveShader : public Shader
00018 {
00019 public:
00026 RefractiveShader( Scene * scene,
00027 const RGBAColor & color,
00028 float refractionIdx );
00029
00032 RGBAColor shade(const Ray & ray) const
00033 {
00034 assert(ray.hit());
00035 assert(ray.obj());
00036
00037
00038 if (ray.influence() < MIN_INFLUENCE || ray.recDeep() > MAX_RECURSION_DEEP)
00039 {
00040
00041 Ray newray;
00042 newray.init(ray.hitPoint(EPSILON), ray.dir());
00043 newray.updateInfluence(ray);
00044 return mScene->rayTrace(newray);
00045
00046 }
00047
00048
00049 Vec3f n = normal(ray);
00050
00051
00052 float cosIncident = n.dot(-ray.dir());
00053 bool fromOutside = cosIncident >= 0;
00054
00055 float refIdx = mRefractionIndex;
00056 if (fromOutside)
00057 refIdx = mInvRefractionIndex;
00058
00059 float sqrCosRefracted = 1.0f - refIdx*refIdx*(1.0f - cosIncident*cosIncident);
00060
00061
00062 Vec3f reflected = ray.dir() + 2*cosIncident*n;
00063 Ray newray;
00064
00065
00066 float R = 1.0f;
00067
00068 Vec3f refractedCol;
00069 if (sqrCosRefracted >= 0.0f)
00070 {
00071
00072 float cosRefracted = sqrtf(sqrCosRefracted);
00073
00074 float Rs = 0.0f;
00075 float Rp = 0.0f;
00076
00077 Vec3f v = refIdx*ray.dir();
00078 if (fromOutside)
00079 {
00080 v += (refIdx*cosIncident - cosRefracted)*n;
00081 }
00082 else
00083 {
00084 cosIncident = - cosIncident;
00085 v -= (refIdx*cosIncident - cosRefracted)*n;
00086 }
00087
00088 Rs = (cosIncident - mRefractionIndex*cosRefracted)/(cosIncident + mRefractionIndex*cosRefracted);
00089 Rp = (cosRefracted - mRefractionIndex*cosIncident)/(cosRefracted + mRefractionIndex*cosIncident);
00090
00091 R = (Rs*Rs + Rp*Rp)*0.5;
00092
00093
00094 newray.init(ray.hitPoint(EPSILON), v);
00095 newray.updateInfluence(ray, 1.0f - R);
00096 refractedCol = mScene->rayTrace(newray).rgb();
00097 if (fromOutside)
00098 {
00099 float shading = powf(1.0f - mColor.a(), newray.t());
00100 refractedCol = lerp(mColor.rgb(), refractedCol, shading);
00101 }
00102 }
00103
00104 assert(0 <= R && R <= 1);
00105
00106
00107 newray.init(ray.hitPoint(-EPSILON), reflected);
00108 newray.updateInfluence(ray, R);
00109 Vec3f reflectedCol = mScene->rayTrace(newray).rgb();
00110 if (!fromOutside)
00111 {
00112 float shading = powf(1.0f - mColor.a(), newray.t());
00113 reflectedCol = lerp(mColor.rgb(), reflectedCol, shading);
00114 }
00115
00116
00117 return RGBAColor(lerp(refractedCol, reflectedCol, R));
00118 }
00119
00120 private:
00122 RGBAColor mColor;
00123
00125 float mRefractionIndex;
00126
00128 float mInvRefractionIndex;
00129 };
00130
00131
00132 #endif
00133