Color3 PathIntegrator::li(const Scene *scene_ptr, const Ray &ray, const hitRecord &record, const Sample* sample_ptr, Random462 &rng) { Color3 L = Color3::Black(); if (record.shape_ptr == NULL) return L; for (uint32_t j = 0; j < num_per_path; j++) { bool specular_bounce = false; const hitRecord *current_h_ptr = &record; hitRecord path_record; Ray current_ray(ray); Color3 path_weight = Color3::White(); LightSampleSet light_set; BSDFSampleSet bsdf_set; BSDFSample path_sample; float select; light_set.num = 1; bsdf_set.num = 1; Color3 new_path_l; Color3 bsdf_factor; Color3 weight_records[7]; for (uint32_t i = 0; i < max_depth; i++) { Vector3 p = current_h_ptr->p; Vector3 n = current_h_ptr->n; Vector3 wo = -current_ray.d; BSDF *bsdf_ptr = current_h_ptr->bsdf_ptr; if (i == 0 || specular_bounce) { if (current_h_ptr->shape_ptr->light_ptr != NULL) { L += path_weight * current_h_ptr->shape_ptr->light_ptr->L(n, wo); } } // TODO: hit light source? if (current_h_ptr->shape_ptr->light_ptr != NULL) break; if (i < sample_depth) { light_set.light_1d = (float*) sample_ptr + 2 + light_offsets[j * sample_depth + i].offset_1d; light_set.light_2d = (float*) sample_ptr + 2 + light_offsets[j * sample_depth + i].offset_2d; bsdf_set.bsdf_1d = (float*) sample_ptr + 2 + bsdf_offsets[j * sample_depth + i].offset_1d; bsdf_set.bsdf_2d = (float*) sample_ptr + 2 + bsdf_offsets[j * sample_depth + i].offset_2d; float* path_sample_ptr = (float*) sample_ptr + 2 + path_offsets[j * sample_depth + i].offset_2d; path_sample.r1 = path_sample_ptr[0]; path_sample.r2 = path_sample_ptr[1]; path_sample.c = *((float*) sample_ptr + 2 + path_offsets[j * sample_depth + i].offset_1d); select = *((float*)sample_ptr + 2); } else { light_set.light_1d = NULL; light_set.light_2d = NULL; bsdf_set.bsdf_1d = NULL; bsdf_set.bsdf_2d = NULL; path_sample.r1 = rng.random(); path_sample.r2 = rng.random(); path_sample.c = rng.random(); select = -1; } new_path_l = path_weight * uniform_sample_one_light(scene_ptr, bsdf_ptr, p, n, wo, select, &light_set, &bsdf_set, rng); L += new_path_l; Vector3 wi; float path_pdf; BxDFType flags; Color3 f = bsdf_ptr->sample_f(wo, path_sample.r1,path_sample.r2, path_sample.c, &wi, n, &path_pdf, BSDF_ALL, &flags); if (f == Color3::Black() || path_pdf < 1e-3) break; specular_bounce = (flags & BSDF_SPECULAR) > 0; bsdf_factor = f * std::fabs(dot(n, wi)) / path_pdf; weight_records[i] = bsdf_factor; path_weight *= bsdf_factor; if (i >= sample_depth) { // TODO : how to determine the prob? float continue_prob = std::min(0.5, path_weight.relative_luminance()); if (rng.random() > continue_prob) break; path_weight /= continue_prob; } else if (i >= max_depth) { break; } Ray path_ray(p, wi); if (!scene_ptr->hit(path_ray, 1e-3, BIG_NUMBER, path_record, true)) { if (specular_bounce) for (uint32_t i = 0; i < scene_ptr->num_lights(); i++) L += path_weight * scene_ptr->get_lights()[i]->Le(path_ray); break; } current_ray.e = path_ray.e; current_ray.d = path_ray.d; current_h_ptr = &path_record; } } L /= num_per_path; return L; }
rose::Spectrum rose::PathTracerIntegrator::IncomingRadiance(const rose::Ray &ray, const rose::RayInterval &interval, const rose::Scene &scene, uint32_t) const { // Final incoming radiance and accumulation value Spectrum L(0.f), beta(1.f); Ray current_ray(ray); RayInterval current_interval(interval); bool specular_bounce = false; uint32_t bounces; // Keep track of specular bounce for (bounces = 0;; ++bounces) { SurfaceInteraction interaction; bool found_interaction = scene.Intersect(current_ray, current_interval, &interaction); // Possibly add emission if (bounces == 0 || specular_bounce) { // Add emitted light if (found_interaction) { L += beta * interaction.Le(Normalize(-current_ray.Direction())); } else { for (const auto &light : scene.Lights()) { L += beta * light->Le(current_ray); } } } // Terminate path if ray escaped or max depth reached if (!found_interaction || bounces >= max_depth) { break; } // Compute scattering function std::unique_ptr<BSDF> bsdf = interaction.CreateBSDF(true); // Get shading variables const Vector3f n = interaction.sh_frame.N(); const Vector3f wo = Normalize(-current_ray.Direction()); // Loop over all lights and add direct contribution for (const auto &light : scene.Lights()) { // Sample light LightSample light_sample; OcclusionTester occlusion_tester; Spectrum Li = light->SampleLi(interaction, sampler->Next2D(), &light_sample, &occlusion_tester); // Check light return if (Li.IsBlack() || light_sample.pdf == 0.f) { continue; } // Evaluate BSDF Spectrum f = bsdf->F(wo, light_sample.wi); if (!f.IsBlack() && occlusion_tester.Unoccluded(scene)) { L += beta * f * Li * AbsDotProduct(n, light_sample.wi) / light_sample.pdf; } } // Sample BSDF to get new path BXDFSample bsdf_sample; Spectrum f = bsdf->SampleF(wo, sampler->Next2D(), &bsdf_sample); if (f.IsBlack() || bsdf_sample.pdf == 0.f) { break; } // Update beta beta *= f * AbsDotProduct(bsdf_sample.wi, n) / bsdf_sample.pdf; // Check if bounce is specular specular_bounce = (bsdf_sample.sampled_type & SPECULAR) != 0; // Compute new ray current_ray = interaction.SpawnRay(bsdf_sample.wi); // Possibly terminate path with Russian roulette if (bounces > 3) { float q = std::max(0.05f, 1.f - beta.Norm()); if (sampler->Next1D() < q) { break; } beta /= 1.f - q; } } return L; }
Spectrum PathTracer::Integration ( const Scene * thisScene, const Ray & ray ) { Spectrum intensity; Attenuation throughput; throughput.resetOne(); Intersection intersectionInfo; double cos_i = 0; double pdf = 1; double rr = 1; Ray current_ray( ray.origin, ray.direction ); size_t current_depth = 0; while ( !( current_depth == maxDepth ) ) { if ( !thisScene->IntersectionWithScene( current_ray, intersectionInfo ) ) break; Objects * obj = intersectionInfo.object; if ( obj->emitter ) { intensity += Attenuate_Light_Spectrum( throughput, obj->emission ); } BRDFModels * brdf = obj->brdf_model; // Get surface (macro) normal direction Vector geometryNormalDirection; geometryNormalDirection = intersectionInfo.normal; Vector sampledNextDirection( 0, 0, 0 ); Attenuation attenuationFactor; attenuationFactor = brdf->SampleBRDF( current_ray.direction, sampledNextDirection, geometryNormalDirection, pdf ); // double randnum = getUniformRandomNumber ( 0.0 , 0.99 ); // if ( randnum < rr) // break; attenuationFactor.Scaled_by_Spectrum_Value( obj->material_type->color ); cos_i = AbsDot( sampledNextDirection, geometryNormalDirection ); throughput = throughput * ( attenuationFactor * ( cos_i / ( rr * pdf ) ) ); // update ray current_ray.origin = intersectionInfo.intersectionPoint; current_ray.direction = sampledNextDirection; current_depth++; } return intensity; }