glm::vec3 DirectLightingIntegrator::LightPDFEnergy(const Intersection &light_sample_isx, const Intersection &isx, const Ray &light_sample, const glm::vec3 &woW, unsigned int n_light, unsigned int n_brdf) { glm::vec3 ray_color(0, 0, 0); Material* M = isx.object_hit->material; //material of point hit Geometry* L = light_sample_isx.object_hit; //light source float lightPDF = L->RayPDF(light_sample_isx, light_sample); //if light pdf is less than zero, return no light if (lightPDF <= 0.0f) { return glm::vec3(0); } //get BRDFPDF and energy from the material float brdfPDF; float dummy; glm::vec3 M_energy(M->EvaluateScatteredEnergy(isx, woW, light_sample.direction, brdfPDF)); //terminate early if brdf pdf is zero; if (brdfPDF <= 0.0f) return ray_color; glm::vec3 L_energy(L->material->EvaluateScatteredEnergy(light_sample_isx, woW, -light_sample.direction, dummy)); float W = MIS(lightPDF, brdfPDF); //MIS power heuristic weighing function ray_color = ComponentMult(L_energy, M_energy); // multiply the energy of the light with BRDF reflected energy ray_color = ComponentMult(ComponentMult(ray_color, M->base_color), isx.texture_color); ray_color = ray_color*W/lightPDF*glm::abs(glm::dot(isx.normal, light_sample.direction)); // and then do the solid angle PDF and the cosine return ray_color; }
glm::vec3 DirectLightingIntegrator::BxDFPDFEnergy(const Intersection &isx, const glm::vec3 &woW, unsigned int n_light, unsigned int n_brdf) { glm::vec3 ray_color(0, 0, 0); glm::vec3 wiW(0, 0, 0);//this will be obtained by sampling BxDf Material* M = isx.object_hit->material; //material of point hit float brdfPDF; float lightPDF; float dummy; float rand1 = unif_distribution(mersenne_generator); float rand2 = unif_distribution(mersenne_generator); glm::vec3 M_energy(M->SampleAndEvaluateScatteredEnergy(isx, woW, wiW, brdfPDF, rand1, rand2)); //use sampled wiW to check if I can hit the light Ray shadow_feeler(isx.point, wiW); Intersection light_isx = intersection_engine->GetIntersection(shadow_feeler); Geometry* L; //this holds the intersected light source //terminate early if brdf pdf is zero; if (brdfPDF <= 0.0f) return ray_color; if (light_isx.object_hit == NULL)//if ray didnt hit anything return ray_color; if (light_isx.object_hit->material->is_light_source) { L = light_isx.object_hit; lightPDF = L->RayPDF(light_isx, shadow_feeler); if (lightPDF <= 0) { return ray_color; } glm::vec3 L_energy(L->material->EvaluateScatteredEnergy(light_isx, woW, -shadow_feeler.direction, dummy)); float W = MIS(brdfPDF, lightPDF); ray_color = ComponentMult(L_energy, M_energy); ray_color = ComponentMult(ComponentMult(ray_color, M->base_color), isx.texture_color); ray_color = ray_color*W/brdfPDF*glm::abs(glm::dot(isx.normal, shadow_feeler.direction)); return ray_color; } else { return ray_color; } }
int main() { #ifndef ONLINE_JUDGE freopen("c.in", "rt", stdin); //freopen("c.txt", "wt", stdout); #endif int n = 200; while(true) { for (int i = 0; i < n; i++) { W[i + 1] = rand(); if(rand()%2) W[i+1] *= -1; } assert(MIS(n) == BB_Tight(n)); } return 0; }
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; }