Continuing work on BVH creation

This commit is contained in:
Wito Wiala 2026-05-14 15:08:14 +01:00
parent 2fc366878f
commit 1e0840dcda
12 changed files with 102 additions and 96 deletions

View file

@ -6,9 +6,7 @@ use shared::utils::math::encode_morton_3;
use shared::utils::{find_interval, partition_slice}; use shared::utils::{find_interval, partition_slice};
use shared::Float; use shared::Float;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::mem::MaybeUninit;
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
use std::sync::Arc;
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]

View file

@ -8,7 +8,6 @@ use shared::core::light::Light;
use shared::core::medium::Medium; use shared::core::medium::Medium;
use shared::core::shape::Shape; use shared::core::shape::Shape;
use shared::core::spectrum::Spectrum; use shared::core::spectrum::Spectrum;
use shared::lights::*;
use shared::spectra::RGBColorSpace; use shared::spectra::RGBColorSpace;
use shared::utils::Transform; use shared::utils::Transform;
use std::sync::Arc; use std::sync::Arc;

View file

@ -7,7 +7,7 @@ use crate::core::image::{io::ImageIO, Image};
use crate::core::material::MaterialFactory; use crate::core::material::MaterialFactory;
use crate::core::primitive::{CreateGeometricPrimitive, CreateSimplePrimitive}; use crate::core::primitive::{CreateGeometricPrimitive, CreateSimplePrimitive};
use crate::core::sampler::SamplerFactory; use crate::core::sampler::SamplerFactory;
use crate::core::shape::ShapeFactory; use crate::core::shape::{ShapeFactory, ShapeWithContext};
use crate::core::texture::{FloatTexture, SpectrumTexture}; use crate::core::texture::{FloatTexture, SpectrumTexture};
use crate::utils::parallel::{run_async, AsyncJob}; use crate::utils::parallel::{run_async, AsyncJob};
use crate::utils::parameters::{NamedTextures, ParameterDictionary, TextureParameterDictionary}; use crate::utils::parameters::{NamedTextures, ParameterDictionary, TextureParameterDictionary};
@ -665,37 +665,46 @@ impl BasicScene {
entities: &[ShapeSceneEntity], entities: &[ShapeSceneEntity],
lookup: &SceneLookup, lookup: &SceneLookup,
arena: &mut Arena, arena: &mut Arena,
) -> Vec<Vec<Shape>> { ) -> Vec<ShapeWithContext> {
entities // Flat vector with context
.par_iter() let mut shapes_with_context = Vec::new();
.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()
}
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( fn load_animated_shapes_parallel(
&self, &self,
entities: &[AnimatedShapeSceneEntity], entities: &[AnimatedShapeSceneEntity],
lookup: &SceneLookup, lookup: &SceneLookup,
arena: &Arena, arena: &Arena,
) -> Vec<Vec<Shape>> { ) -> Vec<Ptr<Shape>> {
entities entities
.par_iter() .par_iter()
.map(|sh| { .flat_map(|sh| {
Shape::create( Shape::create(
&sh.transformed_base.base.name, &sh.transformed_base.base.name,
*sh.identity.as_ref(), *sh.identity.as_ref(),
@ -706,7 +715,10 @@ impl BasicScene {
sh.transformed_base.base.loc.clone(), sh.transformed_base.base.loc.clone(),
arena, arena,
) )
.expect("Could not create shape") .unwrap_or_else(|e| {
eprintln!("Shape '{}' failed: {}", sh.transformed_base.base.name, e);
Vec::new()
})
}) })
.collect() .collect()
} }
@ -715,15 +727,13 @@ impl BasicScene {
&self, &self,
arena: &Arena, arena: &Arena,
entities: &[ShapeSceneEntity], entities: &[ShapeSceneEntity],
loaded: Vec<Vec<Shape>>, loaded: Vec<ShapeWithContext>,
lookup: &SceneLookup, lookup: &SceneLookup,
) -> Vec<Primitive> { ) -> Vec<Primitive> {
let mut primitives = Vec::new(); let mut primitives = Vec::new();
for (i, (entity, shapes)) in entities.iter().zip(loaded).enumerate() { for shape_ctx in loaded {
if shapes.is_empty() { let entity = &entities[shape_ctx.entity_index];
continue;
}
let alpha_tex = self.get_alpha_texture( let alpha_tex = self.get_alpha_texture(
&entity.base.parameters, &entity.base.parameters,
@ -746,37 +756,30 @@ impl BasicScene {
.unwrap_or(Ptr::null()), .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 area_light = shape_lights_opt
let mut area_light = None; .map(|l| l.upload(arena))
if entity.light_index.is_some() { .unwrap_or(Ptr::null());
if let Some(lights) = shape_lights_opt {
if j < lights.len() {
area_light = Some(lights[j].clone());
}
}
}
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 = primitives.push(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 primitives
@ -786,7 +789,7 @@ impl BasicScene {
&self, &self,
_arena: &mut Arena, _arena: &mut Arena,
_entities: &[AnimatedShapeSceneEntity], _entities: &[AnimatedShapeSceneEntity],
_loaded: Vec<Vec<Shape>>, _loaded: Vec<Ptr<Shape>>,
_lookup: &SceneLookup, _lookup: &SceneLookup,
) -> Vec<Primitive> { ) -> Vec<Primitive> {
// TODO: implement animated shape upload // TODO: implement animated shape upload

View file

@ -13,6 +13,13 @@ use std::sync::Arc;
pub static ALL_TRIANGLE_MESHES: Mutex<Vec<Arc<TriangleMesh>>> = Mutex::new(Vec::new()); pub static ALL_TRIANGLE_MESHES: Mutex<Vec<Arc<TriangleMesh>>> = Mutex::new(Vec::new());
pub static ALL_BILINEAR_MESHES: Mutex<Vec<Arc<BilinearPatchMesh>>> = Mutex::new(Vec::new()); pub static ALL_BILINEAR_MESHES: Mutex<Vec<Arc<BilinearPatchMesh>>> = Mutex::new(Vec::new());
#[derive(Debug, Clone)]
pub struct ShapeWithContext {
pub shape: Ptr<Shape>,
pub entity_index: usize,
pub shape_index: usize,
}
pub trait CreateShape { pub trait CreateShape {
fn create( fn create(
render_from_object: Transform, render_from_object: Transform,
@ -22,7 +29,7 @@ pub trait CreateShape {
float_textures: &HashMap<String, Arc<FloatTexture>>, float_textures: &HashMap<String, Arc<FloatTexture>>,
loc: FileLoc, loc: FileLoc,
arena: &Arena, arena: &Arena,
) -> Result<Vec<Shape>>; ) -> Result<Vec<Ptr<Shape>>>;
} }
pub trait ShapeFactory { pub trait ShapeFactory {
@ -35,7 +42,7 @@ pub trait ShapeFactory {
float_textures: &HashMap<String, Arc<FloatTexture>>, float_textures: &HashMap<String, Arc<FloatTexture>>,
loc: FileLoc, loc: FileLoc,
arena: &Arena, arena: &Arena,
) -> Result<Vec<Shape>>; ) -> Result<Vec<Ptr<Shape>>>;
} }
impl ShapeFactory for Shape { impl ShapeFactory for Shape {
@ -48,7 +55,7 @@ impl ShapeFactory for Shape {
float_textures: &HashMap<String, Arc<FloatTexture>>, float_textures: &HashMap<String, Arc<FloatTexture>>,
loc: FileLoc, loc: FileLoc,
arena: &Arena, arena: &Arena,
) -> Result<Vec<Shape>> { ) -> Result<Vec<Ptr<Shape>>> {
match name { match name {
"sphere" => SphereShape::create( "sphere" => SphereShape::create(
render_from_object, render_from_object,
@ -111,12 +118,13 @@ impl ShapeFactory for Shape {
let n_tris = host_arc.device.n_triangles; let n_tris = host_arc.device.n_triangles;
let mesh_ptr = Ptr::from(&host_arc.device); let mesh_ptr = Ptr::from(&host_arc.device);
let shapes: Vec<Shape> = (0..n_tris) let shapes: Vec<Ptr<Shape>> = (0..n_tris)
.map(|i| { .map(|i| {
Shape::Triangle(TriangleShape { let tri_shape = Shape::Triangle(TriangleShape {
mesh: mesh_ptr, mesh: mesh_ptr,
tri_index: i as i32, tri_index: i as i32,
}) });
arena.alloc(tri_shape)
}) })
.collect(); .collect();

View file

@ -1,7 +1,6 @@
use super::*; use super::*;
use crate::core::film::{CreateFilmBase, PixelSensor}; use crate::core::film::{CreateFilmBase, PixelSensor};
use crate::utils::containers::Array2D; use crate::utils::containers::Array2D;
use std::sync::Arc;
use crate::Arena; use crate::Arena;
use anyhow::Result; use anyhow::Result;
use shared::core::camera::CameraTransform; use shared::core::camera::CameraTransform;

View file

@ -1,6 +1,5 @@
use crate::core::color::RGBToSpectrumTableData; use crate::core::color::RGBToSpectrumTableData;
use shared::core::color::RES; use shared::core::color::RES;
use bytemuck::cast_slice;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use shared::Float; use shared::Float;
use shared::PBRTOptions; use shared::PBRTOptions;

View file

@ -21,8 +21,8 @@ impl CreateShape for BilinearPatchShape {
parameters: ParameterDictionary, parameters: ParameterDictionary,
_float_textures: &HashMap<String, Arc<FloatTexture>>, _float_textures: &HashMap<String, Arc<FloatTexture>>,
_loc: FileLoc, _loc: FileLoc,
_arena: &Arena, arena: &Arena,
) -> Result<Vec<Shape>> { ) -> Result<Vec<Ptr<Shape>>> {
let mut vertex_indices = parameters.get_int_array("indices")?; let mut vertex_indices = parameters.get_int_array("indices")?;
let p = parameters.get_point3f_array("P")?; let p = parameters.get_point3f_array("P")?;
let mut uv = parameters.get_point2f_array("uv")?; 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 mesh_ptr = Ptr::from(&host_arc.device);
let mut shapes = Vec::with_capacity(n_patches as usize); let mut shapes = Vec::with_capacity(n_patches as usize);
for i in 0..n_patches as i32 { for i in 0..n_patches as i32 {
shapes.push(Shape::BilinearPatch(BilinearPatchShape { shapes.push(arena.alloc(Shape::BilinearPatch(BilinearPatchShape {
mesh: mesh_ptr, mesh: mesh_ptr,
blp_index: i, blp_index: i,
area: 0.0, area: 0.0,
rectangle: false, rectangle: false,
})); })));
} }
// arena.alloc(shapes);
Ok(shapes) Ok(shapes)
} }
} }

View file

@ -12,6 +12,7 @@ use shared::utils::math::lerp;
use shared::utils::splines::{ use shared::utils::splines::{
cubic_bspline_to_bezier, elevate_quadratic_bezier_to_cubic, quadratic_bspline_to_bezier, cubic_bspline_to_bezier, elevate_quadratic_bezier_to_cubic, quadratic_bspline_to_bezier,
}; };
use shared::Ptr;
use log::warn; use log::warn;
use std::collections::HashMap; use std::collections::HashMap;
@ -27,7 +28,8 @@ pub fn create_curve(
curve_type: CurveType, curve_type: CurveType,
seg_normals: &[Normal3f], seg_normals: &[Normal3f],
split_depth: usize, split_depth: usize,
) -> Vec<Shape> { arena: &Arena,
) -> Vec<Ptr<Shape>> {
let curve_common = CurveCommon::new( let curve_common = CurveCommon::new(
seg_cp_bezier, seg_cp_bezier,
w0, w0,
@ -39,7 +41,7 @@ pub fn create_curve(
reverse_orientation, reverse_orientation,
); );
let n_segments = 1 << split_depth; let n_segments = 1 << split_depth;
let mut segments: Vec<Shape> = Vec::with_capacity(n_segments); let mut segments: Vec<Ptr<Shape>> = Vec::with_capacity(n_segments);
for i in 0..n_segments { for i in 0..n_segments {
let u_min = i as Float / n_segments as Float; let u_min = i as Float / n_segments as Float;
@ -51,7 +53,7 @@ pub fn create_curve(
u_max, u_max,
}; };
segments.push(Shape::Curve(curve)); segments.push(arena.alloc(Shape::Curve(curve)));
} }
segments segments
} }
@ -64,8 +66,8 @@ impl CreateShape for CurveShape {
parameters: ParameterDictionary, parameters: ParameterDictionary,
_float_textures: &HashMap<String, Arc<FloatTexture>>, _float_textures: &HashMap<String, Arc<FloatTexture>>,
_loc: FileLoc, _loc: FileLoc,
_arena: &Arena, arena: &Arena,
) -> Result<Vec<Shape>> { ) -> Result<Vec<Ptr<Shape>>> {
let width = parameters.get_one_float("width", 1.0)?; let width = parameters.get_one_float("width", 1.0)?;
let width0 = parameters.get_one_float("width0", width)?; let width0 = parameters.get_one_float("width0", width)?;
let width1 = parameters.get_one_float("width1", width)?; let width1 = parameters.get_one_float("width1", width)?;
@ -150,7 +152,7 @@ impl CreateShape for CurveShape {
parameters.get_one_int("splitdepth", 3)? parameters.get_one_int("splitdepth", 3)?
}; };
let mut curves: Vec<Shape> = Vec::new(); let mut curves: Vec<Ptr<Shape>> = Vec::new();
let mut cp_offset = 0; let mut cp_offset = 0;
for seg in 0..n_segments { for seg in 0..n_segments {
@ -197,11 +199,11 @@ impl CreateShape for CurveShape {
curve_type, curve_type,
seg_normals.expect("Could not determine normals to curve segments"), seg_normals.expect("Could not determine normals to curve segments"),
split_depth.try_into().unwrap(), split_depth.try_into().unwrap(),
arena
); );
curves.extend(new_curves); curves.extend(new_curves);
} }
// arena.alloc(curves);
Ok(curves) Ok(curves)
} }
} }

View file

@ -7,6 +7,7 @@ use shared::shapes::CylinderShape;
use shared::utils::Transform; use shared::utils::Transform;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use shared::Ptr;
impl CreateShape for CylinderShape { impl CreateShape for CylinderShape {
fn create( fn create(
@ -17,7 +18,7 @@ impl CreateShape for CylinderShape {
_float_textures: &HashMap<String, Arc<FloatTexture>>, _float_textures: &HashMap<String, Arc<FloatTexture>>,
_loc: FileLoc, _loc: FileLoc,
arena: &Arena, arena: &Arena,
) -> Result<Vec<Shape>> { ) -> Result<Vec<Ptr<Shape>>> {
let radius = parameters.get_one_float("radius", 1.)?; let radius = parameters.get_one_float("radius", 1.)?;
let z_min = parameters.get_one_float("zmin", -1.)?; let z_min = parameters.get_one_float("zmin", -1.)?;
let z_max = parameters.get_one_float("zmax", 1.)?; let z_max = parameters.get_one_float("zmax", 1.)?;
@ -32,7 +33,6 @@ impl CreateShape for CylinderShape {
phi_max, phi_max,
); );
arena.alloc(Shape::Cylinder(shape)); Ok(vec![arena.alloc(Shape::Cylinder(shape))])
Ok(vec![Shape::Cylinder(shape)])
} }
} }

View file

@ -7,6 +7,7 @@ use shared::shapes::DiskShape;
use shared::utils::Transform; use shared::utils::Transform;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use shared::Ptr;
impl CreateShape for DiskShape { impl CreateShape for DiskShape {
fn create( fn create(
@ -17,7 +18,7 @@ impl CreateShape for DiskShape {
_float_textures: &HashMap<String, Arc<FloatTexture>>, _float_textures: &HashMap<String, Arc<FloatTexture>>,
_loc: FileLoc, _loc: FileLoc,
arena: &Arena, arena: &Arena,
) -> Result<Vec<Shape>> { ) -> Result<Vec<Ptr<Shape>>> {
let height = parameters.get_one_float("height", 0.)?; let height = parameters.get_one_float("height", 0.)?;
let radius = parameters.get_one_float("radius", 1.)?; let radius = parameters.get_one_float("radius", 1.)?;
let inner_radius = parameters.get_one_float("innerradius", 0.)?; let inner_radius = parameters.get_one_float("innerradius", 0.)?;
@ -32,7 +33,6 @@ impl CreateShape for DiskShape {
reverse_orientation, reverse_orientation,
); );
arena.alloc(Shape::Disk(shape)); Ok(vec![arena.alloc(Shape::Disk(shape))])
Ok(vec![Shape::Disk(shape)])
} }
} }

View file

@ -7,6 +7,7 @@ use shared::shapes::SphereShape;
use shared::utils::Transform; use shared::utils::Transform;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use shared::Ptr;
impl CreateShape for SphereShape { impl CreateShape for SphereShape {
fn create( fn create(
@ -17,7 +18,7 @@ impl CreateShape for SphereShape {
_float_textures: &HashMap<String, Arc<FloatTexture>>, _float_textures: &HashMap<String, Arc<FloatTexture>>,
_loc: FileLoc, _loc: FileLoc,
arena: &Arena, arena: &Arena,
) -> Result<Vec<Shape>> { ) -> Result<Vec<Ptr<Shape>>> {
let radius = parameters.get_one_float("radius", 1.)?; let radius = parameters.get_one_float("radius", 1.)?;
let zmin = parameters.get_one_float("zmin", -radius)?; let zmin = parameters.get_one_float("zmin", -radius)?;
let zmax = parameters.get_one_float("zmax", radius)?; let zmax = parameters.get_one_float("zmax", radius)?;
@ -31,7 +32,6 @@ impl CreateShape for SphereShape {
zmax, zmax,
phimax, phimax,
); );
arena.alloc(vec![Shape::Sphere(shape)]); Ok(vec![arena.alloc(Shape::Sphere(shape))])
Ok(vec![Shape::Sphere(shape)])
} }
} }

View file

@ -18,8 +18,8 @@ impl CreateShape for TriangleShape {
parameters: ParameterDictionary, parameters: ParameterDictionary,
_float_texture: &HashMap<String, Arc<FloatTexture>>, _float_texture: &HashMap<String, Arc<FloatTexture>>,
_loc: FileLoc, _loc: FileLoc,
_arena: &Arena, arena: &Arena,
) -> Result<Vec<Shape>> { ) -> Result<Vec<Ptr<Shape>>> {
let mut vertex_indices = parameters.get_int_array("indices")?; let mut vertex_indices = parameters.get_int_array("indices")?;
let p = parameters.get_point3f_array("P")?; let p = parameters.get_point3f_array("P")?;
let mut uvs = parameters.get_point2f_array("uv")?; 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 mesh_ptr = Ptr::from(&host_arc.device);
let mut shapes = Vec::with_capacity(n_patches as usize); let mut shapes = Vec::with_capacity(n_patches as usize);
for i in 0..n_patches { for i in 0..n_patches {
shapes.push(Shape::Triangle(TriangleShape { shapes.push(arena.alloc(Shape::Triangle(TriangleShape {
mesh: mesh_ptr, mesh: mesh_ptr,
tri_index: i as i32, tri_index: i as i32,
})); })));
} }
// arena.alloc(shapes);
Ok(shapes) Ok(shapes)
} }
} }