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 kioku::Arena;
use crate::{
color::{Color, SpectralSample},
lerp::lerp_slice,
@ -13,24 +11,19 @@ use super::WorldLightSource;
// TODO: handle case where radius = 0.0.
#[derive(Copy, Clone, Debug)]
pub struct DistantDiskLight<'a> {
radii: &'a [f32],
directions: &'a [Vector],
colors: &'a [Color],
#[derive(Debug, Clone)]
pub struct DistantDiskLight {
radii: Vec<f32>,
directions: Vec<Vector>,
colors: Vec<Color>,
}
impl<'a> DistantDiskLight<'a> {
pub fn new(
arena: &'a Arena,
radii: &[f32],
directions: &[Vector],
colors: &[Color],
) -> DistantDiskLight<'a> {
impl DistantDiskLight {
pub fn new(radii: &[f32], directions: &[Vector], colors: &[Color]) -> DistantDiskLight {
DistantDiskLight {
radii: arena.copy_slice(&radii),
directions: arena.copy_slice(&directions),
colors: arena.copy_slice(&colors),
radii: radii.into(),
directions: directions.into(),
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(
&self,
u: f32,
@ -64,9 +57,9 @@ impl<'a> WorldLightSource for DistantDiskLight<'a> {
time: f32,
) -> (SpectralSample, Vector, f32) {
// Calculate time interpolated values
let radius: f64 = lerp_slice(self.radii, time) as f64;
let direction = lerp_slice(self.directions, time);
let col = lerp_slice(self.colors, time);
let radius: f64 = lerp_slice(&self.radii, time) as f64;
let direction = lerp_slice(&self.directions, time);
let col = lerp_slice(&self.colors, time);
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

View File

@ -9,8 +9,7 @@ use kioku::Arena;
use color::rec709_e_to_xyz;
use crate::{
camera::Camera, color::Color, light::WorldLightSource, math::Xform, renderer::Renderer,
scene::Scene, scene::World,
camera::Camera, color::Color, math::Xform, renderer::Renderer, scene::Scene, scene::World,
};
use super::{
@ -153,7 +152,7 @@ pub fn parse_scene<'a>(
let camera = parse_camera(tree.iter_children_with_type("Camera").nth(0).unwrap())?;
// 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
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() {
let background_color;
let mut lights: Vec<&dyn WorldLightSource> = Vec::new();
let mut lights: Vec<_> = Vec::new();
// Parse background shader
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() {
match *child {
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
return Ok(World {
background_color: background_color,
lights: arena.copy_slice(&lights),
lights: lights,
});
} else {
return Err(PsyParseError::ExpectedInternalNode(

View File

@ -17,10 +17,7 @@ use super::{
DataTree,
};
pub fn parse_distant_disk_light<'a>(
arena: &'a Arena,
tree: &'a DataTree,
) -> Result<DistantDiskLight<'a>, PsyParseError> {
pub fn parse_distant_disk_light<'a>(tree: &'a DataTree) -> Result<DistantDiskLight, PsyParseError> {
if let DataTree::Internal { ref children, .. } = *tree {
let mut radii = 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 {
return Err(PsyParseError::UnknownError(tree.byte_offset()));
}

View File

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

View File

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