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::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)]

View file

@ -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;

View file

@ -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<Vec<Shape>> {
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<ShapeWithContext> {
// 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<Shape>> {
) -> Vec<Ptr<Shape>> {
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<Vec<Shape>>,
loaded: Vec<ShapeWithContext>,
lookup: &SceneLookup,
) -> Vec<Primitive> {
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<Vec<Shape>>,
_loaded: Vec<Ptr<Shape>>,
_lookup: &SceneLookup,
) -> Vec<Primitive> {
// 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_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 {
fn create(
render_from_object: Transform,
@ -22,7 +29,7 @@ pub trait CreateShape {
float_textures: &HashMap<String, Arc<FloatTexture>>,
loc: FileLoc,
arena: &Arena,
) -> Result<Vec<Shape>>;
) -> Result<Vec<Ptr<Shape>>>;
}
pub trait ShapeFactory {
@ -35,7 +42,7 @@ pub trait ShapeFactory {
float_textures: &HashMap<String, Arc<FloatTexture>>,
loc: FileLoc,
arena: &Arena,
) -> Result<Vec<Shape>>;
) -> Result<Vec<Ptr<Shape>>>;
}
impl ShapeFactory for Shape {
@ -48,7 +55,7 @@ impl ShapeFactory for Shape {
float_textures: &HashMap<String, Arc<FloatTexture>>,
loc: FileLoc,
arena: &Arena,
) -> Result<Vec<Shape>> {
) -> Result<Vec<Ptr<Shape>>> {
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<Shape> = (0..n_tris)
let shapes: Vec<Ptr<Shape>> = (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();

View file

@ -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;

View file

@ -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;

View file

@ -21,8 +21,8 @@ impl CreateShape for BilinearPatchShape {
parameters: ParameterDictionary,
_float_textures: &HashMap<String, Arc<FloatTexture>>,
_loc: FileLoc,
_arena: &Arena,
) -> Result<Vec<Shape>> {
arena: &Arena,
) -> Result<Vec<Ptr<Shape>>> {
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)
}
}

View file

@ -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<Shape> {
arena: &Arena,
) -> Vec<Ptr<Shape>> {
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<Shape> = Vec::with_capacity(n_segments);
let mut segments: Vec<Ptr<Shape>> = 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<String, Arc<FloatTexture>>,
_loc: FileLoc,
_arena: &Arena,
) -> Result<Vec<Shape>> {
arena: &Arena,
) -> Result<Vec<Ptr<Shape>>> {
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<Shape> = Vec::new();
let mut curves: Vec<Ptr<Shape>> = 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)
}
}

View file

@ -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<String, Arc<FloatTexture>>,
_loc: FileLoc,
arena: &Arena,
) -> Result<Vec<Shape>> {
) -> Result<Vec<Ptr<Shape>>> {
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))])
}
}

View file

@ -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<String, Arc<FloatTexture>>,
_loc: FileLoc,
arena: &Arena,
) -> Result<Vec<Shape>> {
) -> Result<Vec<Ptr<Shape>>> {
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))])
}
}

View file

@ -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<String, Arc<FloatTexture>>,
_loc: FileLoc,
arena: &Arena,
) -> Result<Vec<Shape>> {
) -> Result<Vec<Ptr<Shape>>> {
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))])
}
}

View file

@ -18,8 +18,8 @@ impl CreateShape for TriangleShape {
parameters: ParameterDictionary,
_float_texture: &HashMap<String, Arc<FloatTexture>>,
_loc: FileLoc,
_arena: &Arena,
) -> Result<Vec<Shape>> {
arena: &Arena,
) -> Result<Vec<Ptr<Shape>>> {
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)
}
}