Make World own its own memory, along with distant disk lights.

This commit is contained in:
Nathan Vegdahl 2022-08-07 13:54:18 -07:00
parent fc7b8da17d
commit c603e24633
5 changed files with 28 additions and 38 deletions

View File

@ -1,7 +1,5 @@
use std::f64::consts::PI as PI_64; use std::f64::consts::PI as PI_64;
use kioku::Arena;
use crate::{ use crate::{
color::{Color, SpectralSample}, color::{Color, SpectralSample},
lerp::lerp_slice, lerp::lerp_slice,
@ -13,24 +11,19 @@ use super::WorldLightSource;
// TODO: handle case where radius = 0.0. // TODO: handle case where radius = 0.0.
#[derive(Copy, Clone, Debug)] #[derive(Debug, Clone)]
pub struct DistantDiskLight<'a> { pub struct DistantDiskLight {
radii: &'a [f32], radii: Vec<f32>,
directions: &'a [Vector], directions: Vec<Vector>,
colors: &'a [Color], colors: Vec<Color>,
} }
impl<'a> DistantDiskLight<'a> { impl DistantDiskLight {
pub fn new( pub fn new(radii: &[f32], directions: &[Vector], colors: &[Color]) -> DistantDiskLight {
arena: &'a Arena,
radii: &[f32],
directions: &[Vector],
colors: &[Color],
) -> DistantDiskLight<'a> {
DistantDiskLight { DistantDiskLight {
radii: arena.copy_slice(&radii), radii: radii.into(),
directions: arena.copy_slice(&directions), directions: directions.into(),
colors: arena.copy_slice(&colors), colors: colors.into(),
} }
} }
@ -55,7 +48,7 @@ impl<'a> DistantDiskLight<'a> {
// } // }
} }
impl<'a> WorldLightSource for DistantDiskLight<'a> { impl WorldLightSource for DistantDiskLight {
fn sample_from_point( fn sample_from_point(
&self, &self,
u: f32, u: f32,
@ -64,9 +57,9 @@ impl<'a> WorldLightSource for DistantDiskLight<'a> {
time: f32, time: f32,
) -> (SpectralSample, Vector, f32) { ) -> (SpectralSample, Vector, f32) {
// Calculate time interpolated values // Calculate time interpolated values
let radius: f64 = lerp_slice(self.radii, time) as f64; let radius: f64 = lerp_slice(&self.radii, time) as f64;
let direction = lerp_slice(self.directions, time); let direction = lerp_slice(&self.directions, time);
let col = lerp_slice(self.colors, time); let col = lerp_slice(&self.colors, time);
let solid_angle_inv = 1.0 / (2.0 * PI_64 * (1.0 - radius.cos())); let solid_angle_inv = 1.0 / (2.0 * PI_64 * (1.0 - radius.cos()));
// Create a coordinate system from the vector pointing at the center of // Create a coordinate system from the vector pointing at the center of

View File

@ -9,8 +9,7 @@ use kioku::Arena;
use color::rec709_e_to_xyz; use color::rec709_e_to_xyz;
use crate::{ use crate::{
camera::Camera, color::Color, light::WorldLightSource, math::Xform, renderer::Renderer, camera::Camera, color::Color, math::Xform, renderer::Renderer, scene::Scene, scene::World,
scene::Scene, scene::World,
}; };
use super::{ use super::{
@ -153,7 +152,7 @@ pub fn parse_scene<'a>(
let camera = parse_camera(tree.iter_children_with_type("Camera").nth(0).unwrap())?; let camera = parse_camera(tree.iter_children_with_type("Camera").nth(0).unwrap())?;
// Parse world // Parse world
let world = parse_world(arena, tree.iter_children_with_type("World").nth(0).unwrap())?; let world = parse_world(tree.iter_children_with_type("World").nth(0).unwrap())?;
// Parse root scene assembly // Parse root scene assembly
let assembly = parse_assembly( let assembly = parse_assembly(
@ -440,10 +439,10 @@ fn parse_camera<'a>(tree: &'a DataTree) -> Result<Camera, PsyParseError> {
} }
} }
fn parse_world<'a>(arena: &'a Arena, tree: &'a DataTree) -> Result<World<'a>, PsyParseError> { fn parse_world(tree: &DataTree) -> Result<World, PsyParseError> {
if tree.is_internal() { if tree.is_internal() {
let background_color; let background_color;
let mut lights: Vec<&dyn WorldLightSource> = Vec::new(); let mut lights: Vec<_> = Vec::new();
// Parse background shader // Parse background shader
let bgs = { let bgs = {
@ -519,7 +518,7 @@ fn parse_world<'a>(arena: &'a Arena, tree: &'a DataTree) -> Result<World<'a>, Ps
for child in tree.iter_children() { for child in tree.iter_children() {
match *child { match *child {
DataTree::Internal { type_name, .. } if type_name == "DistantDiskLight" => { DataTree::Internal { type_name, .. } if type_name == "DistantDiskLight" => {
lights.push(arena.alloc(parse_distant_disk_light(arena, child)?)); lights.push(parse_distant_disk_light(child)?);
} }
_ => {} _ => {}
@ -529,7 +528,7 @@ fn parse_world<'a>(arena: &'a Arena, tree: &'a DataTree) -> Result<World<'a>, Ps
// Build and return the world // Build and return the world
return Ok(World { return Ok(World {
background_color: background_color, background_color: background_color,
lights: arena.copy_slice(&lights), lights: lights,
}); });
} else { } else {
return Err(PsyParseError::ExpectedInternalNode( return Err(PsyParseError::ExpectedInternalNode(

View File

@ -17,10 +17,7 @@ use super::{
DataTree, DataTree,
}; };
pub fn parse_distant_disk_light<'a>( pub fn parse_distant_disk_light<'a>(tree: &'a DataTree) -> Result<DistantDiskLight, PsyParseError> {
arena: &'a Arena,
tree: &'a DataTree,
) -> Result<DistantDiskLight<'a>, PsyParseError> {
if let DataTree::Internal { ref children, .. } = *tree { if let DataTree::Internal { ref children, .. } = *tree {
let mut radii = Vec::new(); let mut radii = Vec::new();
let mut directions = Vec::new(); let mut directions = Vec::new();
@ -77,7 +74,7 @@ pub fn parse_distant_disk_light<'a>(
} }
} }
return Ok(DistantDiskLight::new(arena, &radii, &directions, &colors)); return Ok(DistantDiskLight::new(&radii, &directions, &colors));
} else { } else {
return Err(PsyParseError::UnknownError(tree.byte_offset())); return Err(PsyParseError::UnknownError(tree.byte_offset()));
} }

View File

@ -6,6 +6,7 @@ use crate::{
algorithm::weighted_choice, algorithm::weighted_choice,
camera::Camera, camera::Camera,
color::SpectralSample, color::SpectralSample,
light::WorldLightSource,
math::{Normal, Point, Vector, XformFull}, math::{Normal, Point, Vector, XformFull},
surface::SurfaceIntersection, surface::SurfaceIntersection,
}; };
@ -19,7 +20,7 @@ pub use self::{
pub struct Scene<'a> { pub struct Scene<'a> {
pub name: Option<String>, pub name: Option<String>,
pub camera: Camera, pub camera: Camera,
pub world: World<'a>, pub world: World,
pub root: Assembly<'a>, pub root: Assembly<'a>,
} }
@ -67,7 +68,7 @@ impl<'a> Scene<'a> {
if n < wl_prob { if n < wl_prob {
// World lights // World lights
let n = n / wl_prob; let n = n / wl_prob;
let (i, p) = weighted_choice(self.world.lights, n, |l| l.approximate_energy()); let (i, p) = weighted_choice(&self.world.lights, n, |l| l.approximate_energy());
let (ss, sv, pdf) = let (ss, sv, pdf) =
self.world.lights[i].sample_from_point(uvw.0, uvw.1, wavelength, time); self.world.lights[i].sample_from_point(uvw.0, uvw.1, wavelength, time);
return SceneLightSample::Distant { return SceneLightSample::Distant {

View File

@ -1,7 +1,7 @@
use crate::{color::Color, light::WorldLightSource}; use crate::{color::Color, light::DistantDiskLight};
#[derive(Debug)] #[derive(Debug)]
pub struct World<'a> { pub struct World {
pub background_color: Color, pub background_color: Color,
pub lights: &'a [&'a dyn WorldLightSource], pub lights: Vec<DistantDiskLight>,
} }