//trace the ray and find out the color at its intersection point with the scene Vector4 Renderer::traceColor(Ray ray, Scene* scene, unsigned int recDepth) { Vector4 color(0,0,0); ray.min_t = ray.min_t + ray.epsilon_t; IntersectionData* iData = scene->intersect(ray); if (iData && (recDepth < m_recursionDepth)) { // sucessful intersection test //=== EXERCISE 2.2.3 === Vector3 N = (iData->normal).normalize(); Vector3 R = ((N.operator*(2)).operator*(N.dot(-ray.direction))+ray.direction).normalize(); // calculate R Ray newRay(iData->position, R); newRay.min_t = newRay.min_t + ray.epsilon_t; color = traceColor(newRay, scene, recDepth+1).operator*(iData->reflectionPercentage) + ( m_shader->shade(iData, scene).operator*(1 - iData->reflectionPercentage)) ; // recursion } else { color = m_shader->shade(iData, scene); //color = scene->getBackground(); // background color } // clean if (iData!=NULL){ delete(iData); } return color.clamp01(); }
Spectrum<constant::spectrumSamples> PathBRDF::randomBRDFSampling(bool& randomBRDFsampled, Spectrum<constant::spectrumSamples>& L, const Vector3D& wo, const MaterialBRDF& material, const Intersection& intersection, const TracerSpectrum& pathTracer, const int bounce, const BRDFType type) const { Vector3D wi(INFINITY, INFINITY, INFINITY); //Sample brdf of the give type. Spectrum<constant::spectrumSamples> f = material.samplef(&wi, wo, intersection, type); if(wi.x != INFINITY && wi.y != INFINITY && wi.z != INFINITY) { //BRDF has been sampled. randomBRDFsampled = true; //Normalize wi. wi.normalize(); //Get pdf of wi sampled from brdf. float pdf = material.pdf(wi, wo, intersection, type); Spectrum<constant::spectrumSamples> weight(0.0f); //Check pdf to avoid 0/0 division (and NaN generation). //A spectrum composed of NaN values could bend all samples //during sum in Tracer classes. if(pdf > 0.0f) { weight = (f * fabsf(wi.dot(intersection.normal))) / pdf; } else { //Weight is 0, so all bounces will be useless. return L; } //Setup new ray to be traced. Ray newRay(MathUtils::addEpsilon(intersection.point, intersection.normal), wi); //Rendering equation with recursive path tracing calculation. L = L + weight * pathTracer.trace(newRay, bounce - 1); } return L; }
int main() { Film film(401, 401); ngl::Vec3 pos(0, 0, 0); ngl::Vec3 lookAt(0, 0, 100); ngl::Vec3 up(0, 1, 0); Camera cam(pos, lookAt, up, 90.0, &film); Ray newRay(ngl::Vec3(0, 0, 0), ngl::Vec3(0, 0, 1)); //cam.generateRay(200, 200, &newRay); std::cout << newRay.m_origin << newRay.m_direction << newRay.m_invDirection << std::endl; IsectData intersection; //film.show(); //std::thread task(&Film::show, &film); auto mesh = Meshes::scene1(); auto green = std::make_shared<Material>(); green->m_diffuseColour = SDL_Color{0, 255, 0, 255}; std::shared_ptr<Primative> scenePrim = std::make_shared<GeometricPrim>(mesh, green); Renderer new_renderer(&cam, &film, scenePrim); new_renderer.renderImage(); //task.join(); film.show(); return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { std::cout << "///////////////////// POINT //////////////////////////////////" << std::endl; Point newPoint(0,1,2); std::cout << "x : " << newPoint.x() << std::endl; std::cout << "y : " << newPoint.y() << std::endl; std::cout << "z : " << newPoint.z() << std::endl; newPoint.setY(5); Point pointB; std::cout << "y : " << pointB.y() << std::endl; if (! newPoint.isNotEqual(pointB)) std::cout << "equal" << std::endl; else std::cout << "nonEqual" << std::endl; std::cout << "///////////////////// VECTOR //////////////////////////////////" << std::endl; Vector newVector, vect; newVector.setCoordonne(-8.0, 5.0, 6.0); Vector vec2(newPoint, pointB); Vector vec3(newVector, vec2); std::cout << "x2 : " << vec2.x() << std::endl; std::cout << "y2 : " << vec2.y() << std::endl; std::cout << "z2 : " << vec2.z() << std::endl; if (vect.vecteurNull()) std::cout << "vec Null" << std::endl; else std::cout << "vec Non NUll" << std::endl; if (newVector.vecteurNull()) std::cout << "newVector Null" << std::endl; else std::cout << "newVector Non NUll" << std::endl; std::cout << "dot => " << newVector.dot(vec2) << std::endl; std::cout << "x3 : " << vec3.x() << std::endl; std::cout << "y3 : " << vec3.y() << std::endl; std::cout << "z3 : " << vec3.z() << std::endl; std::cout << "///////////////////// RAY //////////////////////////////////" << std::endl; Ray newRay(pointB,newPoint); std::cout << "origine : " << newRay.P0().x() << ", " << newRay.P0().y() << ", " << newRay.P0().z()<< std::endl; std::cout << "direction : " << newRay.P1().x() << ", " << newRay.P1().y() << ", " << newRay.P1().z() << std::endl; std::cout << "///////////////////// Triangle //////////////////////////////////" << std::endl; Point pointC(6,8,5); Point V2(0,-1,-10); Point V0(5,-50,59); Point V1(9,0,-25); Triangle newTriangle(V0,V1,V2); std::cout << "coordonnee : " << newTriangle.V0().x() << ", " << newTriangle.V1().y() << ", "<< newTriangle.V2().z() << std::endl; std::cout << "///////////////////// Point/Triangle //////////////////////////////////" << std::endl; Point I; std::cout << newRay.P0().x() + 6 * newVector.x() << std::endl; std::cout << newRay.P0().y() + 6 * newVector.y() << std::endl; std::cout << newRay.P0().z() + 6 * newVector.z() << std::endl; I.setCoordonne(newRay.P0().x() + 6 * newVector.x(), newRay.P0().y() + 6 * newVector.y(), newRay.P0().z() + 6 * newVector.z()); std::cout << "coucou" << std::endl; std::cout << "///////////////////// test intersect //////////////////////////////////" << std::endl; int test; test = intersect3D_RayTriangle(newRay, newTriangle, I); std::cout << "I : " << I.x() << ", " << I.y() <<", "<< I.z() << "\n test : " << test << std::endl; std::cout << "///////////////////// VECTOR/Triangle //////////////////////////////////" << std::endl; Vector newVector2(newTriangle.V0(), newTriangle.V1()); std::cout << "x : " << newVector2.x() << std::endl; std::cout << "y : " << newVector2.y() << std::endl; std::cout << "z : " << newVector2.z() << std::endl; return 0; }
inline Spectrum EstimateDirectIllumination ( const Scene * thisScene, const Intersection * intersectionInfo, const Ray & ray ) { Spectrum intensity; Objects * obj = intersectionInfo->object; BRDFModels * brdf = obj->brdf_model; Vector newRayDirection; Vector normalDirection; normalDirection = intersectionInfo->normal; Attenuation attenuationFactor; bool delta_brdf_hitEmissive = false; bool occludedByObjects = true; Spectrum lightIntensity; if ( obj->brdf_model->surfaceFlag == surface_delta ) { // get reflection direction // generate new ray // intersect with scene to see if the ray hit a light source normalDirection = intersectionInfo->normal; attenuationFactor = brdf->SampleBRDF( ray.direction, newRayDirection, normalDirection ); Ray newRay( intersectionInfo->intersectionPoint, newRayDirection ); Intersection newIntersectionInfo; if ( !thisScene->IntersectionWithScene( newRay, newIntersectionInfo ) ) return Spectrum(); if ( newIntersectionInfo.object->emitter == true ) { delta_brdf_hitEmissive = true; lightIntensity = newIntersectionInfo.object->emission; attenuationFactor.Scaled_by_Spectrum_Value( obj->material_type->color ); intensity = Attenuate_Light_Spectrum( attenuationFactor, lightIntensity ); } } else { Spectrum lightSourceSamplingContribution; Spectrum brdfSamplingContribution; // light source sampling evaluation Objects * light; light = thisScene->AquireOneOfEmissiveObjects(); double light_pdf = 0; // to be added double brdf_pdf = 0; double light_weight = 0; double brdf_weight = 0; Pnt3D pointOnLight; int i = 0; while ( i < 2 && occludedByObjects == true ) { pointOnLight = light->samplePointOnObject(); occludedByObjects = thisScene->Occluded( intersectionInfo->intersectionPoint, pointOnLight, light ); i++; } if ( occludedByObjects == false ) { newRayDirection = pointOnLight - intersectionInfo->intersectionPoint; brdf->BRDF( ray.direction, newRayDirection, attenuationFactor ); attenuationFactor.Scaled_by_Spectrum_Value( obj->material_type->color ); // light pdf light_pdf = light->PDF_in_solid_angle ( pointOnLight, intersectionInfo->intersectionPoint, newRayDirection ); // brdf_pdf = obj->brdf_model->PDF ( ray.direction , newRayDirection ); // geomery term???? // according to PBRT page 765, geometric term cancel out ??? Vector normal_on_light; light->getNormalDirection( pointOnLight, normal_on_light ); double geometryTerm = GeometricTerm( ray, normalDirection, pointOnLight, normal_on_light ); lightIntensity = light->emission; lightSourceSamplingContribution = Attenuate_Light_Spectrum( attenuationFactor, lightIntensity ) * geometryTerm / light_pdf; } // evaluate BRDF sampling if ( light->isDeltaEmitter == false ) { attenuationFactor = brdf->SampleBRDF( ray.direction, newRayDirection, normalDirection ); Ray newRay( intersectionInfo->intersectionPoint, newRayDirection ); Intersection newIntersectionInfo; if ( thisScene->IntersectionWithScene( newRay, newIntersectionInfo ) ) if ( newIntersectionInfo.object->emitter == true ) { { brdf_pdf = obj->brdf_model->PDF( ray.direction, newIntersectionInfo.normal, newRayDirection ); // weight = BalanceHeuristic ( 1 , brdf_pdf , 1 , light_pdf ); attenuationFactor.Scaled_by_Spectrum_Value( obj->material_type->color ); double cos_i = AbsDot( ray.direction, normalDirection ); brdfSamplingContribution += Attenuate_Light_Spectrum( attenuationFactor, newIntersectionInfo.object->emission ) * cos_i / brdf_pdf; } } } light_weight = light_pdf / ( brdf_pdf + light_pdf ); brdf_weight = brdf_pdf / ( brdf_pdf + light_pdf ); intensity += lightSourceSamplingContribution * light_weight; intensity += brdfSamplingContribution * brdf_weight; if ( intensity.HasNaNs() ) // printf ( "has nan" ); return Spectrum(); return intensity; } }
Spectrum PathTracer::Integration ( const Scene * thisScene, const Ray & ray, size_t currentDepth ) const { // Russian Roulette // probility to stop this path double rr = 0.01; double randnum = getUniformRandomNumber( 0.0, 0.99 ); if ( randnum < rr && currentDepth > 5 ) return Spectrum(); if ( currentDepth == maxDepth ) return Spectrum(); Intersection intersectionInfo; // check intersection between ray and scene if ( ! thisScene->IntersectionWithScene( ray, intersectionInfo ) ) return Spectrum(); // if there is an intersection Spectrum intensity; Spectrum emission; Objects * obj = intersectionInfo.object; if ( obj->emitter ) { emission = obj->emission; } BRDFModels * brdf = obj->brdf_model; // Get surface (macro) normal direction Vector geometryNormalDirection ( 0 , 0 , 0 ); Vector sampledNextDirection ( 0 , 0 , 0 ); geometryNormalDirection = intersectionInfo.normal; double pdf = 0; Attenuation attenuationFactor = brdf->SampleBRDF( ray.direction, sampledNextDirection, geometryNormalDirection, pdf ); Ray newRay( intersectionInfo.intersectionPoint, sampledNextDirection ); Spectrum Li = Integration( thisScene, newRay, currentDepth + 1 ); if ( !Li.isEmpty() ) { attenuationFactor.Scaled_by_Spectrum_Value( obj->material_type->color ); double cos_i = AbsDot( sampledNextDirection, geometryNormalDirection ); intensity += Attenuate_Light_Spectrum( attenuationFactor, Li ) * cos_i / pdf; } // weight the radiance back after Ruassian Roulette intensity = ( currentDepth > 5 ) ? ( intensity / ( 1 - rr ) ) : intensity; ASSERT_NAN( intensity ); return emission + intensity; }
// with direct illumination // this one actually does not do the right things on DI with MIS // left only for reference Spectrum PathTracer::IntegrationWithDI ( const Scene * thisScene, const Ray & ray, size_t currentDepth ) const { // Russian Roulette // probility to stop this path double rr = 0.01; double randnum = getUniformRandomNumber( 0.0, 1.0 ); if ( randnum < rr && currentDepth > 5 ) return Spectrum(); if ( currentDepth == maxDepth ) return Spectrum(); Intersection intersectionInfo; // check intersection between ray and scene if ( !thisScene->IntersectionWithScene( ray, intersectionInfo ) ) return Spectrum(); // if there is an intersection Spectrum intensity; Spectrum lightSourceSamplingContribution; Spectrum brdfSamplingContribution; double brdf_pdf = 0; double light_pdf = 0; double brdf_weight = 0; double light_weight = 0; Objects * obj = intersectionInfo.object; if ( obj->emitter ) { intensity += obj->emission; } BRDFModels * brdf = obj->brdf_model; // **************** evaluate direction illumination ****** if ( !obj->emitter ) EstimateDirectIllumination( thisScene, & intersectionInfo, ray, light_pdf, lightSourceSamplingContribution ); // ******************** end of direct illumination ********************** // BRDF sampling is evaluated twice???? Vector geometryNormalDirection; geometryNormalDirection = intersectionInfo.normal; Vector sampledNextDirection( 0, 0, 0 ); Attenuation attenuationFactor; attenuationFactor = brdf->SampleBRDF( ray.direction, sampledNextDirection, geometryNormalDirection, brdf_pdf ); Ray newRay( intersectionInfo.intersectionPoint, sampledNextDirection ); Spectrum Li = IntegrationWithDI( thisScene, newRay, currentDepth + 1 ); if ( !Li.isEmpty() ) { attenuationFactor.Scaled_by_Spectrum_Value( obj->material_type->color ); double cos_i = AbsDot( sampledNextDirection, geometryNormalDirection ); brdfSamplingContribution += Attenuate_Light_Spectrum( attenuationFactor, Li ) * cos_i; } if ( light_pdf == 0 && brdf_pdf == 0 ) { return intensity; } // MIS weight BalanceHeuristic( 1, light_pdf, 1, brdf_pdf, light_weight, brdf_weight ); intensity += lightSourceSamplingContribution * light_weight; intensity += brdfSamplingContribution * brdf_weight; intensity = ( currentDepth > 5 ) ? ( intensity / ( 1 - rr ) ) : intensity; ASSERT_NAN( intensity ); return intensity; }
Colour Raytracer::Trace(const Ray& ray, RandomGenerator* random, int depth, int depth2, std::list<IMedium*>& mediumList) { if(depth >= this->maxIterations) return Vec3(0,0,0); // First find intersection with closes geometry. IntersectResult result; geometry->Intersect(ray, result); // First depth2=0, we also include "singular light geometry" if(depth2 == 0 && this->singularLightGeometry) singularLightGeometry->Intersect(ray, result); if(result.distance >= std::numeric_limits<Scalar>::max()) return Vec3(0,0,0); //< Return "sky" radiance // Calculate position of intersection. Vec3 position = result.distance * ray.direction + ray.origin; Vec3 cameraDirection = -ray.direction; // Check for interaction with medium (scaterring) ColourScalar scateringWeight; Vec3 scatteringPos, scatteringDir; if(ray.medium->SampleScattering(ray.origin, result.normal, position, random, scateringWeight, scatteringPos, scatteringDir)) { Ray newRay(scatteringPos, scatteringDir); newRay.medium = ray.medium; return scateringWeight.CMultiply(Trace(newRay, random, depth+1, depth2, mediumList)); } // Now calculate mediums. bool isInsideMedium = cameraDirection * result.normal < 0; IMedium* insideMedium, *outsideMedium; if(isInsideMedium) { // FIXME: sometimes due to numerical errors, we ignore those hits (alternative - set to vacuum). if(mediumList.size() == 0) return Vec3(0,0,0); outsideMedium = mediumList.back(); insideMedium = ray.medium; } else { outsideMedium = ray.medium; insideMedium = result.material->insideMedium; } // Compute radiance of point. Vec3 L(0,0,0); // 1) self radiance if(SELF_LIGHTNING_BIT(depth, depth2) && result.material->surfaceLight != 0) L = SELF_LIGHTNING_MASK(depth, depth2, result.material->surfaceLight->Radiance(position, cameraDirection, result.normal)); // Early exit for non-reflective materials. This is useful for singular lights. if(result.material->bsdf == 0) return scateringWeight.CMultiply(L); SamplingType samplingType = result.material->bsdf->GetSamplingType(cameraDirection, result.normal); // 2) radiance from singular sources if(DIRECT_LIGHTNING_BIT(depth, depth2) && ((samplingType & Singular) != 0)) { for(std::vector<ISingularLight*>::iterator i = lights.begin(); i != lights.end(); i++) { ISingularLight* light = *i; Vec3 towardsLightDirection; // We can use radiance at position for point lights (no translate). Vec3 Li = light->Radiance(position, towardsLightDirection, geometry); // Early exit for shadowed lights (no BRDF execution) && when backfacing lights. if(Li.x == 0 && Li.y == 0 && Li.z == 0) continue; // Weights with cosine. Vec3 t = (result.normal * towardsLightDirection)*Li.CMultiply(result.material->bsdf->BSDF(position, result.normal, cameraDirection, towardsLightDirection, result.materialData, insideMedium, outsideMedium)); L += DIRECT_LIGHTNING_MASK(depth, depth2, t); } } // 3) caustics map lightning if(PHOTONMAP_CAUSTICS_BIT(depth, depth2) && this->causticsMap) { std::vector<Photon*> photons; causticsMap->FindInRange(position, this->causticsPhotonMapGatherRadius, photons); // We estimate radiance at the point. Vec3 Flux(0,0,0); for(std::vector<Photon*>::iterator i = photons.begin(); i != photons.end(); i++) { Photon* p = *i; // Cull backfacings. if(p->outDirection * result.normal < 0) continue; Flux += p->power.CMultiply((result.normal * p->outDirection) * result.material->bsdf->BSDF(position, result.normal, p->outDirection, cameraDirection, result.materialData, insideMedium, outsideMedium)); } Vec3 t = Flux / (PI*this->causticsPhotonMapGatherRadius*this->causticsPhotonMapGatherRadius); L += PHOTONMAP_CAUSTICS_MASK(depth, depth2, t); } // Calculate number of samples int numberOfSamples = std::min(result.material->bsdf->GetMaxNumberOfSamples(cameraDirection, result.normal), (int)(this->secondaryRays * exp(-secondaryRayDecay*depth2))); bool isPerfectReflection = numberOfSamples <= this->gatherIterationThreeshold; //< This will only allow bigger iteration depth. // 4a) indirect photon map rendering (it is either this or hemisphere integration), reflection is still handled with // normal raytracing if(PHOTONMAP_GLOBAL_BIT(depth, depth2) && !isPerfectReflection && this->globalMap) { std::vector<Photon*> photons; globalMap->FindInRange(position, this->globalPhotonMapGatherRadius, photons); // We estimate radiance at the point. Vec3 Flux(0,0,0); for(std::vector<Photon*>::iterator i = photons.begin(); i != photons.end(); i++) { Photon* p = *i; // Cull backfacings. if(p->outDirection * result.normal < 0) continue; Flux += p->power.CMultiply((result.normal * p->outDirection) * result.material->bsdf->BSDF(position, result.normal, p->outDirection, cameraDirection, result.materialData, insideMedium, outsideMedium)); } Vec3 t = Flux / (PI*this->globalPhotonMapGatherRadius*this->globalPhotonMapGatherRadius); L += PHOTONMAP_GLOBAL_MASK(depth, depth2, t); // We skip through return scateringWeight.CMultiply(L); } // 4b) integrated radiance over hemisphere if((samplingType & MultipleSample) == 0 || INDIRECT_LIGHTNING_BIT(depth, depth2) == false) return scateringWeight.CMultiply(L); if(depth2 < this->maxGatherIterations || isPerfectReflection) { // If perfect reflection, we need only one ray to approximate. for(int i = 0; i < numberOfSamples; i++) { Vec3 newDirection; ColourScalar S = result.material->bsdf->Sample(i, numberOfSamples, position, result.normal, cameraDirection, random, result.materialData, insideMedium, outsideMedium, newDirection); // Trace new ray. Ray newRay(position, newDirection); bool needsPop = false, needsPush = false; Scalar translateInwards = -1; if(isInsideMedium) { // In-Out combination if(newDirection * result.normal > 0) { newRay.medium = mediumList.back(); mediumList.pop_back(); needsPush = true; translateInwards = 1; } // In-In combination else newRay.medium = ray.medium; } else { // Out-out combination if(newDirection * result.normal > 0) newRay.medium = ray.medium; else { newRay.medium = result.material->insideMedium; mediumList.push_back(ray.medium); needsPop = true; translateInwards = 1; } } // Translation of ray position so the whole solid angle can be sampled (also in corners) newRay.origin = newRay.origin + (translateInwards * this->hitTranslate) * ray.direction; ColourScalar newL = Trace(newRay, random, depth+1, depth2 + (isPerfectReflection ? 0 : 1), mediumList); // Undo medium list to prev state if(needsPush) mediumList.push_back(newRay.medium); if(needsPop) mediumList.pop_back(); // NaN check (FIXME: must get rid of it and find the source). if(newL.x != newL.x || newL.y != newL.y || newL.z != newL.z) { continue; } // Add already weighted result to intensity. Vec3 t = S.CMultiply(newL); L += INDIRECT_LIGHTNING_MASK(depth,depth2,t); } } return scateringWeight.CMultiply(L); }