glm::vec3 AllLightingIntegrator::TraceRay(Ray r, unsigned int depth) { //Terminate if too deep// if(depth >= max_depth) return glm::vec3(0, 0, 0); //---------------------// //Variables We may need// //for the first intersection with the scene and results Intersection isx; // first intersection hit, glm::vec3 Emitted_Light(0,0,0); // stores the color value of emitted light from the point hit glm::vec3 Direct_Lighting(0,0,0); //stores the direct lighting float epsilon(0.001); //small distance; glm::vec3 Indirect_Lighting(0,0,0);// stores the color value of reflected light from the point hit unsigned int n_light = 50; //number of light samples unsigned int n_brdf = 50; //number of brdf samples unsigned int n_indirect = 50; //number of sample splits //for BRDF PDF sampling // //---------------------// //Light Source sampling// //first find out who and where I hit isx = intersection_engine->GetIntersection(r); if(isx.object_hit == NULL) { return glm::vec3(0, 0, 0); } //traverse back the normal to prevent shadow acne isx.point = isx.point + epsilon*isx.normal; //pass in isx into EstimateDirectLighting //Direct_Lighting = EstimateDirectLighting(isx, num_samples, -r.direction); //if light source, add my light value to it if(isx.object_hit->material->is_light_source) {Emitted_Light = isx.object_hit->material->base_color;} else { Direct_Lighting = EstimateDirectLighting(isx, n_light, n_brdf, -r.direction); Indirect_Lighting = EstimateIndirectLighting(isx, n_indirect, -r.direction); } //---------------------// return Emitted_Light + Direct_Lighting + Indirect_Lighting; }
//Basic ray trace glm::vec3 Integrator::TraceRay(Ray r, unsigned int depth) { if (depth >= max_depth) { //do not continue if max depth is reached return glm::vec3(0.0f); } Intersection isx = this->intersection_engine->GetIntersection(r); //find intersection from ray isx.point = isx.point + 0.0001f*isx.normal; unsigned int N = 10; glm::vec3 direct_light = EstimateDirectLighting(isx,N); // glm::vec3 indirect_light = EstimateIndirectLighting(isx,N); return direct_light/* + indirect_light*/; }
glm::vec3 AllLightingIntegrator::LightIndirectEnergy(const Intersection &isx, unsigned int n_split, const glm::vec3 &woW) { int depth = 0; Intersection isx_temp = isx;//reflected intersection Intersection isx_light; //sampled intersection with "light source" glm::vec3 color_accum(0.0f, 0.0f, 0.0f); //accumulated color glm::vec3 color_temp(0.0f, 0.0f, 0.0f); glm::vec3 wi_temp(0.0f, 0.0f, 0.0f); glm::vec3 wo_temp(woW); glm::vec3 brdf_energy_accum(1.0f, 1.0f, 1.0f); glm::vec3 brdf_energy_temp(0.0f, 0.0f, 0.0f); glm::vec3 L_temp(0.0f, 0.0f, 0.0f); Material* M_temp = isx.object_hit->material; Geometry* obj_temp; //stores the temporary sampled object Ray sampler; float pdf_temp_brdf(0); float pdf_light_temp(0); float W(0); //for MIS float rand1 = unif_distribution(mersenne_generator); float rand2 = unif_distribution(mersenne_generator); float epsilon = 0.0001f; float throughput = 1.000001f; float russian = unif_distribution(mersenne_generator); //default samples for direct lighting when estimating the irradiance of some other point in the scene unsigned int n_light = 10; unsigned int n_brdf = 10; int light_source_choice(0); while(depth < max_depth && (russian < throughput || depth < 2)) { //sample a random point on a random object in the scene light_source_choice = rand()%scene->objects.count(); obj_temp = scene->objects[light_source_choice]; //if I hit a real light source, kill the ray if (scene->objects[light_source_choice]->material->is_light_source) break; isx_light = obj_temp->GetRandISX(rand1, rand2, isx_temp.normal); //update random numbers rand1 = unif_distribution(mersenne_generator); rand2 = unif_distribution(mersenne_generator); //make ray towards these points wi_temp = glm::normalize(isx_light.point - isx_temp.point); sampler = Ray(isx_temp.point, wi_temp); //update my light intersection isx_light = intersection_engine->GetIntersection(sampler); //this ray dies if it hit nothing or is blocked, kill the ray as well if(isx_light.object_hit == NULL) break; if(isx_light.object_hit != obj_temp) break; //to avoid shadow acne isx_light.point = isx_light.point + epsilon*isx_light.normal; //find out the pdf w/r/t light pdf_light_temp = obj_temp->RayPDF(isx_light, sampler); //if my pdf is negative, kill the ray as well if(pdf_light_temp <= 0) break; //update accumulated brdf energy brdf_energy_temp = M_temp->EvaluateScatteredEnergy(isx_temp, wo_temp, wi_temp, pdf_temp_brdf); brdf_energy_accum = ComponentMult(brdf_energy_accum, brdf_energy_temp); //find the direct lighting irradiance of this point towards my original intersection wo_temp = -wi_temp; //now the old incoming ray is the outgoing ray for the new intersection L_temp = EstimateDirectLighting(isx_light, n_light, n_brdf, wo_temp); W = MIS(pdf_light_temp, pdf_temp_brdf); //this is light source sampling so use the illumination equation for BRDF sampling to accumulate color color_temp = ComponentMult(brdf_energy_accum, L_temp); color_temp = ComponentMult(ComponentMult(color_temp, M_temp->base_color), isx_temp.texture_color); color_temp = color_temp*W/pdf_light_temp*glm::abs(glm::dot(isx_temp.normal, wi_temp)); color_accum = color_accum + color_temp/static_cast<float>(n_split); throughput = throughput * glm::max(glm::max(color_accum.r, color_accum.g), color_accum.b); //update the temporary material M_temp = isx_light.object_hit->material; isx_temp = isx_light; //update random number //update depth depth++; russian = unif_distribution(mersenne_generator); } return color_accum; }
glm::vec3 AllLightingIntegrator::BxDFIndirectEnergy(const Intersection &isx, unsigned int n_split, const glm::vec3 &woW) { int depth = 0; Intersection isx_temp = isx;//reflected intersection Intersection isx_light; //sampled intersection with "light source" glm::vec3 color_accum(0.0f, 0.0f, 0.0f); //accumulated color glm::vec3 color_temp(0.0f, 0.0f, 0.0f); glm::vec3 wi_temp(0.0f, 0.0f, 0.0f); glm::vec3 wo_temp(woW); glm::vec3 brdf_energy_accum(1.0f, 1.0f, 1.0f); glm::vec3 brdf_energy_temp(0.0f, 0.0f, 0.0f); glm::vec3 L_temp(0.0f, 0.0f, 0.0f); Material* M_temp = isx.object_hit->material; Ray sampler; float pdf_temp_brdf(0); float pdf_light_temp(0); float W(0); //for MIS float rand1 = unif_distribution(mersenne_generator); float rand2 = unif_distribution(mersenne_generator); float epsilon = 0.0001; float throughput = 1.000001f; float russian = unif_distribution(mersenne_generator); //default samples for direct lighting when estimating the irradiance of some other point in the scene unsigned int n_light = 10; unsigned int n_brdf = 10; while(depth < max_depth && (russian < throughput || depth < 2)) { //sample random brdf starting at the input isx direction to get reflected ray to begin brdf_energy_temp = M_temp->SampleAndEvaluateScatteredEnergy(isx_temp, wo_temp, wi_temp, pdf_temp_brdf, rand1, rand2); //update accumulated brdf energy brdf_energy_accum = ComponentMult(brdf_energy_accum, brdf_energy_temp); //use the sampled incoming ray to find a reflected intersection sampler = Ray(isx_temp.point, wi_temp); isx_light = intersection_engine->GetIntersection(sampler); //this ray dies if I hit a real light source or nothing if(isx_light.object_hit == NULL) break; else if(isx_light.object_hit->material->is_light_source) break; // //to avoid shadow acne isx_light.point = isx_light.point + epsilon*isx_light.normal; //find the direct lighting irradiance of this point towards my original intersection wo_temp = -wi_temp; //now the old incoming ray is the outgoing ray for the new intersection L_temp = EstimateDirectLighting(isx_light, n_light, n_brdf, wo_temp); //the direct lighting towards the isx pdf_light_temp = isx_light.object_hit->RayPDF(isx_light, sampler); W = MIS(pdf_temp_brdf, pdf_light_temp); //this is BRDF sampling so use the illumination equation for BRDF sampling to accumulate color color_temp = ComponentMult(brdf_energy_accum, L_temp); color_temp = ComponentMult(ComponentMult(color_temp, M_temp->base_color), isx_temp.texture_color); color_temp = color_temp*W/pdf_temp_brdf*glm::abs(glm::dot(isx_temp.normal, wi_temp)); color_accum = color_accum + color_temp/static_cast<float>(n_split); throughput = throughput * glm::max(glm::max(color_accum.r, color_accum.g), color_accum.b); //update the temporary material M_temp = isx_light.object_hit->material; isx_temp = isx_light; //update random number rand1 = unif_distribution(mersenne_generator); rand2 = unif_distribution(mersenne_generator); //update depth depth++; russian = unif_distribution(mersenne_generator); } return color_accum; }