00001 #include "PhotonTracer.h"
00002 #include "../materials/Material.h"
00003 #include "../bxdf/fresnel.hpp"
00004
00005 using namespace std;
00006
00007 namespace rcrt
00008 {
00009
00010 PhotonTracer::PhotonTracer(Scene* s, PhotonMap* photonM, const int& noPhotG, const int& noPhotC):
00011 TracingStrategy(s), photonMap(photonM), noGPhotons(noPhotG), noCPhotons(noPhotC)
00012 {
00013
00014 }
00015
00016 PhotonTracer::~PhotonTracer()
00017 {
00018 }
00019
00020 RGBColor PhotonTracer::directLight(Intersection& is, const Vec3D& rayDir) const
00021 {
00022 RGBColor result(0);
00023 Material* mat = is.getPrimitive()->getParent()->getMaterial();
00024 vector<Light*>* const lights = scene->getLights();
00025 for(unsigned int i = 0; i < lights->size(); i++){
00026 Light* const light = lights->at(i);
00027 RGBColor Lr(0);
00028 std::vector<LightSample> samples;
00029 if(light->hasSampler())
00030
00031 light->getSampler()->sample(is.getPosition(), is.getSNormalW(), samples, light->getMinSamples(), scene);
00032 else
00033
00034 light->illuminate(is.getPosition(), is.getSNormalW(), samples, light->getMinSamples());
00035
00036 for(unsigned int s = 0; s < samples.size(); s++){
00037 const LightSample& sample = samples[s];
00038
00039 if(sample.weight() == 0)
00040 continue;
00041
00042
00043 if(!light->hasSampler() && scene->castShadows() &&
00044 scene->isOccluded(is.getPosition(), sample.dirToLight(), sample.dist())){
00045 continue;
00046 }
00047 const Vec3D dirFromLight = (sample.dirToLight()*-1).normalize();
00048
00049 RGBColor fr = mat->sample(rayDir*-1,dirFromLight, is);
00050 float angle = dirFromLight*is.getSNormalW();
00051 RGBColor power = sample.power();
00052 float weight = sample.weight();
00053
00054 Lr = Lr + power * fr * fabs(angle) * weight;
00055 }
00056 result = result + Lr;
00057 }
00058 return result;
00059 }
00060
00061 RGBColor PhotonTracer::trace(Ray& r) const
00062 {
00063 static const float MAXRAYDEPTH = 7;
00064 static const float THRESHOLD = 0.00001f;
00065 if(r.getDepth() > MAXRAYDEPTH)
00066 return RGBColor::BLACK;
00067
00068 Intersection is = scene->intersect(r);
00069 if(is.isValid())
00070 r.setCurrDist(is.getDistance());
00071
00072 RGBColor result(0);
00073
00074 if(is.isValid()){
00075 Material* mat = is.getPrimitive()->getParent()->getMaterial();
00076 Vec3D normal(mat->getShadingNormal(is));
00077 if(!is.backSide()){
00078
00079 result = result + mat->getEmitted(r.dir()*-1, is);
00080
00081
00082 RGBColor direct(directLight(is, r.dir()));
00083
00084 result = result + direct;
00085
00086
00087 RGBColor radiance(photonMap->getRadiance(r.dir()*-1, noGPhotons, noCPhotons, is));
00088
00089 result = result + radiance;
00090
00091 if(false){
00092 RGBColor indir(0);
00093 for(int i = 0; i < 1; i++){
00094 float xi1 = float(rand()) / float(RAND_MAX);
00095 float xi2 = float(rand()) / float(RAND_MAX);
00096 float z2 = xi2 * 2.0f * M_PI;
00097 Vec3D u;
00098 Vec3D v;
00099 normal.getCS(u, v);
00100 Vec3D sampleDir(u * cos(z2) + v * sin(z2) * sqrt(1-xi1) + normal * sqrt(xi1));
00101 sampleDir.normalize();
00102 RGBColor fr = mat->sample(r.dir()*-1,sampleDir*-1,is);
00103 float weight = fr.avg() * r.getWeight();
00104 Ray indRay(is.getPosition(),sampleDir,r.getDepth()+1,weight);
00105 RGBColor sample = trace(indRay);
00106 indir = indir + fr * sample / (4 * M_PI * indRay.currDist() * indRay.currDist());
00107 }
00108 result = result + indir;
00109 }
00110
00111
00112 if(mat->hasSpecular()){
00113
00114 Vec3D reflDir(r.dir().reflect(normal));
00115 RGBColor fr = mat->sampleSpecular(r.dir()*-1,reflDir*-1,is);
00116 float weight = fr.avg()*r.getWeight();
00117
00118
00119 if(weight > THRESHOLD && r.getDepth()+1 <= MAXRAYDEPTH){
00120 Ray reflRay(is.getPosition(),reflDir,r.getDepth()+1,weight);
00121 RGBColor reflColor = trace(reflRay);
00122 result = result + reflColor * fr;
00123 }
00124 }
00125
00126 }
00127
00128
00129 if(mat->refracts()){
00130 float etaT = mat->getRealIORPart();
00131 float etaI = r.getLastIOR().real();
00132 bool leaving = false;
00133 if(is.backSide()){
00134
00135 etaT = 1;
00136 leaving = true;
00137 }
00138
00139 float eta = etaI / etaT;
00140 float cosI = r.dir() * normal;
00141 float cosT = 1.0 - (eta * eta) * (1.0 - cosI * cosI);
00142
00143 if (leaving && cosT <= 0.0f) {
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 }
00170 cosT = sqrt(cosT);
00171 float k = eta * cosI + cosT;
00172
00173 Vec3D refrDir = r.dir() * eta + normal * -k;
00174 cosT = refrDir * normal;
00175
00176 float fresnel(frTDielectric(cosI, cosT,
00177 r.getLastIOR().real(), etaT));
00178
00179
00180 float weight = fresnel *r.getWeight();
00181 if(weight > THRESHOLD && r.getDepth()+1 <= MAXRAYDEPTH){
00182
00183 Ray refrRay(is.getPosition()+refrDir * 0.0001f,refrDir,r.getDepth()+1, weight);
00184 if(leaving)
00185 refrRay.setLastObject(0);
00186 else
00187 refrRay.setLastObject(is.getPrimitive()->getParent());
00188
00189 refrRay.setLastIOR(complex<float>(etaT,0));
00190
00191 RGBColor refrColor = trace(refrRay);
00192
00193 float dist = refrRay.currDist();
00194
00195 RGBColor absorb(mat->getAbsorbance());
00196 if(dist < std::numeric_limits<float>::infinity() && dist > 0){
00197 absorb = RGBColor(exp(-dist * absorb.r()),
00198 exp(-dist * absorb.g()),
00199 exp(-dist * absorb.b()));
00200 }
00201
00202 result = result + refrColor * absorb * fresnel;
00203 }
00204 }
00205 }
00206
00207 return result.clamped();
00208
00209 }
00210
00211 }