Continuing cleanup of builder and parser. Removing light factory, creating issues with function signatures and unnecessary resources for light creation
This commit is contained in:
parent
0c04eeb0f9
commit
c659ea0f44
11 changed files with 321 additions and 287 deletions
|
|
@ -2,8 +2,8 @@ use crate::cameras::realistic::RealisticCameraHost;
|
|||
use crate::core::image::ImageMetadata;
|
||||
use crate::core::image::{Image, ImageIO};
|
||||
use crate::globals::get_options;
|
||||
use crate::utils::read_float_file;
|
||||
use crate::utils::{Arena, FileLoc, ParameterDictionary};
|
||||
use crate::utils::{Upload, read_float_file};
|
||||
use anyhow::{Result, anyhow};
|
||||
use shared::Ptr;
|
||||
use shared::cameras::*;
|
||||
|
|
|
|||
|
|
@ -49,15 +49,20 @@ impl IndexMut<usize> for TransformSet {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct PendingAreaLight {
|
||||
name: String,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
struct GraphicsState {
|
||||
pub current_inside_medium: String,
|
||||
pub current_outside_medium: String,
|
||||
pub current_material_name: String,
|
||||
pub current_material_index: Option<usize>,
|
||||
pub area_light_name: String,
|
||||
pub area_light_params: ParsedParameterVector,
|
||||
pub area_light_loc: FileLoc,
|
||||
pub pending_area_light: Option<PendingAreaLight>,
|
||||
pub shape_attributes: ParsedParameterVector,
|
||||
pub light_attributes: ParsedParameterVector,
|
||||
pub material_attributes: ParsedParameterVector,
|
||||
|
|
@ -191,7 +196,7 @@ impl BasicSceneBuilder {
|
|||
|
||||
fn make_params(
|
||||
&self,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: &FileLoc,
|
||||
) -> Result<ParameterDictionary, ParserError> {
|
||||
ParameterDictionary::new(params.clone(), self.graphics_state.color_space.clone())
|
||||
|
|
@ -333,7 +338,7 @@ impl ParserTarget for BasicSceneBuilder {
|
|||
fn camera(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
self.verify_options("Camera", &loc)?;
|
||||
|
|
@ -357,7 +362,7 @@ impl ParserTarget for BasicSceneBuilder {
|
|||
CameraTransform::from_world(animated_world_from_cam, rendering_space);
|
||||
self.render_from_world = camera_from_world.t[0];
|
||||
|
||||
let parameters = self.make_params(¶ms.clone(), &loc)?;
|
||||
let parameters = self.make_params(params, &loc)?;
|
||||
|
||||
self.current_camera = Some(CameraSceneEntity {
|
||||
base: SceneEntity {
|
||||
|
|
@ -405,7 +410,7 @@ impl ParserTarget for BasicSceneBuilder {
|
|||
fn pixel_filter(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
self.verify_options("PixelFilter", &loc)?;
|
||||
|
|
@ -421,12 +426,12 @@ impl ParserTarget for BasicSceneBuilder {
|
|||
fn film(
|
||||
&mut self,
|
||||
type_name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
self.verify_options("Film", &loc)?;
|
||||
let parameters = self.make_params(params, &loc)?;
|
||||
self.current_filter = Some(SceneEntity {
|
||||
self.current_film = Some(SceneEntity {
|
||||
name: type_name.to_string(),
|
||||
loc,
|
||||
parameters,
|
||||
|
|
@ -437,7 +442,7 @@ impl ParserTarget for BasicSceneBuilder {
|
|||
fn accelerator(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
self.verify_options("Accelerator", &loc)?;
|
||||
|
|
@ -453,7 +458,7 @@ impl ParserTarget for BasicSceneBuilder {
|
|||
fn integrator(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
self.verify_options("Integrator", &loc)?;
|
||||
|
|
@ -469,7 +474,7 @@ impl ParserTarget for BasicSceneBuilder {
|
|||
fn make_named_medium(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
self.verify_world("MakeNamedMaterial", &loc)?;
|
||||
|
|
@ -509,11 +514,11 @@ impl ParserTarget for BasicSceneBuilder {
|
|||
fn sampler(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
self.verify_options("Sampler", &loc)?;
|
||||
let parameters = self.make_params(¶ms.clone(), &loc)?;
|
||||
let parameters = self.make_params(params, &loc)?;
|
||||
self.current_sampler = Some(SceneEntity {
|
||||
name: name.to_string(),
|
||||
loc,
|
||||
|
|
@ -631,7 +636,7 @@ impl ParserTarget for BasicSceneBuilder {
|
|||
orig_name: &str,
|
||||
type_name: &str,
|
||||
tex_name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
arena: Arc<Arena>,
|
||||
) -> Result<(), ParserError> {
|
||||
|
|
@ -693,7 +698,7 @@ impl ParserTarget for BasicSceneBuilder {
|
|||
fn material(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
self.verify_world("material", &loc);
|
||||
|
|
@ -708,7 +713,7 @@ impl ParserTarget for BasicSceneBuilder {
|
|||
fn make_named_material(
|
||||
&mut self,
|
||||
_name: &str,
|
||||
_params: &ParsedParameterVector,
|
||||
_params: ParsedParameterVector,
|
||||
_loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
todo!()
|
||||
|
|
@ -720,28 +725,114 @@ impl ParserTarget for BasicSceneBuilder {
|
|||
|
||||
fn light_source(
|
||||
&mut self,
|
||||
_name: &str,
|
||||
_params: &ParsedParameterVector,
|
||||
_loc: FileLoc,
|
||||
name: &str,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
self.verify_world("LightSource", &loc)?;
|
||||
let dict = ParameterDictionary::from_array(
|
||||
params.clone(),
|
||||
&self.graphics_state.medium_attributes,
|
||||
self.graphics_state.color_space.clone()
|
||||
)?;
|
||||
|
||||
let render_from_light = AnimatedTransform::new(
|
||||
&self.graphics_state.ctm.t[0],
|
||||
self.graphics_state.transform_start_time,
|
||||
&self.graphics_state.ctm.t[1],
|
||||
self.graphics_state.transform_end_time,
|
||||
);
|
||||
|
||||
let entity = LightSceneEntity {
|
||||
transformed_base: TransformedSceneEntity {
|
||||
base: SceneEntity {
|
||||
name: name.to_string(),
|
||||
loc,
|
||||
parameters: dict,
|
||||
},
|
||||
render_from_object: render_from_light,
|
||||
},
|
||||
medium: self.graphics_state.current_outside_medium.clone(),
|
||||
};
|
||||
|
||||
self.scene.add_light(entity);
|
||||
Ok(())
|
||||
|
||||
}
|
||||
|
||||
fn area_light_source(
|
||||
&mut self,
|
||||
_name: &str,
|
||||
_params: &ParsedParameterVector,
|
||||
_loc: FileLoc,
|
||||
name: &str,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
self.verify_world("AreaLightSource", &loc)?;
|
||||
self.graphics_state.pending_area_light = Some(PendingAreaLight {
|
||||
name: name.to_string(),
|
||||
params: params.clone(),
|
||||
loc,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn shape(
|
||||
&mut self,
|
||||
_name: &str,
|
||||
_params: &ParsedParameterVector,
|
||||
_loc: FileLoc,
|
||||
name: &str,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
self.verify_world("Shape", &loc)?;
|
||||
|
||||
let dict = ParameterDictionary::from_array(
|
||||
params.clone(),
|
||||
&self.graphics_state.shape_attributes,
|
||||
self.graphics_state.color_space.clone()
|
||||
)?;
|
||||
|
||||
let render_from_object = self.graphics_state.ctm[0];
|
||||
let object_from_render = render_from_object.inverse();
|
||||
|
||||
let light_index = if let Some(ref al) = self.graphics_state.pending_area_light {
|
||||
let al_dict = self.make_params(al.params.clone(), &al.loc)?;
|
||||
let light_entity = SceneEntity {
|
||||
name: al.name.clone(),
|
||||
loc: al.loc.clone(),
|
||||
parameters: al_dict
|
||||
};
|
||||
Some(self.scene.add_area_light(light_entity))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let material = if !self.graphics_state.current_material_name.is_empty() {
|
||||
MaterialRef::Name(self.graphics_state.current_material_name.clone())
|
||||
} else if let Some(idx) = self.graphics_state.current_material_index {
|
||||
MaterialRef::Index(idx)
|
||||
} else {
|
||||
MaterialRef::None
|
||||
};
|
||||
|
||||
let entity = ShapeSceneEntity {
|
||||
base: SceneEntity {
|
||||
name: name.to_string(),
|
||||
loc,
|
||||
parameters: dict
|
||||
},
|
||||
render_from_object: Arc::new(render_from_object),
|
||||
object_from_render: Arc::new(object_from_render),
|
||||
reverse_orientation: self.graphics_state.reverse_orientation,
|
||||
material,
|
||||
light_index,
|
||||
inside_medium: self.graphics_state.current_inside_medium.clone(),
|
||||
outside_medium: self.graphics_state.current_outside_medium.clone(),
|
||||
};
|
||||
|
||||
if self.active_instance_definition.is_some() {
|
||||
self.active_instance_definition.as_mut().unwrap().shapes.push(entity)
|
||||
} else {
|
||||
self.scene.add_shape(entity);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn object_begin(&mut self, _name: &str, _loc: FileLoc) -> Result<(), ParserError> {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use crate::core::camera::CameraFactory;
|
|||
use crate::core::film::FilmFactory;
|
||||
use crate::core::filter::FilterFactory;
|
||||
use crate::core::image::{Image, io::ImageIO};
|
||||
use crate::core::light::LightFactory;
|
||||
use crate::core::material::MaterialFactory;
|
||||
use crate::core::primitive::{CreateGeometricPrimitive, CreateSimplePrimitive};
|
||||
use crate::core::sampler::SamplerFactory;
|
||||
|
|
@ -16,7 +17,7 @@ use crate::{Arena, FileLoc};
|
|||
use anyhow::{Result, anyhow};
|
||||
use parking_lot::Mutex;
|
||||
use rayon::prelude::*;
|
||||
use shared::core::camera::Camera;
|
||||
use shared::core::camera::{CameraTransform, Camera};
|
||||
use shared::core::color::LINEAR;
|
||||
use shared::core::film::Film;
|
||||
use shared::core::filter::Filter;
|
||||
|
|
@ -313,6 +314,14 @@ impl BasicScene {
|
|||
state.area_lights.len() - 1
|
||||
}
|
||||
|
||||
pub fn add_light(&self, light: LightSceneEntity) {
|
||||
self.light_state.lock().lights.push(light);
|
||||
}
|
||||
|
||||
pub fn add_shape(&self, shape: ShapeSceneEntity) {
|
||||
self.shapes.lock().push(shape);
|
||||
}
|
||||
|
||||
pub fn add_shapes(&self, new_shapes: Vec<ShapeSceneEntity>) {
|
||||
self.shapes.lock().extend(new_shapes);
|
||||
}
|
||||
|
|
@ -489,6 +498,32 @@ impl BasicScene {
|
|||
Ok((named_materials, materials))
|
||||
}
|
||||
|
||||
pub fn create_lights(
|
||||
&self,
|
||||
camera_transform: &CameraTransform,
|
||||
arena: &mut Arena,
|
||||
) -> Result<Vec<Light>> {
|
||||
let state = self.light_state.lock();
|
||||
|
||||
state.lights.par_iter().map(|entity| {
|
||||
let render_from_light = entity.transformed_base.render_from_object.start_transform;
|
||||
let medium = self.get_medium(
|
||||
&entity.medium,
|
||||
&entity.transformed_base.base.loc,
|
||||
);
|
||||
|
||||
Light::create(
|
||||
&entity.transformed_base.base.name,
|
||||
&entity.transformed_base.base.parameters,
|
||||
render_from_light,
|
||||
camera_transform,
|
||||
medium.map(|m| *m),
|
||||
&entity.transformed_base.base.loc,
|
||||
arena,
|
||||
)
|
||||
}).collect()
|
||||
}
|
||||
|
||||
pub fn create_aggregate(
|
||||
&self,
|
||||
textures: &NamedTextures,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use super::{SceneEntity, TextureSceneEntity};
|
||||
use super::{SceneEntity, TextureSceneEntity, LightSceneEntity};
|
||||
use crate::core::image::Image;
|
||||
use crate::core::texture::{FloatTexture, SpectrumTexture};
|
||||
use crate::utils::parallel::AsyncJob;
|
||||
|
|
@ -29,7 +29,7 @@ pub struct MaterialState {
|
|||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct LightState {
|
||||
pub light_jobs: Vec<AsyncJob<Light>>,
|
||||
pub lights: Vec<LightSceneEntity>,
|
||||
pub area_lights: Vec<SceneEntity>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use crate::utils::{Arena, FileLoc, ParameterDictionary, Upload, resolve_filename
|
|||
use anyhow::{Result, anyhow};
|
||||
use shared::core::geometry::Point2i;
|
||||
use shared::core::light::{Light, LightBase, LightType};
|
||||
use shared::core::medium::{Medium, MediumInterface};
|
||||
use shared::core::medium::Medium;
|
||||
use shared::core::shape::{Shape, ShapeTrait};
|
||||
use shared::core::spectrum::Spectrum;
|
||||
use shared::core::texture::GPUFloatTexture;
|
||||
|
|
@ -18,89 +18,6 @@ use shared::spectra::RGBColorSpace;
|
|||
use shared::utils::{Ptr, Transform};
|
||||
use shared::{Float, PI};
|
||||
|
||||
pub trait CreateDiffuseLight {
|
||||
fn new(
|
||||
render_from_light: Transform,
|
||||
medium_interface: MediumInterface,
|
||||
le: Spectrum,
|
||||
scale: Float,
|
||||
shape: Ptr<Shape>,
|
||||
alpha: Ptr<GPUFloatTexture>,
|
||||
image: Ptr<Image>,
|
||||
colorspace: Ptr<RGBColorSpace>,
|
||||
two_sided: bool,
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
impl CreateDiffuseLight for DiffuseAreaLight {
|
||||
fn new(
|
||||
render_from_light: Transform,
|
||||
medium_interface: MediumInterface,
|
||||
le: Spectrum,
|
||||
scale: Float,
|
||||
shape: Ptr<Shape>,
|
||||
alpha: Ptr<GPUFloatTexture>,
|
||||
image: Ptr<Image>,
|
||||
colorspace: Ptr<RGBColorSpace>,
|
||||
two_sided: bool,
|
||||
) -> Self {
|
||||
let is_constant_zero = match &*alpha {
|
||||
GPUFloatTexture::Constant(tex) => tex.evaluate(&TextureEvalContext::default()) == 0.0,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let (light_type, stored_alpha) = if is_constant_zero {
|
||||
(LightType::DeltaPosition, None)
|
||||
} else {
|
||||
(LightType::Area, Some(alpha))
|
||||
};
|
||||
|
||||
let base = LightBase::new(light_type, render_from_light, medium_interface);
|
||||
|
||||
let lemit = lookup_spectrum(&le);
|
||||
|
||||
if !image.is_null() {
|
||||
let desc = image
|
||||
.get_channel_desc(&["R", "G", "B"])
|
||||
.expect("Image used for DiffuseAreaLight doesn't have R, G, B channels");
|
||||
|
||||
assert_eq!(3, desc.size(), "Image channel description size mismatch");
|
||||
assert!(
|
||||
desc.is_identity(),
|
||||
"Image channel description is not identity"
|
||||
);
|
||||
|
||||
assert!(
|
||||
!colorspace.is_null(),
|
||||
"Image provided but ColorSpace is missing"
|
||||
);
|
||||
}
|
||||
|
||||
let is_triangle_or_bilinear =
|
||||
matches!(*shape, Shape::Triangle(_) | Shape::BilinearPatch(_));
|
||||
if render_from_light.has_scale(None) && !is_triangle_or_bilinear {
|
||||
println!(
|
||||
"Scaling detected in rendering to light space transformation! \
|
||||
The system has numerous assumptions, implicit and explicit, \
|
||||
that this transform will have no scale factors in it. \
|
||||
Proceed at your own risk; your image may have errors."
|
||||
);
|
||||
}
|
||||
|
||||
Self {
|
||||
base,
|
||||
area: shape.area(),
|
||||
image: Ptr::from(image.device()),
|
||||
colorspace,
|
||||
shape,
|
||||
alpha: stored_alpha.expect("Could not retrieve texture"),
|
||||
lemit: Ptr::from(&lemit.device()),
|
||||
two_sided,
|
||||
scale,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CreateLight for DiffuseAreaLight {
|
||||
fn create(
|
||||
render_from_light: Transform,
|
||||
|
|
@ -186,17 +103,61 @@ impl CreateLight for DiffuseAreaLight {
|
|||
scale *= phi_v / k_e;
|
||||
}
|
||||
|
||||
let specific = DiffuseAreaLight::new(
|
||||
render_from_light,
|
||||
medium.into(),
|
||||
*l_for_scale,
|
||||
let alpha_ptr = alpha.upload(arena);
|
||||
let is_constant_zero = match &*alpha_ptr {
|
||||
GPUFloatTexture::Constant(tex) => tex.evaluate(&TextureEvalContext::default()) == 0.0,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let (light_type, stored_alpha) = if is_constant_zero {
|
||||
(LightType::DeltaPosition, None)
|
||||
} else {
|
||||
(LightType::Area, Some(alpha))
|
||||
};
|
||||
|
||||
let base = LightBase::new(light_type, render_from_light, medium.into());
|
||||
if let Some(ref img) = image {
|
||||
let desc = img
|
||||
.get_channel_desc(&["R", "G", "B"])
|
||||
.expect("Image used for DiffuseAreaLight doesn't have R, G, B channels");
|
||||
assert_eq!(3, desc.size());
|
||||
assert!(desc.is_identity());
|
||||
assert!(
|
||||
image_color_space.is_some(),
|
||||
"Image provided but ColorSpace is missing"
|
||||
);
|
||||
}
|
||||
|
||||
let is_triangle_or_bilinear =
|
||||
matches!(*shape, Shape::Triangle(_) | Shape::BilinearPatch(_));
|
||||
if render_from_light.has_scale(None) && !is_triangle_or_bilinear {
|
||||
println!(
|
||||
"Scaling detected in rendering to light space transformation! \
|
||||
Proceed at your own risk; your image may have errors."
|
||||
);
|
||||
}
|
||||
|
||||
let shape_ptr = shape.upload(arena);
|
||||
let image_ptr = image
|
||||
.as_ref()
|
||||
.map(|img| arena.alloc(*img.device()))
|
||||
.unwrap_or(Ptr::null());
|
||||
let colorspace_ptr = image_color_space
|
||||
.map(|cs| cs.upload(arena))
|
||||
.unwrap_or(Ptr::null());
|
||||
let lemit_ptr = arena.alloc(lookup_spectrum(l_for_scale).device());
|
||||
|
||||
let specific = DiffuseAreaLight {
|
||||
base,
|
||||
area: shape.area(),
|
||||
shape: shape_ptr,
|
||||
alpha: alpha_ptr,
|
||||
image: image_ptr,
|
||||
colorspace: colorspace_ptr,
|
||||
lemit: lemit_ptr,
|
||||
two_sided,
|
||||
scale,
|
||||
shape.upload(arena),
|
||||
alpha.upload(arena),
|
||||
Ptr::from(&image.unwrap()),
|
||||
image_color_space.upload(arena),
|
||||
true,
|
||||
);
|
||||
};
|
||||
|
||||
Ok(Light::DiffuseArea(specific))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ use crate::core::light::{CreateLight, lookup_spectrum};
|
|||
use crate::core::spectrum::spectrum_to_photometric;
|
||||
use crate::core::texture::FloatTexture;
|
||||
use crate::utils::sampling::PiecewiseConstant2D;
|
||||
use crate::utils::{Arena, FileLoc, ParameterDictionary, resolve_filename};
|
||||
use crate::utils::{Arena, FileLoc, ParameterDictionary, Upload, resolve_filename};
|
||||
use anyhow::{Result, anyhow};
|
||||
use shared::core::geometry::Point2i;
|
||||
use shared::core::light::{Light, LightBase, LightType};
|
||||
use shared::core::medium::{Medium, MediumInterface};
|
||||
use shared::core::medium::Medium;
|
||||
use shared::core::shape::Shape;
|
||||
use shared::core::spectrum::Spectrum;
|
||||
use shared::core::texture::SpectrumType;
|
||||
|
|
@ -18,42 +18,6 @@ use shared::spectra::RGBColorSpace;
|
|||
use shared::utils::{Ptr, Transform};
|
||||
use shared::{Float, PI};
|
||||
|
||||
pub trait CreateGoniometricLight {
|
||||
fn new(
|
||||
render_from_light: Transform,
|
||||
medium_interface: MediumInterface,
|
||||
le: Spectrum,
|
||||
scale: Float,
|
||||
image: Ptr<Image>,
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
impl CreateGoniometricLight for GoniometricLight {
|
||||
fn new(
|
||||
render_from_light: Transform,
|
||||
medium_interface: MediumInterface,
|
||||
le: Spectrum,
|
||||
scale: Float,
|
||||
image: Ptr<Image>,
|
||||
) -> Self {
|
||||
let base = LightBase::new(
|
||||
LightType::DeltaPosition,
|
||||
render_from_light,
|
||||
medium_interface,
|
||||
);
|
||||
|
||||
let iemit = lookup_spectrum(&le);
|
||||
let distrib = PiecewiseConstant2D::from_image(&image);
|
||||
Self {
|
||||
base,
|
||||
iemit: Ptr::from(&iemit.device()),
|
||||
scale,
|
||||
image: Ptr::from(image.device()),
|
||||
distrib: Ptr::from(&distrib.device),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CreateLight for GoniometricLight {
|
||||
fn create(
|
||||
render_from_light: Transform,
|
||||
|
|
@ -63,7 +27,7 @@ impl CreateLight for GoniometricLight {
|
|||
_shape: &Shape,
|
||||
_alpha_text: &FloatTexture,
|
||||
colorspace: Option<&RGBColorSpace>,
|
||||
_arena: &Arena,
|
||||
arena: &Arena,
|
||||
) -> Result<Light> {
|
||||
let i = params
|
||||
.get_one_spectrum(
|
||||
|
|
@ -116,8 +80,30 @@ impl CreateLight for GoniometricLight {
|
|||
.expect("Could not create transform for GoniometricLight");
|
||||
let final_render_from_light = render_from_light * t;
|
||||
|
||||
let specific =
|
||||
GoniometricLight::new(final_render_from_light, medium.into(), i, scale, image);
|
||||
let base = LightBase::new(
|
||||
LightType::DeltaPosition,
|
||||
final_render_from_light,
|
||||
medium.into(),
|
||||
);
|
||||
|
||||
let iemit = lookup_spectrum(&i);
|
||||
|
||||
let image_ptr = if !image.is_null() {
|
||||
let distrib = PiecewiseConstant2D::from_image(&image);
|
||||
let distrib_ptr = distrib.upload(arena);
|
||||
let img_ptr = image.upload(arena);
|
||||
(img_ptr, distrib_ptr)
|
||||
} else {
|
||||
(Ptr::null(), Ptr::null())
|
||||
};
|
||||
|
||||
let specific = GoniometricLight {
|
||||
base,
|
||||
iemit: arena.alloc(iemit.device()),
|
||||
scale,
|
||||
image: image_ptr.0,
|
||||
distrib: image_ptr.1,
|
||||
};
|
||||
|
||||
Ok(Light::Goniometric(specific))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,9 @@ pub mod projection;
|
|||
pub mod sampler;
|
||||
pub mod spot;
|
||||
|
||||
pub use diffuse::CreateDiffuseLight;
|
||||
pub use distant::CreateDistantLight;
|
||||
pub use goniometric::CreateGoniometricLight;
|
||||
pub use infinite::{
|
||||
CreateImageInfiniteLight, CreatePortalInfiniteLight, CreateUniformInfiniteLight,
|
||||
};
|
||||
pub use point::CreatePointLight;
|
||||
pub use projection::CreateProjectionLight;
|
||||
pub use spot::CreateSpotLight;
|
||||
|
|
|
|||
|
|
@ -10,88 +10,14 @@ use shared::core::geometry::{
|
|||
Bounds2f, Point2f, Point2i, Point3f, Vector3f, VectorLike, cos_theta,
|
||||
};
|
||||
use shared::core::light::{Light, LightBase, LightType};
|
||||
use shared::core::medium::{Medium, MediumInterface};
|
||||
use shared::core::medium::Medium;
|
||||
use shared::core::shape::Shape;
|
||||
use shared::core::spectrum::Spectrum;
|
||||
use shared::lights::ProjectionLight;
|
||||
use shared::spectra::RGBColorSpace;
|
||||
use shared::utils::Transform;
|
||||
use shared::utils::math::{radians, square};
|
||||
use shared::utils::{Ptr, Transform};
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait CreateProjectionLight {
|
||||
fn new(
|
||||
render_from_light: Transform,
|
||||
medium_interface: MediumInterface,
|
||||
scale: Float,
|
||||
image: Arc<Image>,
|
||||
image_color_space: Ptr<RGBColorSpace>,
|
||||
fov: Float,
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
impl CreateProjectionLight for ProjectionLight {
|
||||
fn new(
|
||||
render_from_light: Transform,
|
||||
medium_interface: MediumInterface,
|
||||
scale: Float,
|
||||
image: Arc<Image>,
|
||||
image_color_space: Ptr<RGBColorSpace>,
|
||||
fov: Float,
|
||||
) -> Self {
|
||||
let base = LightBase::new(
|
||||
LightType::DeltaPosition,
|
||||
render_from_light,
|
||||
medium_interface,
|
||||
);
|
||||
|
||||
let opposite = (radians(fov) / 2.0).tan();
|
||||
let res = image.resolution();
|
||||
let aspect = res.x() as Float / res.y() as Float;
|
||||
let aspect_ratio = if aspect > 1.0 { aspect } else { 1.0 / aspect };
|
||||
let a = 4.0 * square(opposite) * aspect_ratio;
|
||||
let screen_bounds = if aspect > 1.0 {
|
||||
Bounds2f::from_points(Point2f::new(-aspect, -1.0), Point2f::new(aspect, 1.0))
|
||||
} else {
|
||||
Bounds2f::from_points(
|
||||
Point2f::new(-1.0, -1.0 / aspect),
|
||||
Point2f::new(1.0, 1.0 / aspect),
|
||||
)
|
||||
};
|
||||
|
||||
let hither = 1e-3;
|
||||
let screen_from_light = Transform::perspective(fov, hither, 1e30).unwrap();
|
||||
let light_from_screen = screen_from_light.inverse();
|
||||
|
||||
let dwda = |p: Point2f| {
|
||||
let w =
|
||||
Vector3f::from(light_from_screen.apply_to_point(Point3f::new(p.x(), p.y(), 0.0)));
|
||||
cos_theta(w.normalize()).powi(3)
|
||||
};
|
||||
|
||||
let d = image.get_sampling_distribution(dwda, screen_bounds);
|
||||
let distrib = PiecewiseConstant2D::from_slice(
|
||||
d.as_slice(),
|
||||
d.x_size() as usize,
|
||||
d.y_size() as usize,
|
||||
screen_bounds,
|
||||
);
|
||||
|
||||
Self {
|
||||
base,
|
||||
image: Ptr::from(image.device()),
|
||||
image_color_space,
|
||||
distrib: Ptr::from(&distrib.device),
|
||||
screen_bounds,
|
||||
screen_from_light,
|
||||
light_from_screen,
|
||||
scale,
|
||||
hither,
|
||||
a,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CreateLight for ProjectionLight {
|
||||
fn create(
|
||||
|
|
@ -155,15 +81,53 @@ impl CreateLight for ProjectionLight {
|
|||
let flip = Transform::scale(1., -1., 1.);
|
||||
let render_from_light_flip = render_from_light * flip;
|
||||
|
||||
let specific = ProjectionLight::new(
|
||||
render_from_light_flip,
|
||||
medium.into(),
|
||||
scale,
|
||||
Arc::new(image),
|
||||
colorspace.upload(arena),
|
||||
fov,
|
||||
let base = LightBase::new(LightType::DeltaPosition, render_from_light, medium.into());
|
||||
|
||||
let opposite = (radians(fov) / 2.0).tan();
|
||||
let res = image.resolution();
|
||||
let aspect = res.x() as Float / res.y() as Float;
|
||||
let aspect_ratio = if aspect > 1.0 { aspect } else { 1.0 / aspect };
|
||||
let a = 4.0 * square(opposite) * aspect_ratio;
|
||||
let screen_bounds = if aspect > 1.0 {
|
||||
Bounds2f::from_points(Point2f::new(-aspect, -1.0), Point2f::new(aspect, 1.0))
|
||||
} else {
|
||||
Bounds2f::from_points(
|
||||
Point2f::new(-1.0, -1.0 / aspect),
|
||||
Point2f::new(1.0, 1.0 / aspect),
|
||||
)
|
||||
};
|
||||
|
||||
let hither = 1e-3;
|
||||
let screen_from_light = Transform::perspective(fov, hither, 1e30).unwrap();
|
||||
let light_from_screen = screen_from_light.inverse();
|
||||
|
||||
let dwda = |p: Point2f| {
|
||||
let w =
|
||||
Vector3f::from(light_from_screen.apply_to_point(Point3f::new(p.x(), p.y(), 0.0)));
|
||||
cos_theta(w.normalize()).powi(3)
|
||||
};
|
||||
|
||||
let d = image.get_sampling_distribution(dwda, screen_bounds);
|
||||
let distrib = PiecewiseConstant2D::from_slice(
|
||||
d.as_slice(),
|
||||
d.x_size() as usize,
|
||||
d.y_size() as usize,
|
||||
screen_bounds,
|
||||
);
|
||||
|
||||
let specific = ProjectionLight {
|
||||
base,
|
||||
image: image.upload(arena),
|
||||
image_color_space: colorspace.upload(arena),
|
||||
distrib: distrib.upload(arena),
|
||||
screen_bounds,
|
||||
screen_from_light,
|
||||
light_from_screen,
|
||||
scale,
|
||||
hither,
|
||||
a,
|
||||
};
|
||||
|
||||
Ok(Light::Projection(specific))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ impl CreateShape for TriangleShape {
|
|||
if vertex_indices.is_empty() {
|
||||
if p.len() == 3 {
|
||||
} else {
|
||||
return bail!("Vertex indices \"indices\" must be provided with triangle mesh.");
|
||||
bail!("Vertex indices \"indices\" must be provided with triangle mesh.");
|
||||
}
|
||||
} else if vertex_indices.len() % 3 != 0 {
|
||||
let excess = vertex_indices.len() % 3;
|
||||
|
|
@ -43,7 +43,7 @@ impl CreateShape for TriangleShape {
|
|||
}
|
||||
|
||||
if p.is_empty() {
|
||||
return bail!("Vertex positions \"P\" must be provided with triangle mesh.");
|
||||
bail!("Vertex positions \"P\" must be provided with triangle mesh.");
|
||||
}
|
||||
|
||||
if !uvs.is_empty() && uvs.len() != p.len() {
|
||||
|
|
@ -64,7 +64,7 @@ impl CreateShape for TriangleShape {
|
|||
for (_, &index) in vertex_indices.iter().enumerate() {
|
||||
// Check for negative indices (if keeping i32) or out of bounds
|
||||
if index < 0 || index as usize >= p.len() {
|
||||
return bail!(
|
||||
bail!(
|
||||
"TriangleMesh has out-of-bounds vertex index {} ({} \"P\" values were given). Discarding this mesh.",
|
||||
index,
|
||||
p.len()
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ pub mod vulkan {
|
|||
fn inner() -> &'static VulkanAllocatorInner {
|
||||
VK_ALLOCATOR
|
||||
.get()
|
||||
.expect("Vulkan not initialized — call init_vulkan() before Arena::default()")
|
||||
.expect("Vulkan not initialized — call init_vulkan() before arena creation")
|
||||
}
|
||||
|
||||
impl Default for VulkanAllocator {
|
||||
|
|
|
|||
|
|
@ -66,37 +66,37 @@ pub trait ParserTarget {
|
|||
fn pixel_filter(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError>;
|
||||
fn film(
|
||||
&mut self,
|
||||
type_name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError>;
|
||||
fn accelerator(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError>;
|
||||
fn integrator(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError>;
|
||||
fn camera(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError>;
|
||||
fn make_named_medium(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError>;
|
||||
fn medium_interface(
|
||||
|
|
@ -108,7 +108,7 @@ pub trait ParserTarget {
|
|||
fn sampler(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError>;
|
||||
|
||||
|
|
@ -127,20 +127,20 @@ pub trait ParserTarget {
|
|||
name: &str,
|
||||
type_name: &str,
|
||||
tex_name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
arena: Arc<Arena>,
|
||||
) -> Result<(), ParserError>;
|
||||
fn material(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError>;
|
||||
fn make_named_material(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError>;
|
||||
fn named_material(&mut self, name: &str, loc: FileLoc) -> Result<(), ParserError>;
|
||||
|
|
@ -148,20 +148,20 @@ pub trait ParserTarget {
|
|||
fn light_source(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError>;
|
||||
fn area_light_source(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError>;
|
||||
|
||||
fn shape(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
loc: FileLoc,
|
||||
) -> Result<(), ParserError>;
|
||||
fn reverse_orientation(&mut self, loc: FileLoc) -> Result<(), ParserError>;
|
||||
|
|
@ -594,7 +594,7 @@ impl ParserTarget for FormattingParserTarget {
|
|||
fn shape(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
_loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
println!(
|
||||
|
|
@ -609,7 +609,7 @@ impl ParserTarget for FormattingParserTarget {
|
|||
fn material(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &ParsedParameterVector,
|
||||
params: ParsedParameterVector,
|
||||
_loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
println!(
|
||||
|
|
@ -626,7 +626,7 @@ impl ParserTarget for FormattingParserTarget {
|
|||
name: &str,
|
||||
type_name: &str,
|
||||
tex_name: &str,
|
||||
_params: &ParsedParameterVector,
|
||||
_params: ParsedParameterVector,
|
||||
_loc: FileLoc,
|
||||
_arena: Arc<Arena>,
|
||||
) -> Result<(), ParserError> {
|
||||
|
|
@ -658,7 +658,7 @@ impl ParserTarget for FormattingParserTarget {
|
|||
fn pixel_filter(
|
||||
&mut self,
|
||||
_n: &str,
|
||||
_p: &ParsedParameterVector,
|
||||
_p: ParsedParameterVector,
|
||||
_loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
Ok(())
|
||||
|
|
@ -666,7 +666,7 @@ impl ParserTarget for FormattingParserTarget {
|
|||
fn film(
|
||||
&mut self,
|
||||
_t: &str,
|
||||
_p: &ParsedParameterVector,
|
||||
_p: ParsedParameterVector,
|
||||
_loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
Ok(())
|
||||
|
|
@ -674,7 +674,7 @@ impl ParserTarget for FormattingParserTarget {
|
|||
fn accelerator(
|
||||
&mut self,
|
||||
_n: &str,
|
||||
_p: &ParsedParameterVector,
|
||||
_p: ParsedParameterVector,
|
||||
_loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
Ok(())
|
||||
|
|
@ -682,7 +682,7 @@ impl ParserTarget for FormattingParserTarget {
|
|||
fn integrator(
|
||||
&mut self,
|
||||
_n: &str,
|
||||
_p: &ParsedParameterVector,
|
||||
_p: ParsedParameterVector,
|
||||
_loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
Ok(())
|
||||
|
|
@ -690,7 +690,7 @@ impl ParserTarget for FormattingParserTarget {
|
|||
fn camera(
|
||||
&mut self,
|
||||
_n: &str,
|
||||
_p: &ParsedParameterVector,
|
||||
_p: ParsedParameterVector,
|
||||
_loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
Ok(())
|
||||
|
|
@ -698,7 +698,7 @@ impl ParserTarget for FormattingParserTarget {
|
|||
fn make_named_medium(
|
||||
&mut self,
|
||||
_n: &str,
|
||||
_p: &ParsedParameterVector,
|
||||
_p: ParsedParameterVector,
|
||||
_loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
Ok(())
|
||||
|
|
@ -709,7 +709,7 @@ impl ParserTarget for FormattingParserTarget {
|
|||
fn sampler(
|
||||
&mut self,
|
||||
_n: &str,
|
||||
_p: &ParsedParameterVector,
|
||||
_p: ParsedParameterVector,
|
||||
_loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
Ok(())
|
||||
|
|
@ -725,7 +725,7 @@ impl ParserTarget for FormattingParserTarget {
|
|||
fn make_named_material(
|
||||
&mut self,
|
||||
_n: &str,
|
||||
_p: &ParsedParameterVector,
|
||||
_p: ParsedParameterVector,
|
||||
_loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
Ok(())
|
||||
|
|
@ -736,7 +736,7 @@ impl ParserTarget for FormattingParserTarget {
|
|||
fn light_source(
|
||||
&mut self,
|
||||
_n: &str,
|
||||
_p: &ParsedParameterVector,
|
||||
_p: ParsedParameterVector,
|
||||
_loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
Ok(())
|
||||
|
|
@ -744,7 +744,7 @@ impl ParserTarget for FormattingParserTarget {
|
|||
fn area_light_source(
|
||||
&mut self,
|
||||
_n: &str,
|
||||
_p: &ParsedParameterVector,
|
||||
_p: ParsedParameterVector,
|
||||
_loc: FileLoc,
|
||||
) -> Result<(), ParserError> {
|
||||
Ok(())
|
||||
|
|
@ -1093,7 +1093,7 @@ impl<'a> SceneParser<'a> {
|
|||
.collect::<Result<_, _>>()?;
|
||||
self.target.look_at(
|
||||
v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], token.loc,
|
||||
);
|
||||
)?;
|
||||
}
|
||||
_ => {
|
||||
return Err(ParserError::Generic(
|
||||
|
|
@ -1186,7 +1186,7 @@ impl<'a> SceneParser<'a> {
|
|||
let ax = self.expect_float()?;
|
||||
let ay = self.expect_float()?;
|
||||
let az = self.expect_float()?;
|
||||
self.target.rotate(angle, ax, ay, az, token.loc);
|
||||
self.target.rotate(angle, ax, ay, az, token.loc)?;
|
||||
}
|
||||
_ => {
|
||||
return Err(ParserError::Generic(
|
||||
|
|
@ -1203,7 +1203,7 @@ impl<'a> SceneParser<'a> {
|
|||
let x = self.expect_float()?;
|
||||
let y = self.expect_float()?;
|
||||
let z = self.expect_float()?;
|
||||
self.target.scale(x, y, z, token.loc);
|
||||
self.target.scale(x, y, z, token.loc)?;
|
||||
}
|
||||
_ => {
|
||||
return Err(ParserError::Generic(
|
||||
|
|
@ -1245,7 +1245,7 @@ impl<'a> SceneParser<'a> {
|
|||
&name,
|
||||
&type_name,
|
||||
&tex_name,
|
||||
¶ms,
|
||||
params,
|
||||
token.loc,
|
||||
arena.clone(),
|
||||
)?;
|
||||
|
|
@ -1310,7 +1310,7 @@ impl<'a> SceneParser<'a> {
|
|||
F: FnMut(
|
||||
&mut dyn ParserTarget,
|
||||
&str,
|
||||
&ParsedParameterVector,
|
||||
ParsedParameterVector,
|
||||
FileLoc,
|
||||
) -> Result<(), ParserError>,
|
||||
{
|
||||
|
|
@ -1322,6 +1322,6 @@ impl<'a> SceneParser<'a> {
|
|||
};
|
||||
|
||||
let params = self.parse_parameters()?;
|
||||
func(self.target, &type_name, ¶ms, type_token.loc)
|
||||
func(self.target, &type_name, params, type_token.loc)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue