@@ -394,7 +394,7 @@ SoftRasterizer::Intersection SoftRasterizer::Scene::traceScene(Ray &ray) {
394394 return ret;
395395}
396396
397- glm::vec3 SoftRasterizer::Scene::whittedRayTracing (Ray &ray, int depth) {
397+ glm::vec3 SoftRasterizer::Scene::whittedRayTracing (Ray &ray, int depth, const std:: size_t sample ) {
398398
399399 glm::vec3 final_color = this ->m_backgroundColor ;
400400
@@ -427,52 +427,65 @@ glm::vec3 SoftRasterizer::Scene::whittedRayTracing(Ray &ray, int depth) {
427427
428428 /* Phong illumation model*/
429429 if (intersection.material ->getMaterialType () ==
430- MaterialType::DIFFUSE_AND_GLOSSY ) {
431-
432- auto [shading2LightDir, lightAreaPdf] = sampleLight (hitPoint);
433-
434- /* Self-Intersection Problem Avoidance*/
435- glm::dvec3 perturbation = glm::dvec3 (hitPoint) + 1e-6 * glm::dvec3 (N);
436- Ray lightSampleRay (perturbation, shading2LightDir);
437-
438- Intersection lightSampleIntersection = traceScene (lightSampleRay);
439- if (!lightSampleIntersection.intersected ) {
440- return glm::vec3 (0 .f );
441- }
442-
443- // Diffuse reflection (Lambertian)
444- double diff = std::max (0 ., glm::dot (glm::dvec3 (N), shading2LightDir));
445-
446- // Specular reflection (Blinn-Phong)
447- glm::dvec3 reflectDir =
448- glm::normalize (glm::reflect (-shading2LightDir, glm::dvec3 (hitNormal)));
449- double spec =
450- std::pow (std::max (0 ., -glm::dot (glm::dvec3 (ray.direction ), reflectDir)),
451- intersection.material ->specularExponent );
452-
453- double distanceSquare =
454- glm::length2 (hitPoint - lightSampleIntersection.coords );
455- double timeSquare = lightSampleIntersection.intersect_time *
456- lightSampleIntersection.intersect_time ;
457- bool is_shadow = std::abs (timeSquare - distanceSquare) > 1e-6f ;
458-
459- spdlog::debug (" timeSquare={}, distanceSquare={},delta = {}, is_shadow={}" ,
460- timeSquare, distanceSquare,
461- std::abs (distanceSquare - timeSquare), is_shadow);
462-
463- // Compute light contribution
464- glm::vec3 ambient =
465- !is_shadow ? lightSampleIntersection.emit : glm::vec3 (0 .f );
466- glm::vec3 diffuse = !is_shadow
467- ? glm::vec3 (diff) * lightSampleIntersection.emit
468- : glm::vec3 (0 .f );
469- glm::vec3 specular = spec * glm::dvec3 (lightSampleIntersection.emit );
470-
471- // Accumulate to local sum
472- final_color = (ambient * intersection.material ->Ka ) +
473- (intersection.color * diffuse) +
474- (specular * intersection.material ->Ks );
475-
430+ MaterialType::DIFFUSE_AND_GLOSSY ) {
431+
432+ final_color = tbb::parallel_reduce (
433+ tbb::blocked_range<std::size_t >(0 , sample),
434+ glm::vec3 (0 .0f ), // Initial value
435+ [&](const tbb::blocked_range<std::size_t >& range,
436+ glm::vec3 local_sum) -> glm::vec3 {
437+ for (std::size_t i = range.begin (); i < range.end (); ++i) {
438+ auto [shading2LightDir, lightAreaPdf] = sampleLightOnCenter (hitPoint);
439+
440+ Ray lightSampleRay (hitPoint, shading2LightDir);
441+
442+ Intersection lightSampleIntersection = traceScene (lightSampleRay);
443+ if (!lightSampleIntersection.intersected ){
444+ // || (lightSampleIntersection.intersected && glm::length(lightSampleIntersection.emit) < m_epsilon)) {
445+ return glm::vec3 (0 .f );
446+ }
447+
448+ // Diffuse reflection (Lambertian)
449+ double diff = std::max (0 ., glm::dot (glm::dvec3 (N), shading2LightDir));
450+
451+ // Specular reflection (Blinn-Phong)
452+ glm::dvec3 reflectDir =
453+ glm::normalize (glm::reflect (-shading2LightDir, glm::dvec3 (hitNormal)));
454+ double spec =
455+ std::pow (std::max (0 ., -glm::dot (glm::dvec3 (ray.direction ), reflectDir)),
456+ intersection.material ->specularExponent );
457+
458+ double distanceSquare =
459+ glm::length2 (hitPoint - lightSampleIntersection.coords );
460+ double timeSquare = lightSampleIntersection.intersect_time *
461+ lightSampleIntersection.intersect_time ;
462+ bool is_shadow = std::abs (timeSquare - distanceSquare) > 1e-6f ;
463+
464+ spdlog::debug (" timeSquare={}, distanceSquare={},delta = {}, is_shadow={}" ,
465+ timeSquare, distanceSquare,
466+ std::abs (distanceSquare - timeSquare), is_shadow);
467+
468+ // Compute light contribution
469+ glm::vec3 ambient =
470+ !is_shadow ? lightSampleIntersection.emit : glm::vec3 (0 .f );
471+ glm::vec3 diffuse = !is_shadow
472+ ? glm::vec3 (diff) * lightSampleIntersection.emit
473+ : glm::vec3 (0 .f );
474+ glm::vec3 specular = spec * glm::dvec3 (lightSampleIntersection.emit );
475+
476+ // Accumulate to local sum
477+ local_sum = (ambient * intersection.material ->Ka ) +
478+ (intersection.color * diffuse) +
479+ (specular * intersection.material ->Ks );
480+ }
481+ return local_sum;
482+ },
483+ [](const glm::vec3& a, const glm::vec3& b) {
484+ return a + b;
485+ } // Combine partial results
486+ ) ;
487+
488+ final_color /= sample;
476489 }
477490
478491 else if (intersection.material ->getMaterialType () ==
@@ -518,14 +531,14 @@ glm::vec3 SoftRasterizer::Scene::whittedRayTracing(Ray &ray, int depth) {
518531 if (glm::length (refractPath) < 1e-6f || std::abs (kr - 1 .0f ) < 1e-6f ) {
519532 // prevent relfection and refraction from happening at the same time
520533 Ray reflectedRay (reflectCoord, reflectPath);
521- reflectedColor = whittedRayTracing (reflectedRay, depth + 1 );
534+ reflectedColor = whittedRayTracing (reflectedRay, depth + 1 , sample );
522535 kr = 1 .0f ;
523536 } else {
524537 Ray reflectedRay (reflectCoord, reflectPath);
525538 Ray refractedRay (refractCoord, refractPath);
526539
527- reflectedColor = whittedRayTracing (reflectedRay, depth + 1 );
528- refractedColor = whittedRayTracing (refractedRay, depth + 1 );
540+ reflectedColor = whittedRayTracing (reflectedRay, depth + 1 , sample );
541+ refractedColor = whittedRayTracing (refractedRay, depth + 1 , sample );
529542 }
530543
531544 final_color = glm::clamp (reflectedColor * kr + refractedColor * (1 .f - kr),
@@ -548,7 +561,7 @@ glm::vec3 SoftRasterizer::Scene::whittedRayTracing(Ray &ray, int depth) {
548561
549562 Ray reflectedRay (reflectCoord, reflectPath);
550563
551- reflectedColor = whittedRayTracing (reflectedRay, depth + 1 );
564+ reflectedColor = whittedRayTracing (reflectedRay, depth + 1 , sample );
552565
553566 final_color =
554567 glm::clamp (reflectedColor * kr, glm::vec3 (0 .0f ), glm::vec3 (1 .0f ));
@@ -609,6 +622,38 @@ SoftRasterizer::Scene::sampleLight() {
609622 return {intersection, pdf};
610623}
611624
625+ [[nodiscard]] std::tuple<glm::dvec3, double >
626+ SoftRasterizer::Scene::sampleLightOnCenter (const glm::vec3& shadingPoint) {
627+ // Collect all emissive objects and approximate their bounding spheres**
628+ std::vector<std::pair<glm::dvec3, double >> lightSpheres;
629+ for (const auto & obj : m_exportedObjs) {
630+ if (obj->isSelfEmissiveObject ()) {
631+ Bounds3 bbox = obj->getBounds ();
632+ glm::dvec3 center = (glm::dvec3 (bbox.min ) + glm::dvec3 (bbox.max )) * 0.5 ;
633+ double radius = glm::length (glm::dvec3 (bbox.diagonal ())) * 0.5 ;
634+ lightSpheres.emplace_back (center, radius);
635+ }
636+ }
637+
638+ if (lightSpheres.empty ()) {
639+ spdlog::warn (" No emissive objects found in the scene!" );
640+ return { glm::dvec3 (0.0 ), 0.0 };
641+ }
642+
643+ // Randomly select a light source
644+ int randomIndex =
645+ static_cast <int >(Tools::random_generator () * lightSpheres.size ());
646+ glm::dvec3 sphereCenter = lightSpheres[randomIndex].first ;
647+ double sphereRadius = lightSpheres[randomIndex].second ;
648+
649+ // Compute direction from shading point to light source
650+ glm::dvec3 lightDir = glm::normalize (sphereCenter - glm::dvec3 (shadingPoint));
651+
652+ // Compute probability density function (PDF)
653+ double pdf = 0.5 * Tools::PI_INV ;
654+ return { lightDir, pdf };
655+ }
656+
612657std::tuple<glm::dvec3, double >
613658SoftRasterizer::Scene::sampleLight (const glm::vec3 &shadingPoint) {
614659 // Collect all emissive objects and approximate their bounding spheres**
0 commit comments