From e244664b322ab328cac7d785b11d7742a8f764cf Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Sun, 7 Aug 2022 11:05:34 -0700 Subject: [PATCH] Move shader bindings to objects rather than instances. --- psychoblend/objects.py | 43 +++++------------------------------ psychoblend/psy_export.py | 4 ++-- src/light/rectangle_light.rs | 2 +- src/light/sphere_light.rs | 2 +- src/parse/psy_assembly.rs | 25 +++++--------------- src/parse/psy_mesh_surface.rs | 19 +++++++++++++++- src/scene/assembly.rs | 22 ++---------------- src/surface/mod.rs | 2 +- src/surface/triangle_mesh.rs | 18 +++++++++++++-- src/tracer.rs | 19 ++++------------ 10 files changed, 57 insertions(+), 99 deletions(-) diff --git a/psychoblend/objects.py b/psychoblend/objects.py index b503a78..1e08f98 100644 --- a/psychoblend/objects.py +++ b/psychoblend/objects.py @@ -40,16 +40,16 @@ class Mesh: if self.is_subdiv == False: # Exporting normal mesh - w.write("MeshSurface $%s {\n" % self.name) + w.write("MeshSurface $%s {\n" % escape_name(self.name)) w.indent() else: # Exporting subdivision surface cage - w.write("SubdivisionSurface $%s {\n" % self.name) + w.write("SubdivisionSurface $%s {\n" % escape_name(self.name)) w.indent() # Material bindings. if self.material_name != None: - w.write("SurfaceShaderBind [${}]\n".format(self.material_name)) + w.write("SurfaceShaderBind [${}]\n".format(escape_name(self.material_name))) # Write vertices and (if it's smooth shaded) normals for ti in range(len(self.time_meshes)): @@ -102,7 +102,7 @@ class SphereLamp: def export(self, render_engine, w): render_engine.update_stats("", "Psychopath: Exporting %s" % self.name) - w.write("SphereLight $%s {\n" % self.name) + w.write("SphereLight $%s {\n" % escape_name(self.name)) w.indent() for col in self.time_col: if col[0] == 'Rec709': @@ -147,7 +147,7 @@ class RectLamp: def export(self, render_engine, w): render_engine.update_stats("", "Psychopath: Exporting %s" % self.name) - w.write("RectangleLight $%s {\n" % self.name) + w.write("RectangleLight $%s {\n" % escape_name(self.name)) w.indent() for col in self.time_col: if col[0] == 'Rec709': @@ -187,7 +187,7 @@ class DistantDiskLamp: pass def export(self, render_engine, w): - render_engine.update_stats("", "Psychopath: Exporting %s" % self.name) + render_engine.update_stats("", "Psychopath: Exporting %s" % escape_name(self.name)) w.write("DistantDiskLight $%s {\n" % self.name) w.indent() for direc in self.time_dir: @@ -204,34 +204,3 @@ class DistantDiskLamp: w.unindent() w.write("}\n") - - -# class Instance: -# def __init__(self, render_engine, depsgraph, ob, data_name): -# self.data_name = data_name -# self.needs_mb = needs_xform_mb(self.ob) -# self.time_xforms = [] - -# def take_sample(self, render_engine, time, translation_offset): -# if len(self.time_xforms) == 0 or self.needs_mb: -# render_engine.update_stats("", "Psychopath: Collecting '{}' xforms at time {}".format(self.ob.name, time)) -# mat = self.ob.matrix_world.copy() -# mat[0][3] += translation_offset[0] -# mat[1][3] += translation_offset[1] -# mat[2][3] += translation_offset[2] -# self.time_xforms += [mat] - -# def export(self, render_engine, w): -# render_engine.update_stats("", "Psychopath: Exporting %s" % self.ob.name) - -# w.write("Instance {\n") -# w.indent() -# w.write("Data [$%s]\n" % self.data_name) -# for mat in self.time_xforms: -# w.write("Transform [%s]\n" % mat2str(mat)) -# for ms in self.ob.material_slots: -# if ms != None: -# w.write("SurfaceShaderBind [$%s]\n" % escape_name(ms.material.name)) -# break -# w.unindent() -# w.write("}\n") diff --git a/psychoblend/psy_export.py b/psychoblend/psy_export.py index df888a3..71815be 100644 --- a/psychoblend/psy_export.py +++ b/psychoblend/psy_export.py @@ -240,11 +240,11 @@ class PsychoExporter: self.render_engine.update_stats("", "Psychopath: Exporting %s instance" % obj_name) prefix = str(hex(hash(id))) - name = "inst_{}__{}".format(prefix, obj_name) + name = "inst_{}__{}".format(prefix, escape_name(obj_name)) self.w.write("Instance {\n") self.w.indent() - self.w.write("Data [${}]\n".format(obj_name)) + self.w.write("Data [${}]\n".format(escape_name(obj_name))) for mat in xforms: self.w.write("Transform [{}]\n".format(mat2str(mat))) self.w.unindent() diff --git a/src/light/rectangle_light.rs b/src/light/rectangle_light.rs index ae31f6c..2618ae8 100644 --- a/src/light/rectangle_light.rs +++ b/src/light/rectangle_light.rs @@ -257,7 +257,7 @@ impl<'a> Surface for RectangleLight<'a> { _local_ray: &LocalRay, space: &XformFull, isect: &mut SurfaceIntersection, - _shader: &dyn SurfaceShader, + _shaders: &[&dyn SurfaceShader], ) { let time = ray.time; diff --git a/src/light/sphere_light.rs b/src/light/sphere_light.rs index 4763a56..b94a424 100644 --- a/src/light/sphere_light.rs +++ b/src/light/sphere_light.rs @@ -207,7 +207,7 @@ impl<'a> Surface for SphereLight<'a> { local_ray: &LocalRay, space: &XformFull, isect: &mut SurfaceIntersection, - _shader: &dyn SurfaceShader, + _shaders: &[&dyn SurfaceShader], ) { let time = ray.time; diff --git a/src/parse/psy_assembly.rs b/src/parse/psy_assembly.rs index 9083c5b..f1edf25 100644 --- a/src/parse/psy_assembly.rs +++ b/src/parse/psy_assembly.rs @@ -50,23 +50,6 @@ pub fn parse_assembly<'a>( child.iter_leaf_children_with_type("Data").nth(0).unwrap().1 }; - // Get surface shader binding, if any. - let surface_shader_name = if child - .iter_leaf_children_with_type("SurfaceShaderBind") - .count() - > 0 - { - Some( - child - .iter_leaf_children_with_type("SurfaceShaderBind") - .nth(0) - .unwrap() - .1, - ) - } else { - None - }; - // Get xforms let mut xforms = Vec::new(); for (_, contents, _) in child.iter_leaf_children_with_type("Transform") { @@ -75,7 +58,7 @@ pub fn parse_assembly<'a>( // Add instance if builder.name_exists(name) { - builder.add_instance(name, surface_shader_name, Some(&xforms)); + builder.add_instance(name, Some(&xforms)); } else { return Err(PsyParseError::InstancedMissingData( child.iter_leaf_children_with_type("Data").nth(0).unwrap().2, @@ -113,7 +96,11 @@ pub fn parse_assembly<'a>( { builder.add_object( ident, - Object::Surface(arena.alloc(parse_mesh_surface(arena, child)?)), + Object::Surface(arena.alloc(parse_mesh_surface( + arena, + child, + &builder.surface_shader_map, + )?)), ); } else { // TODO: error condition of some kind, because no ident diff --git a/src/parse/psy_mesh_surface.rs b/src/parse/psy_mesh_surface.rs index c435ca1..d794976 100644 --- a/src/parse/psy_mesh_surface.rs +++ b/src/parse/psy_mesh_surface.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] -use std::result::Result; +use std::{collections::HashMap, result::Result}; use nom::{sequence::tuple, IResult}; @@ -27,7 +27,9 @@ use super::{ pub fn parse_mesh_surface<'a>( arena: &'a Arena, tree: &'a DataTree, + surface_shader_map: &HashMap, ) -> Result, PsyParseError> { + let mut shader_idx = None; let mut verts = Vec::new(); // Vec of vecs, one for each time sample let mut normals = Vec::new(); // Vec of vecs, on for each time sample let mut face_vert_counts = Vec::new(); @@ -36,6 +38,20 @@ pub fn parse_mesh_surface<'a>( // TODO: make sure there are the right number of various children, // and other validation. + // Get surface shader binding, if any. + if tree + .iter_leaf_children_with_type("SurfaceShaderBind") + .count() + > 0 + { + let name = tree + .iter_leaf_children_with_type("SurfaceShaderBind") + .nth(0) + .unwrap() + .1; + shader_idx = surface_shader_map.get(name).map(|i| *i); + } + // Get verts for (_, mut text, _) in tree.iter_leaf_children_with_type("Vertices") { // Collect verts for this time sample @@ -116,6 +132,7 @@ pub fn parse_mesh_surface<'a>( Ok(TriangleMesh::from_verts_and_indices( arena, + shader_idx, &verts, &if normals.is_empty() { None diff --git a/src/scene/assembly.rs b/src/scene/assembly.rs index 9a0470b..54a3752 100644 --- a/src/scene/assembly.rs +++ b/src/scene/assembly.rs @@ -142,7 +142,7 @@ pub struct AssemblyBuilder<'a> { // Shader list surface_shaders: Vec<&'a dyn SurfaceShader>, - surface_shader_map: HashMap, // map Name -> Index + pub surface_shader_map: HashMap, // map Name -> Index // Object list objects: Vec>, @@ -206,12 +206,7 @@ impl<'a> AssemblyBuilder<'a> { self.assemblies.push(asmb); } - pub fn add_instance( - &mut self, - name: &str, - surface_shader_name: Option<&str>, - xforms: Option<&[Xform]>, - ) { + pub fn add_instance(&mut self, name: &str, xforms: Option<&[Xform]>) { // Make sure name exists if !self.name_exists(name) { panic!("Attempted to add instance with a name that doesn't exist."); @@ -233,12 +228,6 @@ impl<'a> AssemblyBuilder<'a> { Instance { instance_type: InstanceType::Object, data_index: self.object_map[name], - surface_shader_index: surface_shader_name.map(|name| { - *self - .surface_shader_map - .get(name) - .unwrap_or_else(|| panic!("Unknown surface shader '{}'.", name)) - }), id: self.instances.len(), transform_indices: xforms .map(|xf| (self.xforms.len(), self.xforms.len() + xf.len())), @@ -247,12 +236,6 @@ impl<'a> AssemblyBuilder<'a> { Instance { instance_type: InstanceType::Assembly, data_index: self.assembly_map[name], - surface_shader_index: surface_shader_name.map(|name| { - *self - .surface_shader_map - .get(name) - .unwrap_or_else(|| panic!("Unknown surface shader '{}'.", name)) - }), id: self.instances.len(), transform_indices: xforms .map(|xf| (self.xforms.len(), self.xforms.len() + xf.len())), @@ -391,7 +374,6 @@ pub enum Object<'a> { pub struct Instance { pub instance_type: InstanceType, pub data_index: usize, - pub surface_shader_index: Option, pub id: usize, pub transform_indices: Option<(usize, usize)>, } diff --git a/src/surface/mod.rs b/src/surface/mod.rs index 546238a..7372a06 100644 --- a/src/surface/mod.rs +++ b/src/surface/mod.rs @@ -24,7 +24,7 @@ pub trait Surface: Boundable + Debug + Sync { local_ray: &LocalRay, space: &XformFull, isect: &mut SurfaceIntersection, - shader: &dyn SurfaceShader, + shaders: &[&dyn SurfaceShader], ); } diff --git a/src/surface/triangle_mesh.rs b/src/surface/triangle_mesh.rs index 1faaa02..2ef2804 100644 --- a/src/surface/triangle_mesh.rs +++ b/src/surface/triangle_mesh.rs @@ -6,10 +6,11 @@ use crate::{ accel::BVH4, bbox::BBox, boundable::Boundable, + color::Color, lerp::lerp_slice, math::{cross, dot, Normal, Point, XformFull}, ray::{LocalRay, Ray}, - shading::SurfaceShader, + shading::{SimpleSurfaceShader, SurfaceShader}, }; use super::{triangle, Surface, SurfaceIntersection, SurfaceIntersectionData}; @@ -18,6 +19,7 @@ const MAX_LEAF_TRIANGLE_COUNT: usize = 3; #[derive(Copy, Clone, Debug)] pub struct TriangleMesh<'a> { + pub shader_idx: Option, time_sample_count: usize, vertices: &'a [Point], // Vertices, with the time samples for each vertex stored contiguously normals: Option<&'a [Normal]>, // Vertex normals, organized the same as `vertices` @@ -28,6 +30,7 @@ pub struct TriangleMesh<'a> { impl<'a> TriangleMesh<'a> { pub fn from_verts_and_indices<'b>( arena: &'b Arena, + shader_idx: Option, verts: &[Vec], vert_normals: &Option>>, tri_indices: &[(usize, usize, usize)], @@ -106,6 +109,7 @@ impl<'a> TriangleMesh<'a> { }); TriangleMesh { + shader_idx: shader_idx, time_sample_count: time_sample_count, vertices: vertices, normals: normals, @@ -128,8 +132,18 @@ impl<'a> Surface for TriangleMesh<'a> { local_ray: &LocalRay, space: &XformFull, isect: &mut SurfaceIntersection, - shader: &dyn SurfaceShader, + shaders: &[&dyn SurfaceShader], ) { + let unassigned_shader = SimpleSurfaceShader::Emit { + color: Color::new_xyz(color::rec709_to_xyz((1.0, 0.0, 1.0))), + }; + + let shader = if let Some(idx) = self.shader_idx { + shaders[idx] + } else { + &unassigned_shader + }; + self.accel.traverse(ray, local_ray, |idx_range, ray| { // Iterate through the triangles and test the ray against them. let mut non_shadow_hit = false; diff --git a/src/tracer.rs b/src/tracer.rs index a453f4a..c00d929 100644 --- a/src/tracer.rs +++ b/src/tracer.rs @@ -73,12 +73,11 @@ impl<'a> Tracer<'a> { InstanceType::Object => { self.trace_object( &assembly.objects[inst.data_index], - inst.surface_shader_index - .map(|i| assembly.surface_shaders[i]), ray, &local_ray, &local_space, isect, + assembly.surface_shaders, ); } @@ -103,29 +102,19 @@ impl<'a> Tracer<'a> { fn trace_object<'b>( &mut self, obj: &Object, - surface_shader: Option<&dyn SurfaceShader>, ray: &mut Ray, local_ray: &LocalRay, space: &XformFull, isect: &mut SurfaceIntersection, + shaders: &[&dyn SurfaceShader], ) { match *obj { Object::Surface(surface) => { - let unassigned_shader = SimpleSurfaceShader::Emit { - color: Color::new_xyz(color::rec709_to_xyz((1.0, 0.0, 1.0))), - }; - let shader = surface_shader.unwrap_or(&unassigned_shader); - - surface.intersect_ray(ray, local_ray, space, isect, shader); + surface.intersect_ray(ray, local_ray, space, isect, shaders); } Object::SurfaceLight(surface) => { - // Lights don't use shaders - let bogus_shader = SimpleSurfaceShader::Emit { - color: Color::new_xyz(color::rec709_to_xyz((1.0, 0.0, 1.0))), - }; - - surface.intersect_ray(ray, local_ray, space, isect, &bogus_shader); + surface.intersect_ray(ray, local_ray, space, isect, shaders); } } }