RayTracing / raytracing.github.io

Main Web Site (Online Books)
https://raytracing.github.io/
Creative Commons Zero v1.0 Universal
8.72k stars 857 forks source link

Book 3.8.3: What are we supposed to do with the returned material::scatter() pdf value? #1543

Open hollasch opened 5 months ago

hollasch commented 5 months ago

We add the double pdf value reference to the material::scatter() functions, but don't show the corresponding update to camera::ray_color(), let alone how to use it.

9mm commented 3 months ago

lol glad to see this, i was quite confused. i still honestly dont know what to do. are you able to give a quick answer now?

This is what I attempted to do... im assuming i initialize an empty value, but im not sure about the initial value, whether it should be 0 or 1 / 2 * pi

fn ray_color<T: Hittable>(&self, r: Ray, depth: u32, world: &T) -> Color {
    if depth == 0 {
        return Color::new(0, 0, 0);
    }

    let mut rec = HitRecord::default();

    if !world.hit(r, Interval::new(0.001, f64::INFINITY), &mut rec) {
        return self.background;
    }

    let mut scattered = Ray::default();
    let mut attenuation = Color::default();
    let mut pdf = 0.0; //1.0 / (2.0 * std::f64::consts::PI);

    let color_from_emission = rec
        .mat
        .as_ref()
        .expect("material is present")
        .emitted(rec.u, rec.v, rec.p);

    // clone the material, and move the hit record
    if !rec.mat.as_ref().expect("material is present").scatter(
        r,
        &rec,
        &mut attenuation,
        &mut scattered,
        &mut pdf,
    ) {
        return color_from_emission;
    }

    let scattering_pdf = rec
        .mat
        .as_ref()
        .expect("material is present")
        .scattering_pdf(r, &rec, &scattered);

    let color_from_scatter =
        (attenuation * scattering_pdf * self.ray_color(scattered, depth - 1, world)) / pdf;

    color_from_emission + color_from_scatter
}
9mm commented 3 months ago

In case anyone comes across this... just proceed to the next section and it mostly answers it. Heres my finished function (after this section) which seems to be caught up.

    fn ray_color<T: Hittable>(&self, r: Ray, depth: u32, world: &T) -> Color {
        if depth == 0 {
            return Color::new(0, 0, 0);
        }

        let mut rec = HitRecord::default();

        if !world.hit(r, Interval::new(0.001, f64::INFINITY), &mut rec) {
            return self.background;
        }

        let mut scattered = Ray::default();
        let mut attenuation = Color::default();
        let mut pdf = 0.0;

        let color_from_emission = rec
            .mat
            .as_ref()
            .expect("material is present")
            .emitted(rec.u, rec.v, rec.p);

        if !rec.mat.as_ref().expect("material is present").scatter(
            r,
            &rec,
            &mut attenuation,
            &mut scattered,
            &mut pdf,
        ) {
            return color_from_emission;
        }

        let mut rng = rand::thread_rng();
        let on_light = Point3::new(rng.gen_range(213.0..343.0), 554.0, rng.gen_range(227.0..332.0));
        let mut to_light = on_light - rec.p;
        let distance_squared = to_light.length_squared();
        to_light = unit_vector(to_light);

        if dot(to_light, rec.normal) < 0.0 {
            return color_from_emission;
        }

        let light_area = (343.0 - 213.0) * (332.0 - 227.0);
        let light_cosine = f64::abs(to_light.y);
        if light_cosine < 0.000001 {
            return color_from_emission;
        }

        pdf = distance_squared / (light_cosine * light_area);
        scattered = Ray::new(rec.p, to_light, r.time);

        let scattering_pdf = rec
            .mat
            .as_ref()
            .expect("material is present")
            .scattering_pdf(r, &rec, &scattered);

        let color_from_scatter =
            (attenuation * scattering_pdf * self.ray_color(scattered, depth - 1, world)) / pdf;

        color_from_emission + color_from_scatter
    }
impl Material for Lambertian {
    fn scatter(
        &self,
        ray_in: Ray,
        rec: &HitRecord,
        attenuation: &mut Color,
        scattered: &mut Ray,
        pdf: &mut f64,
    ) -> bool {
        let uvw = Onb::new_from_w(rec.normal);
        let scatter_direction = uvw.local_from_vec(random_cosine_direction());

        *scattered = Ray::new(rec.p, unit_vector(scatter_direction), ray_in.time);
        *attenuation = self.tex.value(rec.u, rec.v, rec.p);
        *pdf = dot(uvw.w(), scattered.direction) / std::f64::consts::PI;

        true
    }

    fn scattering_pdf(&self, ray_in: Ray, rec: &HitRecord, scattered: &Ray) -> f64 {
        const SCATTERING_PDF: f64 = 1.0 / (2.0 * std::f64::consts::PI);
        SCATTERING_PDF
    }
}

impl Material for Isotropic {
    fn scatter(
        &self,
        ray_in: Ray,
        rec: &HitRecord,
        attenuation: &mut Color,
        scattered: &mut Ray,
        pdf: &mut f64,
    ) -> bool {
        *scattered = Ray::new(rec.p, random_unit_vector(), ray_in.time);
        *attenuation = self.tex.value(rec.u, rec.v, rec.p);
        *pdf = 1.0 / (4.0 * std::f64::consts::PI);

        true
    }

    fn scattering_pdf(&self, _ray_in: Ray, _rec: &HitRecord, _scattered: &Ray) -> f64 {
        1.0 / (4.0 * std::f64::consts::PI)
    }
}