Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
hollasch opened this issue Apr 20, 2024 · 2 comments
Milestone

Comments

@hollasch
Copy link
Collaborator

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.

@hollasch hollasch added this to the v4.0.0 milestone Apr 20, 2024
@9mm
Copy link

9mm commented Jun 21, 2024

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
Copy link

9mm commented Jun 21, 2024

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)
    }
}

@hollasch hollasch modified the milestones: v4.0.0, Backlog, v4.1.0 Jul 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants