1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// std
use std::sync::Arc;
// pbrt
use crate::core::camera::Camera;
use crate::core::geometry::{nrm_cross_vec3, nrm_faceforward_vec3, vec3_dot_nrm};
use crate::core::geometry::{Bounds2i, Normal3f, Point2f, Ray, Vector3f};
use crate::core::interaction::{Interaction, SurfaceInteraction};
use crate::core::material::TransportMode;
use crate::core::pbrt::{Float, Spectrum};
use crate::core::sampler::Sampler;
use crate::core::sampling::{
    cosine_hemisphere_pdf, cosine_sample_hemisphere, uniform_hemisphere_pdf,
    uniform_sample_hemisphere,
};
use crate::core::scene::Scene;

// see ao.h

/// Ambient Occlusion
pub struct AOIntegrator {
    // inherited from SamplerIntegrator (see integrator.h)
    pub camera: Arc<Camera>,
    pub sampler: Box<Sampler>,
    pub pixel_bounds: Bounds2i,
    // see ao.h
    pub cos_sample: bool,
    pub n_samples: i32,
}

impl AOIntegrator {
    pub fn new(
        cos_sample: bool,
        n_samples: i32,
        camera: Arc<Camera>,
        sampler: Box<Sampler>,
        pixel_bounds: Bounds2i,
    ) -> Self {
        AOIntegrator {
            camera,
            sampler,
            pixel_bounds,
            cos_sample,
            n_samples,
        }
    }
    pub fn preprocess(&mut self, _scene: &Scene) {
        self.sampler.request_2d_array(self.n_samples);
    }
    pub fn li(
        &self,
        r: &mut Ray,
        scene: &Scene,
        sampler: &mut Sampler,
        // arena: &mut Arena,
        _depth: i32,
    ) -> Spectrum {
        // TODO: ProfilePhase p(Prof::SamplerIntegratorLi);
        let mut l: Spectrum = Spectrum::default();
        let mut ray: Ray = Ray {
            o: r.o,
            d: r.d,
            t_max: r.t_max,
            time: r.time,
            differential: r.differential,
            medium: r.medium.clone(),
        };
        let mut isect: SurfaceInteraction = SurfaceInteraction::default();
        if scene.intersect(&mut ray, &mut isect) {
            let mode: TransportMode = TransportMode::Radiance;
            isect.compute_scattering_functions(&ray, true, mode);
            // if (!isect.bsdf) {
            //     VLOG(2) << "Skipping intersection due to null bsdf";
            //     ray = isect.SpawnRay(ray.d);
            //     goto retry;
            // }
            // compute coordinate frame based on true geometry, not
            // shading geometry.
            let n: Normal3f = nrm_faceforward_vec3(&isect.n, &-ray.d);
            let s: Vector3f = isect.dpdu.normalize();
            let t: Vector3f = nrm_cross_vec3(&isect.n, &s);
            let u_opt: Option<&[Point2f]> = sampler.get_2d_array(self.n_samples);
            if let Some(u) = u_opt {
                for item in u.iter().take(self.n_samples as usize) {
                    // Vector3f wi;
                    let mut wi: Vector3f;
                    let pdf = if self.cos_sample {
                        wi = cosine_sample_hemisphere(*item);
                        cosine_hemisphere_pdf(wi.z.abs())
                    } else {
                        wi = uniform_sample_hemisphere(*item);
                        uniform_hemisphere_pdf()
                    };
                    // transform wi from local frame to world space.
                    wi = Vector3f {
                        x: s.x * wi.x + t.x * wi.y + n.x * wi.z,
                        y: s.y * wi.x + t.y * wi.y + n.y * wi.z,
                        z: s.z * wi.x + t.z * wi.y + n.z * wi.z,
                    };
                    let mut ray: Ray = isect.spawn_ray(&wi);
                    if !scene.intersect_p(&mut ray) {
                        l += Spectrum::new(vec3_dot_nrm(&wi, &n) / (pdf * self.n_samples as Float));
                    }
                }
            }
        }
        l
    }
    pub fn get_camera(&self) -> Arc<Camera> {
        self.camera.clone()
    }
    pub fn get_sampler(&self) -> &Sampler {
        &self.sampler
    }
    pub fn get_pixel_bounds(&self) -> Bounds2i {
        self.pixel_bounds
    }
}