From 1e0840dcda4203a401d0c08a1a57afc25fba5426 Mon Sep 17 00:00:00 2001 From: Wito Wiala Date: Thu, 14 May 2026 15:08:14 +0100 Subject: [PATCH] Continuing work on BVH creation --- src/core/aggregates.rs | 2 - src/core/light.rs | 1 - src/core/scene/scene.rs | 121 ++++++++++++++++++++-------------------- src/core/shape.rs | 20 +++++-- src/films/rgb.rs | 1 - src/globals.rs | 1 - src/shapes/bilinear.rs | 9 ++- src/shapes/curves.rs | 16 +++--- src/shapes/cylinder.rs | 6 +- src/shapes/disk.rs | 6 +- src/shapes/sphere.rs | 6 +- src/shapes/triangle.rs | 9 ++- 12 files changed, 102 insertions(+), 96 deletions(-) diff --git a/src/core/aggregates.rs b/src/core/aggregates.rs index 2277cb5..7ca1b1f 100644 --- a/src/core/aggregates.rs +++ b/src/core/aggregates.rs @@ -6,9 +6,7 @@ use shared::utils::math::encode_morton_3; use shared::utils::{find_interval, partition_slice}; use shared::Float; use std::cmp::Ordering; -use std::mem::MaybeUninit; use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; -use std::sync::Arc; #[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/src/core/light.rs b/src/core/light.rs index c02abe9..8858645 100644 --- a/src/core/light.rs +++ b/src/core/light.rs @@ -8,7 +8,6 @@ use shared::core::light::Light; use shared::core::medium::Medium; use shared::core::shape::Shape; use shared::core::spectrum::Spectrum; -use shared::lights::*; use shared::spectra::RGBColorSpace; use shared::utils::Transform; use std::sync::Arc; diff --git a/src/core/scene/scene.rs b/src/core/scene/scene.rs index 039da42..103954c 100644 --- a/src/core/scene/scene.rs +++ b/src/core/scene/scene.rs @@ -7,7 +7,7 @@ use crate::core::image::{io::ImageIO, Image}; use crate::core::material::MaterialFactory; use crate::core::primitive::{CreateGeometricPrimitive, CreateSimplePrimitive}; use crate::core::sampler::SamplerFactory; -use crate::core::shape::ShapeFactory; +use crate::core::shape::{ShapeFactory, ShapeWithContext}; use crate::core::texture::{FloatTexture, SpectrumTexture}; use crate::utils::parallel::{run_async, AsyncJob}; use crate::utils::parameters::{NamedTextures, ParameterDictionary, TextureParameterDictionary}; @@ -665,37 +665,46 @@ impl BasicScene { entities: &[ShapeSceneEntity], lookup: &SceneLookup, arena: &mut Arena, - ) -> Vec> { - entities - .par_iter() - .map(|sh| { - Shape::create( - &sh.base.name, - *sh.render_from_object.as_ref(), - *sh.object_from_render.as_ref(), - sh.reverse_orientation, - sh.base.parameters.clone(), - &lookup.textures.float_textures, - sh.base.loc.clone(), - arena, - ) - .unwrap_or_else(|e| { - eprintln!("Shape '{}' failed: {}", sh.base.name, e); - Vec::new() - }) - }) - .collect() - } + ) -> Vec { + // Flat vector with context + let mut shapes_with_context = Vec::new(); + for (entity_index, entity) in entities.iter().enumerate() { + let shapes = Shape::create( + &entity.base.name, + *entity.render_from_object.as_ref(), + *entity.object_from_render.as_ref(), + entity.reverse_orientation, + entity.base.parameters.clone(), + &lookup.textures.float_textures, + entity.base.loc.clone(), + arena, + ) + .unwrap_or_else(|e| { + eprintln!("Shape '{}' failed: {}", entity.base.name, e); + Vec::new() + }); + + for (shape_index, shape) in shapes.into_iter().enumerate() { + shapes_with_context.push(ShapeWithContext { + shape, + entity_index, + shape_index, + }); + } + } + + shapes_with_context + } fn load_animated_shapes_parallel( &self, entities: &[AnimatedShapeSceneEntity], lookup: &SceneLookup, arena: &Arena, - ) -> Vec> { + ) -> Vec> { entities .par_iter() - .map(|sh| { + .flat_map(|sh| { Shape::create( &sh.transformed_base.base.name, *sh.identity.as_ref(), @@ -706,7 +715,10 @@ impl BasicScene { sh.transformed_base.base.loc.clone(), arena, ) - .expect("Could not create shape") + .unwrap_or_else(|e| { + eprintln!("Shape '{}' failed: {}", sh.transformed_base.base.name, e); + Vec::new() + }) }) .collect() } @@ -715,15 +727,13 @@ impl BasicScene { &self, arena: &Arena, entities: &[ShapeSceneEntity], - loaded: Vec>, + loaded: Vec, lookup: &SceneLookup, ) -> Vec { let mut primitives = Vec::new(); - for (i, (entity, shapes)) in entities.iter().zip(loaded).enumerate() { - if shapes.is_empty() { - continue; - } + for shape_ctx in loaded { + let entity = &entities[shape_ctx.entity_index]; let alpha_tex = self.get_alpha_texture( &entity.base.parameters, @@ -746,37 +756,30 @@ impl BasicScene { .unwrap_or(Ptr::null()), }; - let shape_lights_opt = lookup.shape_lights.get(&i); + let shape_lights_opt = lookup + .shape_lights + .get(&shape_ctx.entity_index) + .and_then(|lights| lights.get(shape_ctx.shape_index)); - for (j, shape) in shapes.into_iter().enumerate() { - let mut area_light = None; - if entity.light_index.is_some() { - if let Some(lights) = shape_lights_opt { - if j < lights.len() { - area_light = Some(lights[j].clone()); - } - } - } + let area_light = shape_lights_opt + .map(|l| l.upload(arena)) + .unwrap_or(Ptr::null()); - let shape_ptr = shape.upload(arena); + let shape_ptr = shape_ctx.shape; + let prim = if area_light.is_null() && !mi.is_medium_transition() && alpha_tex.is_none() + { + Primitive::Simple(SimplePrimitive::new(shape_ptr, Ptr::from(&mtl))) + } else { + Primitive::Geometric(GeometricPrimitive::new( + shape_ptr, + mtl.upload(arena), + area_light, + mi.clone(), + alpha_tex.upload(arena), + )) + }; - let prim = - if area_light.is_none() && !mi.is_medium_transition() && alpha_tex.is_none() { - let p = SimplePrimitive::new(shape_ptr, Ptr::from(&mtl)); - Primitive::Simple(p) - } else { - let p = GeometricPrimitive::new( - shape_ptr, - mtl.upload(arena), - area_light.upload(arena), - mi.clone(), - alpha_tex.upload(arena), - ); - Primitive::Geometric(p) - }; - - primitives.push(prim); - } + primitives.push(prim); } primitives @@ -786,7 +789,7 @@ impl BasicScene { &self, _arena: &mut Arena, _entities: &[AnimatedShapeSceneEntity], - _loaded: Vec>, + _loaded: Vec>, _lookup: &SceneLookup, ) -> Vec { // TODO: implement animated shape upload diff --git a/src/core/shape.rs b/src/core/shape.rs index 56e470b..6d9ce32 100644 --- a/src/core/shape.rs +++ b/src/core/shape.rs @@ -13,6 +13,13 @@ use std::sync::Arc; pub static ALL_TRIANGLE_MESHES: Mutex>> = Mutex::new(Vec::new()); pub static ALL_BILINEAR_MESHES: Mutex>> = Mutex::new(Vec::new()); +#[derive(Debug, Clone)] +pub struct ShapeWithContext { + pub shape: Ptr, + pub entity_index: usize, + pub shape_index: usize, +} + pub trait CreateShape { fn create( render_from_object: Transform, @@ -22,7 +29,7 @@ pub trait CreateShape { float_textures: &HashMap>, loc: FileLoc, arena: &Arena, - ) -> Result>; + ) -> Result>>; } pub trait ShapeFactory { @@ -35,7 +42,7 @@ pub trait ShapeFactory { float_textures: &HashMap>, loc: FileLoc, arena: &Arena, - ) -> Result>; + ) -> Result>>; } impl ShapeFactory for Shape { @@ -48,7 +55,7 @@ impl ShapeFactory for Shape { float_textures: &HashMap>, loc: FileLoc, arena: &Arena, - ) -> Result> { + ) -> Result>> { match name { "sphere" => SphereShape::create( render_from_object, @@ -111,12 +118,13 @@ impl ShapeFactory for Shape { let n_tris = host_arc.device.n_triangles; let mesh_ptr = Ptr::from(&host_arc.device); - let shapes: Vec = (0..n_tris) + let shapes: Vec> = (0..n_tris) .map(|i| { - Shape::Triangle(TriangleShape { + let tri_shape = Shape::Triangle(TriangleShape { mesh: mesh_ptr, tri_index: i as i32, - }) + }); + arena.alloc(tri_shape) }) .collect(); diff --git a/src/films/rgb.rs b/src/films/rgb.rs index e63f49b..cd39dd5 100644 --- a/src/films/rgb.rs +++ b/src/films/rgb.rs @@ -1,7 +1,6 @@ use super::*; use crate::core::film::{CreateFilmBase, PixelSensor}; use crate::utils::containers::Array2D; -use std::sync::Arc; use crate::Arena; use anyhow::Result; use shared::core::camera::CameraTransform; diff --git a/src/globals.rs b/src/globals.rs index 9c44d76..7b15fde 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -1,6 +1,5 @@ use crate::core::color::RGBToSpectrumTableData; use shared::core::color::RES; -use bytemuck::cast_slice; use once_cell::sync::Lazy; use shared::Float; use shared::PBRTOptions; diff --git a/src/shapes/bilinear.rs b/src/shapes/bilinear.rs index b85ab48..403a80d 100644 --- a/src/shapes/bilinear.rs +++ b/src/shapes/bilinear.rs @@ -21,8 +21,8 @@ impl CreateShape for BilinearPatchShape { parameters: ParameterDictionary, _float_textures: &HashMap>, _loc: FileLoc, - _arena: &Arena, - ) -> Result> { + arena: &Arena, + ) -> Result>> { let mut vertex_indices = parameters.get_int_array("indices")?; let p = parameters.get_point3f_array("P")?; let mut uv = parameters.get_point2f_array("uv")?; @@ -121,14 +121,13 @@ impl CreateShape for BilinearPatchShape { let mesh_ptr = Ptr::from(&host_arc.device); let mut shapes = Vec::with_capacity(n_patches as usize); for i in 0..n_patches as i32 { - shapes.push(Shape::BilinearPatch(BilinearPatchShape { + shapes.push(arena.alloc(Shape::BilinearPatch(BilinearPatchShape { mesh: mesh_ptr, blp_index: i, area: 0.0, rectangle: false, - })); + }))); } - // arena.alloc(shapes); Ok(shapes) } } diff --git a/src/shapes/curves.rs b/src/shapes/curves.rs index 53570f0..7fed644 100644 --- a/src/shapes/curves.rs +++ b/src/shapes/curves.rs @@ -12,6 +12,7 @@ use shared::utils::math::lerp; use shared::utils::splines::{ cubic_bspline_to_bezier, elevate_quadratic_bezier_to_cubic, quadratic_bspline_to_bezier, }; +use shared::Ptr; use log::warn; use std::collections::HashMap; @@ -27,7 +28,8 @@ pub fn create_curve( curve_type: CurveType, seg_normals: &[Normal3f], split_depth: usize, -) -> Vec { + arena: &Arena, +) -> Vec> { let curve_common = CurveCommon::new( seg_cp_bezier, w0, @@ -39,7 +41,7 @@ pub fn create_curve( reverse_orientation, ); let n_segments = 1 << split_depth; - let mut segments: Vec = Vec::with_capacity(n_segments); + let mut segments: Vec> = Vec::with_capacity(n_segments); for i in 0..n_segments { let u_min = i as Float / n_segments as Float; @@ -51,7 +53,7 @@ pub fn create_curve( u_max, }; - segments.push(Shape::Curve(curve)); + segments.push(arena.alloc(Shape::Curve(curve))); } segments } @@ -64,8 +66,8 @@ impl CreateShape for CurveShape { parameters: ParameterDictionary, _float_textures: &HashMap>, _loc: FileLoc, - _arena: &Arena, - ) -> Result> { + arena: &Arena, + ) -> Result>> { let width = parameters.get_one_float("width", 1.0)?; let width0 = parameters.get_one_float("width0", width)?; let width1 = parameters.get_one_float("width1", width)?; @@ -150,7 +152,7 @@ impl CreateShape for CurveShape { parameters.get_one_int("splitdepth", 3)? }; - let mut curves: Vec = Vec::new(); + let mut curves: Vec> = Vec::new(); let mut cp_offset = 0; for seg in 0..n_segments { @@ -197,11 +199,11 @@ impl CreateShape for CurveShape { curve_type, seg_normals.expect("Could not determine normals to curve segments"), split_depth.try_into().unwrap(), + arena ); curves.extend(new_curves); } - // arena.alloc(curves); Ok(curves) } } diff --git a/src/shapes/cylinder.rs b/src/shapes/cylinder.rs index 797ad2a..7ab7463 100644 --- a/src/shapes/cylinder.rs +++ b/src/shapes/cylinder.rs @@ -7,6 +7,7 @@ use shared::shapes::CylinderShape; use shared::utils::Transform; use std::collections::HashMap; use std::sync::Arc; +use shared::Ptr; impl CreateShape for CylinderShape { fn create( @@ -17,7 +18,7 @@ impl CreateShape for CylinderShape { _float_textures: &HashMap>, _loc: FileLoc, arena: &Arena, - ) -> Result> { + ) -> Result>> { let radius = parameters.get_one_float("radius", 1.)?; let z_min = parameters.get_one_float("zmin", -1.)?; let z_max = parameters.get_one_float("zmax", 1.)?; @@ -32,7 +33,6 @@ impl CreateShape for CylinderShape { phi_max, ); - arena.alloc(Shape::Cylinder(shape)); - Ok(vec![Shape::Cylinder(shape)]) + Ok(vec![arena.alloc(Shape::Cylinder(shape))]) } } diff --git a/src/shapes/disk.rs b/src/shapes/disk.rs index a082685..8b5eee6 100644 --- a/src/shapes/disk.rs +++ b/src/shapes/disk.rs @@ -7,6 +7,7 @@ use shared::shapes::DiskShape; use shared::utils::Transform; use std::collections::HashMap; use std::sync::Arc; +use shared::Ptr; impl CreateShape for DiskShape { fn create( @@ -17,7 +18,7 @@ impl CreateShape for DiskShape { _float_textures: &HashMap>, _loc: FileLoc, arena: &Arena, - ) -> Result> { + ) -> Result>> { let height = parameters.get_one_float("height", 0.)?; let radius = parameters.get_one_float("radius", 1.)?; let inner_radius = parameters.get_one_float("innerradius", 0.)?; @@ -32,7 +33,6 @@ impl CreateShape for DiskShape { reverse_orientation, ); - arena.alloc(Shape::Disk(shape)); - Ok(vec![Shape::Disk(shape)]) + Ok(vec![arena.alloc(Shape::Disk(shape))]) } } diff --git a/src/shapes/sphere.rs b/src/shapes/sphere.rs index ec8adfa..a88d2b4 100644 --- a/src/shapes/sphere.rs +++ b/src/shapes/sphere.rs @@ -7,6 +7,7 @@ use shared::shapes::SphereShape; use shared::utils::Transform; use std::collections::HashMap; use std::sync::Arc; +use shared::Ptr; impl CreateShape for SphereShape { fn create( @@ -17,7 +18,7 @@ impl CreateShape for SphereShape { _float_textures: &HashMap>, _loc: FileLoc, arena: &Arena, - ) -> Result> { + ) -> Result>> { let radius = parameters.get_one_float("radius", 1.)?; let zmin = parameters.get_one_float("zmin", -radius)?; let zmax = parameters.get_one_float("zmax", radius)?; @@ -31,7 +32,6 @@ impl CreateShape for SphereShape { zmax, phimax, ); - arena.alloc(vec![Shape::Sphere(shape)]); - Ok(vec![Shape::Sphere(shape)]) + Ok(vec![arena.alloc(Shape::Sphere(shape))]) } } diff --git a/src/shapes/triangle.rs b/src/shapes/triangle.rs index f280a2a..ab387af 100644 --- a/src/shapes/triangle.rs +++ b/src/shapes/triangle.rs @@ -18,8 +18,8 @@ impl CreateShape for TriangleShape { parameters: ParameterDictionary, _float_texture: &HashMap>, _loc: FileLoc, - _arena: &Arena, - ) -> Result> { + arena: &Arena, + ) -> Result>> { let mut vertex_indices = parameters.get_int_array("indices")?; let p = parameters.get_point3f_array("P")?; let mut uvs = parameters.get_point2f_array("uv")?; @@ -104,13 +104,12 @@ impl CreateShape for TriangleShape { let mesh_ptr = Ptr::from(&host_arc.device); let mut shapes = Vec::with_capacity(n_patches as usize); for i in 0..n_patches { - shapes.push(Shape::Triangle(TriangleShape { + shapes.push(arena.alloc(Shape::Triangle(TriangleShape { mesh: mesh_ptr, tri_index: i as i32, - })); + }))); } - // arena.alloc(shapes); Ok(shapes) } }