Compare commits
No commits in common. "e244664b322ab328cac7d785b11d7742a8f764cf" and "d132e6a015d39bc250a8f96d16f5574590358ae1" have entirely different histories.
e244664b32
...
d132e6a015
|
@ -1,7 +1,6 @@
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
from .util import escape_name, mat2str, needs_def_mb, needs_xform_mb, ExportCancelled
|
from .util import escape_name, mat2str, needs_def_mb, needs_xform_mb, ExportCancelled
|
||||||
from mathutils import Vector, Matrix
|
|
||||||
|
|
||||||
def make_object_data_cache(render_engine, depsgraph, ob, name):
|
def make_object_data_cache(render_engine, depsgraph, ob, name):
|
||||||
if ob.type == 'MESH':
|
if ob.type == 'MESH':
|
||||||
|
@ -19,9 +18,6 @@ class Mesh:
|
||||||
"""
|
"""
|
||||||
def __init__(self, render_engine, depsgraph, ob, name):
|
def __init__(self, render_engine, depsgraph, ob, name):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.material_name = None
|
|
||||||
if len(ob.material_slots) >= 1 and ob.material_slots[0].material != None:
|
|
||||||
self.material_name = ob.material_slots[0].material.name
|
|
||||||
self.is_subdiv = ob.data.psychopath.is_subdivision_surface
|
self.is_subdiv = ob.data.psychopath.is_subdivision_surface
|
||||||
self.needs_mb = needs_def_mb(ob)
|
self.needs_mb = needs_def_mb(ob)
|
||||||
self.time_meshes = []
|
self.time_meshes = []
|
||||||
|
@ -40,17 +36,13 @@ class Mesh:
|
||||||
|
|
||||||
if self.is_subdiv == False:
|
if self.is_subdiv == False:
|
||||||
# Exporting normal mesh
|
# Exporting normal mesh
|
||||||
w.write("MeshSurface $%s {\n" % escape_name(self.name))
|
w.write("MeshSurface $%s {\n" % self.name)
|
||||||
w.indent()
|
w.indent()
|
||||||
else:
|
else:
|
||||||
# Exporting subdivision surface cage
|
# Exporting subdivision surface cage
|
||||||
w.write("SubdivisionSurface $%s {\n" % escape_name(self.name))
|
w.write("SubdivisionSurface $%s {\n" % self.name)
|
||||||
w.indent()
|
w.indent()
|
||||||
|
|
||||||
# Material bindings.
|
|
||||||
if self.material_name != None:
|
|
||||||
w.write("SurfaceShaderBind [${}]\n".format(escape_name(self.material_name)))
|
|
||||||
|
|
||||||
# Write vertices and (if it's smooth shaded) normals
|
# Write vertices and (if it's smooth shaded) normals
|
||||||
for ti in range(len(self.time_meshes)):
|
for ti in range(len(self.time_meshes)):
|
||||||
w.write("Vertices [")
|
w.write("Vertices [")
|
||||||
|
@ -102,7 +94,7 @@ class SphereLamp:
|
||||||
def export(self, render_engine, w):
|
def export(self, render_engine, w):
|
||||||
render_engine.update_stats("", "Psychopath: Exporting %s" % self.name)
|
render_engine.update_stats("", "Psychopath: Exporting %s" % self.name)
|
||||||
|
|
||||||
w.write("SphereLight $%s {\n" % escape_name(self.name))
|
w.write("SphereLight $%s {\n" % self.name)
|
||||||
w.indent()
|
w.indent()
|
||||||
for col in self.time_col:
|
for col in self.time_col:
|
||||||
if col[0] == 'Rec709':
|
if col[0] == 'Rec709':
|
||||||
|
@ -140,14 +132,14 @@ class RectLamp:
|
||||||
self.time_dim += [(ob.data.size, ob.data.size_y)]
|
self.time_dim += [(ob.data.size, ob.data.size_y)]
|
||||||
else:
|
else:
|
||||||
self.time_dim += [(ob.data.size, ob.data.size)]
|
self.time_dim += [(ob.data.size, ob.data.size)]
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def export(self, render_engine, w):
|
def export(self, render_engine, w):
|
||||||
render_engine.update_stats("", "Psychopath: Exporting %s" % self.name)
|
render_engine.update_stats("", "Psychopath: Exporting %s" % self.ob.name)
|
||||||
|
|
||||||
w.write("RectangleLight $%s {\n" % escape_name(self.name))
|
w.write("RectangleLight $%s {\n" % self.name)
|
||||||
w.indent()
|
w.indent()
|
||||||
for col in self.time_col:
|
for col in self.time_col:
|
||||||
if col[0] == 'Rec709':
|
if col[0] == 'Rec709':
|
||||||
|
@ -183,11 +175,8 @@ class DistantDiskLamp:
|
||||||
|
|
||||||
self.time_rad += [ob.data.shadow_soft_size]
|
self.time_rad += [ob.data.shadow_soft_size]
|
||||||
|
|
||||||
def cleanup(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def export(self, render_engine, w):
|
def export(self, render_engine, w):
|
||||||
render_engine.update_stats("", "Psychopath: Exporting %s" % escape_name(self.name))
|
render_engine.update_stats("", "Psychopath: Exporting %s" % self.ob.name)
|
||||||
w.write("DistantDiskLight $%s {\n" % self.name)
|
w.write("DistantDiskLight $%s {\n" % self.name)
|
||||||
w.indent()
|
w.indent()
|
||||||
for direc in self.time_dir:
|
for direc in self.time_dir:
|
||||||
|
@ -204,3 +193,35 @@ class DistantDiskLamp:
|
||||||
|
|
||||||
w.unindent()
|
w.unindent()
|
||||||
w.write("}\n")
|
w.write("}\n")
|
||||||
|
|
||||||
|
|
||||||
|
# class Instance:
|
||||||
|
# def __init__(self, render_engine, depsgraph, ob, data_name):
|
||||||
|
# self.ob = ob
|
||||||
|
# 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")
|
||||||
|
|
|
@ -2,7 +2,6 @@ import bpy
|
||||||
|
|
||||||
from math import log
|
from math import log
|
||||||
|
|
||||||
from .material import Material
|
|
||||||
from .objects import make_object_data_cache, Mesh, DistantDiskLamp
|
from .objects import make_object_data_cache, Mesh, DistantDiskLamp
|
||||||
from .util import escape_name, mat2str, ExportCancelled
|
from .util import escape_name, mat2str, ExportCancelled
|
||||||
from .world import World, Camera
|
from .world import World, Camera
|
||||||
|
@ -54,9 +53,6 @@ class PsychoExporter:
|
||||||
self.sun_lamp_data = {} # name -> cached_data
|
self.sun_lamp_data = {} # name -> cached_data
|
||||||
self.sun_lamp_instances = {} # instance_id -> [sun_lamp_data_name, transform_list]
|
self.sun_lamp_instances = {} # instance_id -> [sun_lamp_data_name, transform_list]
|
||||||
|
|
||||||
# For all materials.
|
|
||||||
self.materials = {} # name -> cached_data
|
|
||||||
|
|
||||||
# Motion blur segments are rounded down to a power of two.
|
# Motion blur segments are rounded down to a power of two.
|
||||||
if self.scene.psychopath.motion_blur_segments > 0:
|
if self.scene.psychopath.motion_blur_segments > 0:
|
||||||
self.time_samples = (2**int(log(self.scene.psychopath.motion_blur_segments, 2))) + 1
|
self.time_samples = (2**int(log(self.scene.psychopath.motion_blur_segments, 2))) + 1
|
||||||
|
@ -128,21 +124,6 @@ class PsychoExporter:
|
||||||
self.w.unindent()
|
self.w.unindent()
|
||||||
self.w.write("}\n")
|
self.w.write("}\n")
|
||||||
|
|
||||||
#------------------------------------------------------
|
|
||||||
# Collect materials.
|
|
||||||
|
|
||||||
# TODO: handle situations where there are more than one
|
|
||||||
# material with the same name. This can happen through
|
|
||||||
# library linking.
|
|
||||||
|
|
||||||
for inst in self.depsgraph.object_instances:
|
|
||||||
ob = inst.object
|
|
||||||
if ob.type in ['MESH']:
|
|
||||||
for ms in ob.material_slots:
|
|
||||||
if ms.material != None:
|
|
||||||
if ms.material.name not in self.materials:
|
|
||||||
self.materials[ms.material.name] = Material(self.render_engine, self.depsgraph, ms.material)
|
|
||||||
|
|
||||||
#------------------------------------------------------
|
#------------------------------------------------------
|
||||||
# Collect world and object data.
|
# Collect world and object data.
|
||||||
|
|
||||||
|
@ -152,10 +133,7 @@ class PsychoExporter:
|
||||||
if self.render_engine.test_break():
|
if self.render_engine.test_break():
|
||||||
raise ExportCancelled()
|
raise ExportCancelled()
|
||||||
|
|
||||||
subframe = self.shutter_start + (self.shutter_diff*i)
|
time = self.fr + self.shutter_start + (self.shutter_diff*i)
|
||||||
time = self.fr + subframe
|
|
||||||
self.depsgraph.scene.frame_set(self.fr, subframe=subframe)
|
|
||||||
self.depsgraph.update()
|
|
||||||
|
|
||||||
# Collect camera and world data.
|
# Collect camera and world data.
|
||||||
self.camera.take_sample(self.render_engine, self.depsgraph, time)
|
self.camera.take_sample(self.render_engine, self.depsgraph, time)
|
||||||
|
@ -174,22 +152,13 @@ class PsychoExporter:
|
||||||
# We use this a couple of times, so make a shorthand.
|
# We use this a couple of times, so make a shorthand.
|
||||||
is_sun_lamp = inst.object.type == 'LIGHT' and inst.object.data.type == 'SUN'
|
is_sun_lamp = inst.object.type == 'LIGHT' and inst.object.data.type == 'SUN'
|
||||||
|
|
||||||
# TODO: handle situations where there are more than one
|
|
||||||
# object with the same name. This can happen through
|
|
||||||
# library linking.
|
|
||||||
|
|
||||||
# Get a unique id for the instance. This is surprisingly
|
# Get a unique id for the instance. This is surprisingly
|
||||||
# tricky, because the instance's "persistent_id" property
|
# tricky, because the instance's "persistent_id" property
|
||||||
# isn't globally unique, as I would have expected from
|
# isn't globally unique, as I would have expected from
|
||||||
# the documentation.
|
# the documentation.
|
||||||
id = None
|
id = None
|
||||||
if inst.is_instance:
|
if inst.is_instance:
|
||||||
id = (
|
id = (hash((inst.object.name, inst.parent.name)), inst.persistent_id)
|
||||||
hash((inst.object.name, inst.parent.name)),
|
|
||||||
# Has to be turned into a tuple, otherwise it doesn't
|
|
||||||
# work as part of the ID for some reason.
|
|
||||||
tuple(inst.persistent_id),
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
id = inst.object.name
|
id = inst.object.name
|
||||||
|
|
||||||
|
@ -226,30 +195,6 @@ class PsychoExporter:
|
||||||
self.w.write("Assembly {\n")
|
self.w.write("Assembly {\n")
|
||||||
self.w.indent()
|
self.w.indent()
|
||||||
|
|
||||||
# Export materials.
|
|
||||||
for name in self.materials:
|
|
||||||
self.materials[name].export(self.render_engine, self.w)
|
|
||||||
|
|
||||||
# Export objects.
|
|
||||||
for name in self.object_data:
|
|
||||||
self.object_data[name].export(self.render_engine, self.w)
|
|
||||||
|
|
||||||
# Export instances.
|
|
||||||
for id in self.instances:
|
|
||||||
[obj_name, xforms] = self.instances[id]
|
|
||||||
self.render_engine.update_stats("", "Psychopath: Exporting %s instance" % obj_name)
|
|
||||||
|
|
||||||
prefix = str(hex(hash(id)))
|
|
||||||
name = "inst_{}__{}".format(prefix, escape_name(obj_name))
|
|
||||||
|
|
||||||
self.w.write("Instance {\n")
|
|
||||||
self.w.indent()
|
|
||||||
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()
|
|
||||||
self.w.write("}\n")
|
|
||||||
|
|
||||||
self.w.unindent()
|
self.w.unindent()
|
||||||
self.w.write("}\n")
|
self.w.write("}\n")
|
||||||
finally:
|
finally:
|
||||||
|
|
|
@ -65,7 +65,7 @@ class Camera:
|
||||||
mat = self.ob.matrix_world.copy()
|
mat = self.ob.matrix_world.copy()
|
||||||
matz = Matrix()
|
matz = Matrix()
|
||||||
matz[2][2] = -1
|
matz[2][2] = -1
|
||||||
self.xforms += [(mat @ matz).inverted()]
|
self.xforms += [(mat * matz).inverted()]
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -257,7 +257,7 @@ impl<'a> Surface for RectangleLight<'a> {
|
||||||
_local_ray: &LocalRay,
|
_local_ray: &LocalRay,
|
||||||
space: &XformFull,
|
space: &XformFull,
|
||||||
isect: &mut SurfaceIntersection,
|
isect: &mut SurfaceIntersection,
|
||||||
_shaders: &[&dyn SurfaceShader],
|
_shader: &dyn SurfaceShader,
|
||||||
) {
|
) {
|
||||||
let time = ray.time;
|
let time = ray.time;
|
||||||
|
|
||||||
|
|
|
@ -207,7 +207,7 @@ impl<'a> Surface for SphereLight<'a> {
|
||||||
local_ray: &LocalRay,
|
local_ray: &LocalRay,
|
||||||
space: &XformFull,
|
space: &XformFull,
|
||||||
isect: &mut SurfaceIntersection,
|
isect: &mut SurfaceIntersection,
|
||||||
_shaders: &[&dyn SurfaceShader],
|
_shader: &dyn SurfaceShader,
|
||||||
) {
|
) {
|
||||||
let time = ray.time;
|
let time = ray.time;
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,23 @@ pub fn parse_assembly<'a>(
|
||||||
child.iter_leaf_children_with_type("Data").nth(0).unwrap().1
|
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
|
// Get xforms
|
||||||
let mut xforms = Vec::new();
|
let mut xforms = Vec::new();
|
||||||
for (_, contents, _) in child.iter_leaf_children_with_type("Transform") {
|
for (_, contents, _) in child.iter_leaf_children_with_type("Transform") {
|
||||||
|
@ -58,7 +75,7 @@ pub fn parse_assembly<'a>(
|
||||||
|
|
||||||
// Add instance
|
// Add instance
|
||||||
if builder.name_exists(name) {
|
if builder.name_exists(name) {
|
||||||
builder.add_instance(name, Some(&xforms));
|
builder.add_instance(name, surface_shader_name, Some(&xforms));
|
||||||
} else {
|
} else {
|
||||||
return Err(PsyParseError::InstancedMissingData(
|
return Err(PsyParseError::InstancedMissingData(
|
||||||
child.iter_leaf_children_with_type("Data").nth(0).unwrap().2,
|
child.iter_leaf_children_with_type("Data").nth(0).unwrap().2,
|
||||||
|
@ -96,11 +113,7 @@ pub fn parse_assembly<'a>(
|
||||||
{
|
{
|
||||||
builder.add_object(
|
builder.add_object(
|
||||||
ident,
|
ident,
|
||||||
Object::Surface(arena.alloc(parse_mesh_surface(
|
Object::Surface(arena.alloc(parse_mesh_surface(arena, child)?)),
|
||||||
arena,
|
|
||||||
child,
|
|
||||||
&builder.surface_shader_map,
|
|
||||||
)?)),
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// TODO: error condition of some kind, because no ident
|
// TODO: error condition of some kind, because no ident
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::{collections::HashMap, result::Result};
|
use std::result::Result;
|
||||||
|
|
||||||
use nom::{sequence::tuple, IResult};
|
use nom::{sequence::tuple, IResult};
|
||||||
|
|
||||||
|
@ -27,9 +27,7 @@ use super::{
|
||||||
pub fn parse_mesh_surface<'a>(
|
pub fn parse_mesh_surface<'a>(
|
||||||
arena: &'a Arena,
|
arena: &'a Arena,
|
||||||
tree: &'a DataTree,
|
tree: &'a DataTree,
|
||||||
surface_shader_map: &HashMap<String, usize>,
|
|
||||||
) -> Result<TriangleMesh<'a>, PsyParseError> {
|
) -> Result<TriangleMesh<'a>, PsyParseError> {
|
||||||
let mut shader_idx = None;
|
|
||||||
let mut verts = Vec::new(); // Vec of vecs, one for each time sample
|
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 normals = Vec::new(); // Vec of vecs, on for each time sample
|
||||||
let mut face_vert_counts = Vec::new();
|
let mut face_vert_counts = Vec::new();
|
||||||
|
@ -38,20 +36,6 @@ pub fn parse_mesh_surface<'a>(
|
||||||
// TODO: make sure there are the right number of various children,
|
// TODO: make sure there are the right number of various children,
|
||||||
// and other validation.
|
// 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
|
// Get verts
|
||||||
for (_, mut text, _) in tree.iter_leaf_children_with_type("Vertices") {
|
for (_, mut text, _) in tree.iter_leaf_children_with_type("Vertices") {
|
||||||
// Collect verts for this time sample
|
// Collect verts for this time sample
|
||||||
|
@ -132,7 +116,6 @@ pub fn parse_mesh_surface<'a>(
|
||||||
|
|
||||||
Ok(TriangleMesh::from_verts_and_indices(
|
Ok(TriangleMesh::from_verts_and_indices(
|
||||||
arena,
|
arena,
|
||||||
shader_idx,
|
|
||||||
&verts,
|
&verts,
|
||||||
&if normals.is_empty() {
|
&if normals.is_empty() {
|
||||||
None
|
None
|
||||||
|
|
|
@ -142,7 +142,7 @@ pub struct AssemblyBuilder<'a> {
|
||||||
|
|
||||||
// Shader list
|
// Shader list
|
||||||
surface_shaders: Vec<&'a dyn SurfaceShader>,
|
surface_shaders: Vec<&'a dyn SurfaceShader>,
|
||||||
pub surface_shader_map: HashMap<String, usize>, // map Name -> Index
|
surface_shader_map: HashMap<String, usize>, // map Name -> Index
|
||||||
|
|
||||||
// Object list
|
// Object list
|
||||||
objects: Vec<Object<'a>>,
|
objects: Vec<Object<'a>>,
|
||||||
|
@ -206,7 +206,12 @@ impl<'a> AssemblyBuilder<'a> {
|
||||||
self.assemblies.push(asmb);
|
self.assemblies.push(asmb);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_instance(&mut self, name: &str, xforms: Option<&[Xform]>) {
|
pub fn add_instance(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
surface_shader_name: Option<&str>,
|
||||||
|
xforms: Option<&[Xform]>,
|
||||||
|
) {
|
||||||
// Make sure name exists
|
// Make sure name exists
|
||||||
if !self.name_exists(name) {
|
if !self.name_exists(name) {
|
||||||
panic!("Attempted to add instance with a name that doesn't exist.");
|
panic!("Attempted to add instance with a name that doesn't exist.");
|
||||||
|
@ -228,6 +233,12 @@ impl<'a> AssemblyBuilder<'a> {
|
||||||
Instance {
|
Instance {
|
||||||
instance_type: InstanceType::Object,
|
instance_type: InstanceType::Object,
|
||||||
data_index: self.object_map[name],
|
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(),
|
id: self.instances.len(),
|
||||||
transform_indices: xforms
|
transform_indices: xforms
|
||||||
.map(|xf| (self.xforms.len(), self.xforms.len() + xf.len())),
|
.map(|xf| (self.xforms.len(), self.xforms.len() + xf.len())),
|
||||||
|
@ -236,6 +247,12 @@ impl<'a> AssemblyBuilder<'a> {
|
||||||
Instance {
|
Instance {
|
||||||
instance_type: InstanceType::Assembly,
|
instance_type: InstanceType::Assembly,
|
||||||
data_index: self.assembly_map[name],
|
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(),
|
id: self.instances.len(),
|
||||||
transform_indices: xforms
|
transform_indices: xforms
|
||||||
.map(|xf| (self.xforms.len(), self.xforms.len() + xf.len())),
|
.map(|xf| (self.xforms.len(), self.xforms.len() + xf.len())),
|
||||||
|
@ -374,6 +391,7 @@ pub enum Object<'a> {
|
||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
pub instance_type: InstanceType,
|
pub instance_type: InstanceType,
|
||||||
pub data_index: usize,
|
pub data_index: usize,
|
||||||
|
pub surface_shader_index: Option<usize>,
|
||||||
pub id: usize,
|
pub id: usize,
|
||||||
pub transform_indices: Option<(usize, usize)>,
|
pub transform_indices: Option<(usize, usize)>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub trait Surface: Boundable + Debug + Sync {
|
||||||
local_ray: &LocalRay,
|
local_ray: &LocalRay,
|
||||||
space: &XformFull,
|
space: &XformFull,
|
||||||
isect: &mut SurfaceIntersection,
|
isect: &mut SurfaceIntersection,
|
||||||
shaders: &[&dyn SurfaceShader],
|
shader: &dyn SurfaceShader,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,10 @@ use crate::{
|
||||||
accel::BVH4,
|
accel::BVH4,
|
||||||
bbox::BBox,
|
bbox::BBox,
|
||||||
boundable::Boundable,
|
boundable::Boundable,
|
||||||
color::Color,
|
|
||||||
lerp::lerp_slice,
|
lerp::lerp_slice,
|
||||||
math::{cross, dot, Normal, Point, XformFull},
|
math::{cross, dot, Normal, Point, XformFull},
|
||||||
ray::{LocalRay, Ray},
|
ray::{LocalRay, Ray},
|
||||||
shading::{SimpleSurfaceShader, SurfaceShader},
|
shading::SurfaceShader,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{triangle, Surface, SurfaceIntersection, SurfaceIntersectionData};
|
use super::{triangle, Surface, SurfaceIntersection, SurfaceIntersectionData};
|
||||||
|
@ -19,7 +18,6 @@ const MAX_LEAF_TRIANGLE_COUNT: usize = 3;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct TriangleMesh<'a> {
|
pub struct TriangleMesh<'a> {
|
||||||
pub shader_idx: Option<usize>,
|
|
||||||
time_sample_count: usize,
|
time_sample_count: usize,
|
||||||
vertices: &'a [Point], // Vertices, with the time samples for each vertex stored contiguously
|
vertices: &'a [Point], // Vertices, with the time samples for each vertex stored contiguously
|
||||||
normals: Option<&'a [Normal]>, // Vertex normals, organized the same as `vertices`
|
normals: Option<&'a [Normal]>, // Vertex normals, organized the same as `vertices`
|
||||||
|
@ -30,7 +28,6 @@ pub struct TriangleMesh<'a> {
|
||||||
impl<'a> TriangleMesh<'a> {
|
impl<'a> TriangleMesh<'a> {
|
||||||
pub fn from_verts_and_indices<'b>(
|
pub fn from_verts_and_indices<'b>(
|
||||||
arena: &'b Arena,
|
arena: &'b Arena,
|
||||||
shader_idx: Option<usize>,
|
|
||||||
verts: &[Vec<Point>],
|
verts: &[Vec<Point>],
|
||||||
vert_normals: &Option<Vec<Vec<Normal>>>,
|
vert_normals: &Option<Vec<Vec<Normal>>>,
|
||||||
tri_indices: &[(usize, usize, usize)],
|
tri_indices: &[(usize, usize, usize)],
|
||||||
|
@ -109,7 +106,6 @@ impl<'a> TriangleMesh<'a> {
|
||||||
});
|
});
|
||||||
|
|
||||||
TriangleMesh {
|
TriangleMesh {
|
||||||
shader_idx: shader_idx,
|
|
||||||
time_sample_count: time_sample_count,
|
time_sample_count: time_sample_count,
|
||||||
vertices: vertices,
|
vertices: vertices,
|
||||||
normals: normals,
|
normals: normals,
|
||||||
|
@ -132,18 +128,8 @@ impl<'a> Surface for TriangleMesh<'a> {
|
||||||
local_ray: &LocalRay,
|
local_ray: &LocalRay,
|
||||||
space: &XformFull,
|
space: &XformFull,
|
||||||
isect: &mut SurfaceIntersection,
|
isect: &mut SurfaceIntersection,
|
||||||
shaders: &[&dyn SurfaceShader],
|
shader: &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| {
|
self.accel.traverse(ray, local_ray, |idx_range, ray| {
|
||||||
// Iterate through the triangles and test the ray against them.
|
// Iterate through the triangles and test the ray against them.
|
||||||
let mut non_shadow_hit = false;
|
let mut non_shadow_hit = false;
|
||||||
|
|
|
@ -73,11 +73,12 @@ impl<'a> Tracer<'a> {
|
||||||
InstanceType::Object => {
|
InstanceType::Object => {
|
||||||
self.trace_object(
|
self.trace_object(
|
||||||
&assembly.objects[inst.data_index],
|
&assembly.objects[inst.data_index],
|
||||||
|
inst.surface_shader_index
|
||||||
|
.map(|i| assembly.surface_shaders[i]),
|
||||||
ray,
|
ray,
|
||||||
&local_ray,
|
&local_ray,
|
||||||
&local_space,
|
&local_space,
|
||||||
isect,
|
isect,
|
||||||
assembly.surface_shaders,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,19 +103,29 @@ impl<'a> Tracer<'a> {
|
||||||
fn trace_object<'b>(
|
fn trace_object<'b>(
|
||||||
&mut self,
|
&mut self,
|
||||||
obj: &Object,
|
obj: &Object,
|
||||||
|
surface_shader: Option<&dyn SurfaceShader>,
|
||||||
ray: &mut Ray,
|
ray: &mut Ray,
|
||||||
local_ray: &LocalRay,
|
local_ray: &LocalRay,
|
||||||
space: &XformFull,
|
space: &XformFull,
|
||||||
isect: &mut SurfaceIntersection,
|
isect: &mut SurfaceIntersection,
|
||||||
shaders: &[&dyn SurfaceShader],
|
|
||||||
) {
|
) {
|
||||||
match *obj {
|
match *obj {
|
||||||
Object::Surface(surface) => {
|
Object::Surface(surface) => {
|
||||||
surface.intersect_ray(ray, local_ray, space, isect, shaders);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object::SurfaceLight(surface) => {
|
Object::SurfaceLight(surface) => {
|
||||||
surface.intersect_ray(ray, local_ray, space, isect, shaders);
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user