wahn / rs_pbrt

Rust crate to implement a counterpart to the PBRT book's (3rd edition) C++ code. See also https://www.rs-pbrt.org/about ...
https://www.rs-pbrt.org
Other
811 stars 59 forks source link

OrthographicCamera::generate_ray_differential was incorrect #113

Closed flarelee closed 5 years ago

flarelee commented 5 years ago

OrthographicCamera::generate_ray_differential was incorrect.

my fixed code

fn generate_ray_differential(&self, sample: &CameraSample, ray: &mut Ray) -> Float {
    // TODO: ProfilePhase prof(Prof::GenerateCameraRay);
    // compute raster and camera sample positions
    let p_film: Point3f = Point3f {
        x: sample.p_film.x,
        y: sample.p_film.y,
        z: 0.0,
    };
    let p_camera: Point3f = self.raster_to_camera.transform_point(&p_film);
    *ray = Ray {
        o: p_camera,
        d: Vector3f {
            x: 0.0,
            y: 0.0,
            z: 1.0,
        },
        t_max: std::f32::INFINITY,
        time: lerp(sample.time, self.shutter_open, self.shutter_close),
        medium: None,
        differential: None,
    };
    // modify ray for depth of field
    if self.lens_radius > 0.0 as Float {
        // sample point on lens
        let p_lens: Point2f = concentric_sample_disk(&sample.p_lens) * self.lens_radius;
        // compute point on plane of focus
        let ft: Float = self.focal_distance / ray.d.z;
        let p_focus: Point3f = ray.position(ft);
        // update ray for effect of lens
        ray.o = Point3f {
            x: p_lens.x,
            y: p_lens.y,
            z: 0.0 as Float,
        };
        ray.d = (p_focus - ray.o).normalize();
    }
    // compute offset rays for _OrthographicCamera_ ray differentials
    if self.lens_radius > 0.0 as Float {
        // compute _OrthographicCamera_ ray differentials accounting for lens

        // sample point on lens
        let p_lens: Point2f = concentric_sample_disk(&sample.p_lens) * self.lens_radius;
        let ft: Float = self.focal_distance / ray.d.z;
        let p_focus: Point3f = p_camera
            + self.dx_camera
            + (Vector3f {
                x: 0.0 as Float,
                y: 0.0 as Float,
                z: 1.0 as Float,
            } * ft);
        let rx_origin = Point3f {
            x: p_lens.x,
            y: p_lens.y,
            z: 0.0 as Float,
        };
        let ry_origin = Point3f {
            x: p_lens.x,
            y: p_lens.y,
            z: 0.0 as Float,
        };
        let diff = RayDifferential {
            rx_origin: rx_origin,
            rx_direction: (p_focus - rx_origin).normalize(),
            ry_origin: ry_origin,
            ry_direction: (p_focus - ry_origin).normalize(),
        };
        // replace differential
        ray.differential = Some(diff);
    } else {
        let diff: RayDifferential = RayDifferential {
            rx_origin: ray.o + self.dx_camera,
            ry_origin: ray.o + self.dy_camera,
            rx_direction: ray.d,
            ry_direction: ray.d,
        };
        ray.differential = Some(diff);
    }
    // ray->medium = medium;
    if let Some(ref medium_arc) = self.medium {
        ray.medium = Some(medium_arc.clone());
    } else {
        ray.medium = None;
    }
    *ray = self.camera_to_world.transform_ray(ray);
    1.0
}
wahn commented 5 years ago

Can you explain a bit, what was actually wrong in the current implementation?