glm::vec3 Transparent::shade(const ShadeRec& sr)const { glm::vec3 L(Phong::shade(sr)); glm::vec3 incoming = -sr.ray.getDirection(); glm::vec3 reflected; glm::vec3 fr = reflectiveBrdf->sampleF(sr,incoming,reflected); Ray reflectedRay(sr.hitPoint,reflected); if(specularBtfd->tir(sr)) { //comment this out to remove the reflection and get cool effects L += sr.world.getTracer()->traceRay(reflectedRay,sr.depth + 1); //kr = 1.0 } else { glm::vec3 transmitted; glm::vec3 ft = specularBtfd->sampleF(sr,incoming,transmitted); Ray transmittedRay(sr.hitPoint,transmitted); glm::vec3 reflectedColor = sr.world.getTracer()->traceRay(reflectedRay,sr.depth + 1) * fabs(glm::dot(sr.normal,reflected)); fr.x *= reflectedColor.x; fr.y *= reflectedColor.y; fr.z *= reflectedColor.z; glm::vec3 transmittedColor = sr.world.getTracer()->traceRay(transmittedRay,sr.depth + 1) * fabs(glm::dot(sr.normal,transmitted)); ft.x *= transmittedColor.x; ft.y *= transmittedColor.y; ft.z *= transmittedColor.z; L += fr + ft; } return L; }
glm::vec3 Dielectric::shade(const ShadeRec& sr)const { glm::vec3 L; //glm::vec3 L = Phong::shade(sr); glm::vec3 reflected; glm::vec3 incoming(-sr.ray.getDirection()); glm::vec3 fr = fresnelBrdf->sampleF(sr,incoming,reflected); Ray reflectedRay(sr.hitPoint,reflected); float t = 0.0f; glm::vec3 Lr, Lt; float nDotR = glm::dot(sr.normal,reflected); if(fresnelBtdf->tir(sr)) { if(nDotR < 0.0) { //reflected ray is inside Lr = sr.world.getTracer()->traceRay(reflectedRay,t,sr.depth + 1); glm::vec3 colorFilter = glm::pow(colorFilterIn,glm::vec3(t)); L.x += colorFilter.x * Lr.x; L.y += colorFilter.y * Lr.y; L.z += colorFilter.z * Lr.z; } else { //reflected ray is outside Lr = sr.world.getTracer()->traceRay(reflectedRay,t,sr.depth + 1); glm::vec3 colorFilter = glm::pow(colorFilterOut,glm::vec3(t)); L.x += colorFilter.x * Lr.x; L.y += colorFilter.y * Lr.y; L.z += colorFilter.z * Lr.z; } } else { //no total internal reflection glm::vec3 transmitted; glm::vec3 ft = fresnelBtdf->sampleF(sr,incoming,transmitted); Ray transmittedRay(sr.hitPoint,transmitted); float nDotT = glm::dot(sr.normal,transmitted); if(nDotT > 0.0) { //reflected ray is inside Lr = sr.world.getTracer()->traceRay(reflectedRay,t,sr.depth +1) * fabs(nDotR); Lr.x *= fr.x; Lr.y *= fr.y; Lr.z *= fr.z; glm::vec3 colorFilterR = glm::pow(colorFilterIn,glm::vec3(t)); L.x += colorFilterR.x * Lr.x; L.y += colorFilterR.y * Lr.y; L.z += colorFilterR.z * Lr.z; //transmitted ray is outside Lt = sr.world.getTracer()->traceRay(transmittedRay,t,sr.depth +1) * fabs(nDotT); Lt.x *= ft.x; Lt.y *= ft.y; Lt.z *= ft.z; glm::vec3 colorFilterT = glm::pow(colorFilterOut, glm::vec3(t)); L.x += colorFilterT.x * Lt.x; L.y += colorFilterT.y * Lt.y; L.z += colorFilterT.z * Lt.z; } else { //reflected ray is outisde Lr = sr.world.getTracer()->traceRay(reflectedRay,t,sr.depth +1) * fabs(nDotR); Lr.x *= fr.x; Lr.y *= fr.y; Lr.z *= fr.z; glm::vec3 colorFilterR = glm::pow(colorFilterOut,glm::vec3(t)); colorFilterR.x *= Lr.x; colorFilterR.y *= Lr.y; colorFilterR.z *= Lr.z; L += colorFilterR; //transmitted ray is inside Lt = sr.world.getTracer()->traceRay(transmittedRay,t,sr.depth +1) * fabs(nDotT); Lt.x *= ft.x; Lt.y *= ft.y; Lt.z *= ft.z; glm::vec3 colorFilterT = glm::pow(colorFilterIn,glm::vec3(t)); colorFilterT.x *= Lt.x; colorFilterT.y *= Lt.y; colorFilterT.z *= Lt.z; L += colorFilterT; } } return L; }
/** * Compute recursivly the color contribution of one ray. * @param currentRay the ray whose contribution is computed. * @return the color associated with the ray contribution. */ glm::vec3 Scene::getColor(const ray::Ray & currentRay) { glm::vec3 color(0,0,0); scene::Intersection inter; if(intersect(currentRay,inter)) { glm::vec3 pointHit=inter.getPoint(); glm::vec3 normalHit=inter.getNormal(); glm::vec3 incident = currentRay.getDirection(); materials::Material * materialHit=inter.getMaterial(); float alpha = 1.0; // Part 1 : Light contribution for(iterator_light it=begin_light(); it!=end_light();++it) { glm::vec3 direction=(*it)->getPosition()-pointHit; ray::ShadowRay shadowRay(pointHit,direction,0.001, getCamera()->getFarPlan(),1); scene::Intersection dummyInter; ray::ShadowRay dummyRay(shadowRay); float attenuation = 0.0; while(intersect(shadowRay,dummyInter)) { shadowRay.setOrigin(dummyInter.getPoint()); attenuation+=1-dummyInter.getMaterial()->getTransmissionAttenuation(); if(attenuation >= 1.0) { attenuation=1.0; break; } } glm::vec3 matColor= materialHit->computeBRDF(shadowRay, normalHit); glm::vec3 lightColor=(*it)->powerAt(pointHit); glm::vec3 lightContribution=componentProduct(matColor, lightColor); lightContribution = glm::clamp(lightContribution, glm::vec3(0),glm::vec3(1)); alpha = materialHit->getTransmissionAttenuation(); color+=(1-attenuation)*(1-alpha)*lightContribution; } // Part 2 : Other rays // 2 steps : computing ray direction then getting color recursively if(currentRay.getBounces() > 0) { float coeff=fabs(glm::dot(currentRay.getDirection(),normalHit)); // Reflexion ray if(coeff*materialHit->getReflexionAttenuation()>EPSILON) { ray::ReflexionRay reflexionRay(pointHit,glm::reflect(incident,normalHit), 0.001,getCamera()->getFarPlan(), currentRay.getBounces()-1); color+=coeff*materialHit->getReflexionAttenuation()* getColor(reflexionRay); } // Transmission ray float alpha = materialHit->getTransmissionAttenuation(); alpha*=coeff; if(alpha>EPSILON) { glm::vec3 dummyVec = glm::dot(incident,normalHit) * normalHit - incident; float sinT1 = glm::dot(dummyVec,dummyVec); float cosT1 = sqrt(fabs(1-sinT1*sinT1)); float eta12 = currentRay.getMRI()/materialHit->getMRI(); float c = 1-eta12*eta12*sinT1*sinT1; c = (c>0) ? c : 0; float dF1 = (eta12 * cosT1 - sqrt(c)); glm::vec3 transmittedDirection = eta12 * incident + (dF1 * normalHit); transmittedDirection = glm::normalize(transmittedDirection); ray::TransmissionRay transmittedRay(pointHit, transmittedDirection, 0.001, getCamera()->getFarPlan(), currentRay.getBounces()-1, (eta12==1.0) ? 1.0 : materialHit->getMRI() ); color+=alpha*getColor(transmittedRay); } } } return color; }