Skip to content

Commit

Permalink
feature: implement SimplePath integrator (sample lights)
Browse files Browse the repository at this point in the history
  • Loading branch information
w3ntao committed Dec 26, 2023
1 parent b517118 commit 4bb9487
Show file tree
Hide file tree
Showing 23 changed files with 613 additions and 80 deletions.
22 changes: 22 additions & 0 deletions src/base/integrator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,28 @@ pub struct IntegratorBase {
pub infinite_lights: Vec<Arc<dyn Light>>,
}

impl IntegratorBase {
pub fn new(
aggregate: Arc<dyn Primitive>,
camera: Arc<dyn Camera>,
lights: Vec<Arc<dyn Light>>,
) -> Self {
let mut infinite_lights = vec![];
for _light in &lights {
if _light.light_type() == LightType::Infinite {
infinite_lights.push(_light.clone());
}
}

return Self {
camera,
aggregate,
lights,
infinite_lights,
};
}
}

pub trait Integrator: Send + Sync {
fn fast_intersect(&self, ray: &Ray, t_max: f64) -> bool;

Expand Down
12 changes: 6 additions & 6 deletions src/base/interaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,11 @@ impl SurfaceInteraction {
// Compute auxiliary intersection points with plane, _px_ and _py_
let p = Point3f::from(self.interaction.pi);

let d = -n.dot(Vector3f::from(p));
let tx = (-n.dot(Vector3::from(ray.rx_origin)) - d) / n.dot(ray.rx_direction);
let d = -n.dot(p.into());
let tx = (-n.dot(ray.rx_origin.into()) - d) / n.dot(ray.rx_direction);
let px = ray.rx_origin + tx * ray.rx_direction;

let ty = (-n.dot(Vector3f::from(ray.ry_origin)) - d) / n.dot(ray.ry_direction);
let ty = (-n.dot(ray.ry_origin.into()) - d) / n.dot(ray.ry_direction);

let py = ray.ry_origin + ty * ray.ry_direction;

Expand All @@ -140,7 +140,7 @@ impl SurfaceInteraction {
} else {
// Approximate screen-space change in $\pt{}$ based on camera projection
(self.dpdx, self.dpdy) = camera.approximate_dp_dxy(
Point3f::from(self.interaction.pi),
self.interaction.pi.into(),
self.interaction.n,
samples_per_pixel,
);
Expand Down Expand Up @@ -176,7 +176,7 @@ impl SurfaceInteraction {
// Clamp derivatives of $u$ and $v$ to reasonable values
let local_clamp = |x: f64| {
if x.is_finite() {
clamp_float(x, -1e8, 1e8)
x.clamp(-1e8, 1e8)
} else {
0.0
}
Expand Down Expand Up @@ -223,7 +223,7 @@ impl SurfaceInteraction {
return match &self.area_light {
None => SampledSpectrum::same_value(0.0),
Some(are_light) => are_light.l(
Point3f::from(self.interaction.pi),
self.interaction.pi.into(),
self.interaction.n,
self.interaction.uv,
w,
Expand Down
28 changes: 28 additions & 0 deletions src/base/shape.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::pbrt::*;

pub const MIN_SPHERICAL_SAMPLE_AREA: f64 = 3e-4;
pub const MAX_SPHERICAL_SAMPLE_AREA: f64 = 6.22;

pub struct Shading {
pub n: Normal3f,
pub dpdu: Vector3f,
Expand All @@ -20,6 +23,27 @@ impl Shading {
}
}

pub struct ShapeSampleContext {
pub pi: Point3fi,
pub n: Normal3f,
pub ns: Normal3f,
}

pub struct ShapeSample {
pub interaction: Interaction,
pub pdf: f64,
}

impl ShapeSampleContext {
pub fn offset_ray_origin(&self, w: Vector3f) -> Point3f {
panic!("ShapeSampleContext::offset_ray_origin() not implemented");
}

pub fn spawn_ray(&self, w: Vector3f) -> Ray {
panic!("ShapeSampleContext::spawn_ray() not implemented");
}
}

pub struct ShapeIntersection {
pub t_hit: f64,
pub surface_interaction: SurfaceInteraction,
Expand All @@ -39,4 +63,8 @@ pub trait Shape: Send + Sync {
fn bounds(&self) -> Bounds3f;

fn area(&self) -> f64;

fn sample(&self, u: Point2f) -> Option<ShapeSample>;

fn sample_with_context(&self, ctx: &ShapeSampleContext, u: Point2f) -> Option<ShapeSample>;
}
2 changes: 1 addition & 1 deletion src/base/texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl Display for TextureEvalContext {
impl TextureEvalContext {
pub fn new(si: &SurfaceInteraction) -> Self {
return Self {
p: Point3f::from(si.interaction.pi),
p: si.interaction.pi.into(),
dpdx: si.dpdx,
dpdy: si.dpdy,
n: si.interaction.n,
Expand Down
2 changes: 1 addition & 1 deletion src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ fn main() {

let absolute_path = fs::canonicalize(args.scene_file).unwrap();

let spp = args.spp.unwrap_or_else(|| 16);
let spp = args.spp.unwrap_or_else(|| 32);

render(&absolute_path.display().to_string(), spp);
}
53 changes: 52 additions & 1 deletion src/euclidean_space/normal.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::pbrt::*;

#[derive(Copy, Clone)]
#[derive(Copy, Clone, PartialEq)]
pub struct Normal3f {
pub x: f64,
pub y: f64,
Expand All @@ -20,6 +20,13 @@ impl Normal3f {
};
}

pub fn is_valid(&self) -> bool {
return self.x.is_finite()
&& self.y.is_finite()
&& self.z.is_finite()
&& (self.x * self.y * self.z != 0.0);
}

pub fn normalize(&self) -> Normal3f {
let length = (sqr(self.x) + sqr(self.y) + sqr(self.z)).sqrt();
return Normal3f {
Expand Down Expand Up @@ -75,3 +82,47 @@ impl Neg for Normal3f {
};
}
}

impl Add<Normal3f> for Normal3f {
type Output = Normal3f;

fn add(self, rhs: Normal3f) -> Self::Output {
return Normal3f {
x: self.x + rhs.x,
y: self.y + rhs.y,
z: self.z + rhs.z,
};
}
}

impl Mul<f64> for Normal3f {
type Output = Normal3f;

fn mul(self, rhs: f64) -> Self::Output {
return Self {
x: self.x * rhs,
y: self.y * rhs,
z: self.z * rhs,
};
}
}

impl Mul<Normal3f> for f64 {
type Output = Normal3f;

fn mul(self, rhs: Normal3f) -> Self::Output {
return Normal3f {
x: self * rhs.x,
y: self * rhs.y,
z: self * rhs.z,
};
}
}

impl MulAssign<f64> for Normal3f {
fn mul_assign(&mut self, rhs: f64) {
self.x *= rhs;
self.y *= rhs;
self.z *= rhs;
}
}
2 changes: 1 addition & 1 deletion src/euclidean_space/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ impl Transform {
let dt = d.abs().dot(o.error()) / length_squared;
let offset_o = o + Vector3fi::from(d * dt);

return (Ray::new(Point3f::from(offset_o), d), dt);
return (Ray::new(offset_o.into(), d), dt);
}

pub fn on_differential_ray(&self, r: &DifferentialRay) -> (DifferentialRay, f64) {
Expand Down
10 changes: 10 additions & 0 deletions src/euclidean_space/vector3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,16 @@ impl Vector3f {
z,
};
}

// Equivalent to std::acos(Dot(a, b)), but more numerically stable.
// via http://www.plunk.org/~hatch/rightway.html
pub fn angle_between(&self, v: Vector3f) -> f64 {
if self.dot(v) < 0.0 {
return PI - 2.0 * safe_asin((*self + v).length() / 2.0);
}

return 2.0 * safe_asin((v - *self).length() / 2.0);
}
}

impl Vector3<Interval> {
Expand Down
7 changes: 1 addition & 6 deletions src/integrators/ambient_occlusion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,7 @@ impl AmbientOcclusion {
let illuminant_scale = 1.0 / illuminant_spectrum.to_photometric();

return Self {
base: IntegratorBase {
aggregate,
camera,
lights: vec![],
infinite_lights: vec![],
},
base: IntegratorBase::new(aggregate, camera, vec![]),
illuminant_spectrum,
illuminant_scale,
};
Expand Down
7 changes: 1 addition & 6 deletions src/integrators/random_walk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,7 @@ impl RandomWalkIntegrator {
}

return Self {
base: IntegratorBase {
aggregate,
camera,
lights,
infinite_lights,
},
base: IntegratorBase::new(aggregate, camera, lights),
illuminant_spectrum,
illuminant_scale,
};
Expand Down
17 changes: 10 additions & 7 deletions src/integrators/simple_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,16 +117,19 @@ impl Integrator for SimplePath {
}

impl SimplePath {
pub fn new(base: IntegratorBase) -> Self {
unreachable!();
pub fn new(
aggregate: Arc<dyn Primitive>,
camera: Arc<dyn Camera>,
lights: Vec<Arc<dyn Light>>,
) -> Self {
let light_sampler = UniformLightSampler {
lights: lights.clone(),
};

/*
return Self {
base,
sample_bsdf: true,
sample_light: true,
base: IntegratorBase::new(aggregate, camera, lights),
max_depth: 5,
light_sampler,
};
*/
}
}
8 changes: 1 addition & 7 deletions src/integrators/surface_normal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,8 @@ impl SurfaceNormal {
camera: Arc<dyn Camera>,
color_space: &RGBColorSpace,
) -> Self {
let val = 0.01;
return SurfaceNormal {
base: IntegratorBase {
aggregate,
camera,
lights: vec![],
infinite_lights: vec![],
},
base: IntegratorBase::new(aggregate, camera, vec![]),
rgb: color_space.generate_albedo_rgb(),
};
}
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![feature(const_fmt_arguments_new)]
#![feature(const_fn_floating_point_arithmetic)]
#![feature(const_float_bits_conv)]
#![feature(const_float_classify)]
#![feature(const_trait_impl)]
#![feature(generic_const_exprs)]
Expand Down
2 changes: 1 addition & 1 deletion src/light_samplers/uniform_light_sampler.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::pbrt::*;

pub struct UniformLightSampler {
lights: Vec<Arc<dyn Light>>,
pub lights: Vec<Arc<dyn Light>>,
}

impl LightSampler for UniformLightSampler {
Expand Down
44 changes: 42 additions & 2 deletions src/lights/diffuse_area.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::pbrt::*;
use crate::FilterFunction::Point;

pub struct DiffuseAreaLight {
base: LightBase,
Expand Down Expand Up @@ -42,8 +43,47 @@ impl Light for DiffuseAreaLight {
lambda: &SampledWavelengths,
allow_incomplete_pdf: bool,
) -> Option<LightLiSample> {
//TODO: progress 2023/12/20 implement DiffuseAreaLight
panic!("DiffuseAreaLight::sample_li() not implemented");
// Sample point on shape for _DiffuseAreaLight_
let shape_ctx = ShapeSampleContext {
pi: ctx.pi,
n: ctx.n,
ns: ctx.ns,
};

let ss = match self.shape.sample_with_context(&shape_ctx, u) {
None => {
return None;
}
Some(_ss) => _ss,
};

if ss.pdf == 0.0
|| (Point3f::from(ss.interaction.pi) - Point3f::from(ctx.pi)).length_squared() == 0.0
{
return None;
}

// Return _LightLiSample_ for sampled point on shape
let wi = (Point3f::from(ss.interaction.pi) - Point3f::from(ctx.pi)).normalize();

let Le = self.l(
ss.interaction.pi.into(),
ss.interaction.n,
ss.interaction.uv,
-wi,
lambda,
);

if !Le.is_positive() {
return None;
}

return Some(LightLiSample {
l: Le,
wi,
pdf: ss.pdf,
p_light: ss.interaction,
});
}
}

Expand Down
Loading

0 comments on commit 4bb9487

Please sign in to comment.