Added missing geometry. Implementing missing material methods
This commit is contained in:
parent
3d95ff4c92
commit
3cb2086f6d
18 changed files with 629 additions and 466 deletions
|
|
@ -75,17 +75,17 @@ pub enum Filter {
|
|||
|
||||
impl<T: FilterTrait> FilterTrait for Ptr<T> {
|
||||
fn radius(&self) -> Vector2f {
|
||||
self.radius()
|
||||
self.get().unwrap().radius()
|
||||
}
|
||||
fn integral(&self) -> Float {
|
||||
self.as_ref().integral()
|
||||
self.get().unwrap().integral()
|
||||
}
|
||||
|
||||
fn evaluate(&self, p: Point2f) -> Float {
|
||||
self.evaluate(p)
|
||||
self.get().unwrap().evaluate(p)
|
||||
}
|
||||
|
||||
fn sample(&self, p: Point2f) -> FilterSample {
|
||||
self.sample(p)
|
||||
self.get().unwrap().sample(p)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -354,8 +354,7 @@ impl SurfaceInteraction {
|
|||
let (dpdu, dpdv) = if !displacement.is_null() {
|
||||
bump_map(tex_eval, &displacement, &ctx)
|
||||
} else if !normal_image.is_null() {
|
||||
let map = unsafe { normal_image.as_ref() };
|
||||
normal_map(map, &ctx)
|
||||
normal_map(&normal_image, &ctx)
|
||||
} else {
|
||||
(self.shading.dpdu, self.shading.dpdv)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -224,14 +224,14 @@ pub enum Primitive {
|
|||
|
||||
impl<T: PrimitiveTrait> PrimitiveTrait for Ptr<T> {
|
||||
fn bounds(&self) -> Bounds3f {
|
||||
unsafe { self.as_ref().bounds() }
|
||||
self.get().unwrap().bounds()
|
||||
}
|
||||
|
||||
fn intersect(&self, r: &Ray, t_max: Option<Float>) -> Option<ShapeIntersection> {
|
||||
unsafe { self.as_ref().intersect(r, t_max) }
|
||||
self.get().unwrap().intersect(r, t_max)
|
||||
}
|
||||
|
||||
fn intersect_p(&self, r: &Ray, t_max: Option<Float>) -> bool {
|
||||
unsafe { self.as_ref().intersect_p(r, t_max) }
|
||||
self.get().unwrap().intersect_p(r, t_max)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,10 +40,10 @@ pub enum Spectrum {
|
|||
|
||||
impl<T: SpectrumTrait> SpectrumTrait for Ptr<T> {
|
||||
fn evaluate(&self, lambda: Float) -> Float {
|
||||
self.evaluate(lambda)
|
||||
self.get().unwrap().evaluate(lambda)
|
||||
}
|
||||
fn max_value(&self) -> Float {
|
||||
self.max_value()
|
||||
self.get().unwrap().max_value()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,34 +10,85 @@ use crate::core::scattering::TrowbridgeReitzDistribution;
|
|||
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
||||
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator};
|
||||
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
||||
use crate::utils::Ptr;
|
||||
use crate::utils::math::clamp;
|
||||
use crate::utils::Ptr;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ConductorMaterial {
|
||||
pub displacement: Ptr<GPUFloatTexture>,
|
||||
pub normal_map: Ptr<Image>,
|
||||
pub reflectance: Ptr<GPUSpectrumTexture>,
|
||||
pub eta: Ptr<GPUSpectrumTexture>,
|
||||
pub k: Ptr<GPUSpectrumTexture>,
|
||||
pub reflectance: Ptr<GPUSpectrumTexture>,
|
||||
pub u_roughness: Ptr<GPUFloatTexture>,
|
||||
pub v_roughness: Ptr<GPUFloatTexture>,
|
||||
pub displacement: Ptr<GPUFloatTexture>,
|
||||
pub remap_roughness: bool,
|
||||
pub normal_map: Ptr<Image>,
|
||||
}
|
||||
|
||||
impl ConductorMaterial {
|
||||
pub fn new(
|
||||
normal_map: Ptr<Image>,
|
||||
reflectance: Ptr<GPUSpectrumTexture>,
|
||||
eta: Ptr<GPUSpectrumTexture>,
|
||||
k: Ptr<GPUSpectrumTexture>,
|
||||
u_roughness: Ptr<GPUFloatTexture>,
|
||||
v_roughness: Ptr<GPUFloatTexture>,
|
||||
displacement: Ptr<GPUFloatTexture>,
|
||||
remap_roughness: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
normal_map,
|
||||
reflectance,
|
||||
eta,
|
||||
k,
|
||||
u_roughness,
|
||||
v_roughness,
|
||||
displacement,
|
||||
remap_roughness,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MaterialTrait for ConductorMaterial {
|
||||
fn get_bsdf<T: TextureEvaluator>(
|
||||
&self,
|
||||
_tex_eval: &T,
|
||||
_ctx: &MaterialEvalContext,
|
||||
_lambda: &SampledWavelengths,
|
||||
tex_eval: &T,
|
||||
ctx: &MaterialEvalContext,
|
||||
lambda: &SampledWavelengths,
|
||||
) -> BSDF {
|
||||
todo!()
|
||||
let mut u_rough = tex_eval.evaluate_float(&self.u_roughness, ctx);
|
||||
let mut v_rough = tex_eval.evaluate_float(&self.v_roughness, ctx);
|
||||
if self.remap_roughness {
|
||||
u_rough = TrowbridgeReitzDistribution::roughness_to_alpha(u_rough);
|
||||
v_rough = TrowbridgeReitzDistribution::roughness_to_alpha(v_rough);
|
||||
}
|
||||
let (etas, ks) = if !self.eta.is_null() {
|
||||
(
|
||||
tex_eval.evaluate_spectrum(&self.eta, ctx, lambda),
|
||||
tex_eval.evaluate_spectrum(&self.k, ctx, lambda),
|
||||
)
|
||||
} else {
|
||||
let r = SampledSpectrum::clamp(
|
||||
&tex_eval.evaluate_spectrum(&self.reflectance, ctx, lambda),
|
||||
0.,
|
||||
0.9999,
|
||||
);
|
||||
let one_minus_r = SampledSpectrum::new(1.) - r;
|
||||
(
|
||||
SampledSpectrum::new(1.),
|
||||
2. * r.sqrt() / SampledSpectrum::clamp_zero(&one_minus_r).sqrt(),
|
||||
)
|
||||
};
|
||||
|
||||
let distrib = TrowbridgeReitzDistribution::new(u_rough, v_rough);
|
||||
let bxdf = BxDF::Conductor(ConductorBxDF::new(&distrib, etas, ks));
|
||||
BSDF::new(ctx.ns, ctx.dpdus, bxdf)
|
||||
}
|
||||
|
||||
fn get_bssrdf<T>(
|
||||
&self,
|
||||
_tex_eval: &T,
|
||||
tex_eval: &T,
|
||||
_ctx: &MaterialEvalContext,
|
||||
_lambda: &SampledWavelengths,
|
||||
) -> Option<BSSRDF> {
|
||||
|
|
@ -51,14 +102,14 @@ impl MaterialTrait for ConductorMaterial {
|
|||
}
|
||||
|
||||
fn get_normal_map(&self) -> Option<&Image> {
|
||||
todo!()
|
||||
self.normal_map.get()
|
||||
}
|
||||
|
||||
fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
|
||||
todo!()
|
||||
self.displacement
|
||||
}
|
||||
|
||||
fn has_subsurface_scattering(&self) -> bool {
|
||||
todo!()
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use core::hash::{Hash, Hasher};
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::Index;
|
||||
use core::cmp;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
|
|
@ -21,6 +22,18 @@ impl<T: ?Sized> PartialEq for Ptr<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> PartialOrd for Ptr<T> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||
Some(self.ptr.cmp(&other.ptr))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Ord for Ptr<T> {
|
||||
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
||||
self.ptr.cmp(&other.ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Eq for Ptr<T> {}
|
||||
|
||||
unsafe impl<T: ?Sized + Send> Send for Ptr<T> {}
|
||||
|
|
@ -61,7 +74,7 @@ impl<T> Ptr<T> {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn get_mut<'a>(self) -> Option<&'a mut T> {
|
||||
pub fn get_mut<'a>(self) -> Option<&'a mut T> {
|
||||
if self.is_null() {
|
||||
None
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ impl InteractionGetter for SurfaceInteraction {
|
|||
) -> Option<BSDF> {
|
||||
self.compute_differentials(r, camera, sampler.samples_per_pixel() as i32);
|
||||
let material = {
|
||||
let mut active_mat = unsafe { self.material.as_ref() };
|
||||
let Some(mut active_mat) = self.material.get() else {
|
||||
return None;
|
||||
};
|
||||
let tex_eval = UniversalTextureEvaluator;
|
||||
while let Material::Mix(mix) = active_mat {
|
||||
let ctx = MaterialEvalContext::from(&*self);
|
||||
|
|
@ -72,7 +74,9 @@ impl InteractionGetter for SurfaceInteraction {
|
|||
lambda: &SampledWavelengths,
|
||||
_camera: &Camera,
|
||||
) -> Option<BSSRDF> {
|
||||
let mut active_mat = unsafe { self.material.as_ref() };
|
||||
let Some(mut active_mat) = self.material.get() else {
|
||||
return None;
|
||||
};
|
||||
let tex_eval = UniversalTextureEvaluator;
|
||||
while let Material::Mix(mix) = active_mat {
|
||||
let ctx = MaterialEvalContext::from(self);
|
||||
|
|
|
|||
|
|
@ -17,13 +17,20 @@ pub fn render_scene(scene: &BasicScene, arena: &Arena) -> Result<()> {
|
|||
let media = scene.create_media();
|
||||
let textures = scene.create_textures(arena);
|
||||
let (named_materials, materials) = scene.create_materials(&textures, arena)?;
|
||||
for (i, m) in materials.iter().enumerate() {
|
||||
eprintln!("materials[{}]: {:?}", i, std::mem::discriminant(m));
|
||||
}
|
||||
let lights = scene.create_lights(&textures, arena);
|
||||
|
||||
let have_scattering = {
|
||||
let shapes = scene.shapes.lock();
|
||||
let animated = scene.animated_shapes.lock();
|
||||
shapes.iter().any(|sh| !sh.inside_medium.is_empty() || !sh.outside_medium.is_empty())
|
||||
|| animated.iter().any(|sh| !sh.inside_medium.is_empty() || !sh.outside_medium.is_empty())
|
||||
shapes
|
||||
.iter()
|
||||
.any(|sh| !sh.inside_medium.is_empty() || !sh.outside_medium.is_empty())
|
||||
|| animated
|
||||
.iter()
|
||||
.any(|sh| !sh.inside_medium.is_empty() || !sh.outside_medium.is_empty())
|
||||
};
|
||||
|
||||
let (aggregate, area_lights) =
|
||||
|
|
@ -83,7 +90,7 @@ pub fn render_scene(scene: &BasicScene, arena: &Arena) -> Result<()> {
|
|||
log::debug!("Distance from camera: {}\n", intr.p().distance(cr.ray.o));
|
||||
|
||||
for (name, mtl) in &named_materials {
|
||||
if *mtl == unsafe { *intr.material.as_ref() } {
|
||||
if *mtl == *intr.material.get().unwrap() {
|
||||
log::debug!("Named material: {}\n\n", name);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,6 @@ impl Default for GraphicsState {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
enum BlockState {
|
||||
OptionsBlock,
|
||||
|
|
@ -263,7 +262,7 @@ impl ParserTarget for BasicSceneBuilder {
|
|||
let stdcs = get_colorspace_device();
|
||||
let _ = match stdcs.get_named(name) {
|
||||
Some(cs) => {
|
||||
self.graphics_state.color_space = unsafe { Some(Arc::new(*cs.as_ref())) };
|
||||
self.graphics_state.color_space = Some(Arc::new(*cs.get().unwrap()));
|
||||
}
|
||||
None => {
|
||||
eprintln!("Error: Color space '{}' unknown at {}", name, loc);
|
||||
|
|
@ -747,9 +746,12 @@ impl ParserTarget for BasicSceneBuilder {
|
|||
loc,
|
||||
parameters: ParameterDictionary::new(params.clone(), None).unwrap(),
|
||||
};
|
||||
self.graphics_state.current_material_name = self.scene.add_material(entity).to_string();
|
||||
let idx = self.scene.add_material(entity);
|
||||
self.graphics_state.current_material_index = Some(idx);
|
||||
self.graphics_state.current_material_name = String::new();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn make_named_material(
|
||||
&mut self,
|
||||
_name: &str,
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ fn resolve_material(
|
|||
arena: &Arena,
|
||||
) -> Material {
|
||||
match mat_ref {
|
||||
MaterialRef::Name(name) => match named_materials.get(name) {
|
||||
MaterialRef::Name(name) => match named_materials.get(name) {
|
||||
Some(m) => *m,
|
||||
None => {
|
||||
log::error!("{}: named material '{}' not found", loc, name);
|
||||
|
|
@ -468,7 +468,7 @@ impl BasicScene {
|
|||
let materials: Vec<Material> = state
|
||||
.materials
|
||||
.iter()
|
||||
.filter_map(|entity| {
|
||||
.map(|entity| {
|
||||
let result: Result<Material> = (|| {
|
||||
let normal_map = self.get_normal_map(&state, &entity.parameters)?;
|
||||
let tex_dict = TextureParameterDictionary::new(
|
||||
|
|
@ -484,12 +484,11 @@ impl BasicScene {
|
|||
arena,
|
||||
)
|
||||
})();
|
||||
|
||||
match result {
|
||||
Ok(mat) => Some(mat),
|
||||
Ok(mat) => mat,
|
||||
Err(e) => {
|
||||
log::error!("{}: failed to create material: {}", entity.loc, e);
|
||||
None
|
||||
crate::core::material::default_diffuse_material(arena)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
use crate::core::texture::FloatTexture;
|
||||
use crate::shapes::*;
|
||||
use crate::utils::loop_subdivide;
|
||||
use crate::utils::resolve_filename;
|
||||
use crate::{Arena, FileLoc, ParameterDictionary};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use parking_lot::Mutex;
|
||||
use shared::core::shape::*;
|
||||
use shared::shapes::*;
|
||||
use shared::{Transform, Ptr};
|
||||
use shared::{Ptr, Transform};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
@ -130,6 +131,79 @@ impl ShapeFactory for Shape {
|
|||
|
||||
Ok(shapes)
|
||||
}
|
||||
"loopsubdiv" => {
|
||||
let n_levels = parameters.get_one_int("levels", 3)? as usize;
|
||||
|
||||
let Ok(vertex_indices_i32) = parameters.get_int_array("indices") else {
|
||||
bail!("Vertex indices \"indices\" not provided for \"LoopSubdiv\" shape.");
|
||||
};
|
||||
let Ok(p) = parameters.get_point3f_array("P") else {
|
||||
bail!("Vertex positions \"P\" not provided for LoopSubdiv shape.");
|
||||
};
|
||||
|
||||
if vertex_indices_i32.is_empty() {
|
||||
bail!("Vertex indices \"indices\" must be provided with loopsubdiv.");
|
||||
}
|
||||
if vertex_indices_i32.len() % 3 != 0 {
|
||||
bail!(
|
||||
"Number of vertex indices {} not a multiple of 3.",
|
||||
vertex_indices_i32.len()
|
||||
);
|
||||
}
|
||||
if p.is_empty() {
|
||||
bail!("Vertex positions \"P\" must be provided with loopsubdiv.");
|
||||
}
|
||||
|
||||
let vertex_indices: Vec<usize> = vertex_indices_i32
|
||||
.iter()
|
||||
.map(|&i| {
|
||||
if i < 0 {
|
||||
bail!("Negative vertex index {} in loopsubdiv.", i);
|
||||
}
|
||||
let ui = i as usize;
|
||||
if ui >= p.len() {
|
||||
bail!(
|
||||
"Vertex index {} out of bounds ({} \"P\" values given).",
|
||||
i,
|
||||
p.len()
|
||||
);
|
||||
}
|
||||
Ok(ui)
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
let scheme = parameters.get_one_string("scheme", "loop")?;
|
||||
if scheme != "loop" {
|
||||
bail!("Unsupported subdivision scheme \"{}\".", scheme);
|
||||
}
|
||||
|
||||
let mesh = loop_subdivide(
|
||||
arena,
|
||||
&render_from_object,
|
||||
reverse_orientation,
|
||||
n_levels,
|
||||
&vertex_indices,
|
||||
&p,
|
||||
);
|
||||
|
||||
let host_arc = Arc::new(mesh);
|
||||
let mut global_store = ALL_TRIANGLE_MESHES.lock();
|
||||
global_store.push(host_arc.clone());
|
||||
drop(global_store);
|
||||
|
||||
let n_tris = host_arc.n_triangles;
|
||||
let mesh_ptr = arena.alloc_arc(host_arc);
|
||||
let shapes: Vec<Ptr<Shape>> = (0..n_tris)
|
||||
.map(|i| {
|
||||
arena.alloc(Shape::Triangle(TriangleShape {
|
||||
mesh: mesh_ptr,
|
||||
tri_index: i as i32,
|
||||
}))
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(shapes)
|
||||
}
|
||||
_ => Err(anyhow!("Unknown shape name")),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -227,12 +227,6 @@ impl RayIntegratorTrait for PathIntegrator {
|
|||
let t_hit = si.t_hit();
|
||||
let isect = &mut si.intr;
|
||||
|
||||
if state.depth == 0 {
|
||||
let n = isect.n();
|
||||
let v = (n.x() + 1.0) * 0.5;
|
||||
return (SampledSpectrum::from_array(&[v, v, v, v]), None);
|
||||
}
|
||||
|
||||
// Emission from hit surface
|
||||
let le = isect.le(-ray.d, lambda);
|
||||
if !le.is_black() {
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ pub fn create(
|
|||
|
||||
// Upload alpha texture to GPU and check for null texture
|
||||
let alpha_ptr = arena.upload(alpha);
|
||||
let light_type = match unsafe { alpha_ptr.as_ref() } {
|
||||
let light_type = match alpha_ptr.get().unwrap() {
|
||||
GPUFloatTexture::Constant(t) if t.evaluate(&TextureEvalContext::default()) == 0.0 => {
|
||||
LightType::DeltaPosition
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,68 @@
|
|||
use crate::core::image::HostImage;
|
||||
use crate::core::material::CreateMaterial;
|
||||
// use crate::core::scattering::TrowbridgeReitzDistribution;
|
||||
use crate::core::texture::SpectrumTexture;
|
||||
use crate::spectra::data::get_named_spectrum;
|
||||
use crate::utils::TextureParameterDictionary;
|
||||
use anyhow::Result;
|
||||
use crate::{Arena, ArenaUpload, FileLoc};
|
||||
use anyhow::{bail, Result};
|
||||
use shared::core::texture::SpectrumType;
|
||||
use shared::core::material::Material;
|
||||
use shared::materials::ConductorMaterial;
|
||||
use shared::textures::SpectrumConstantTexture;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
impl CreateMaterial for ConductorMaterial {
|
||||
fn create(
|
||||
_parameters: &TextureParameterDictionary,
|
||||
_normal_map: Option<Arc<HostImage>>,
|
||||
_named_materials: &std::collections::HashMap<String, shared::core::material::Material>,
|
||||
_loc: &crate::utils::FileLoc,
|
||||
_arena: &crate::Arena,
|
||||
parameters: &TextureParameterDictionary,
|
||||
normal_map: Option<Arc<HostImage>>,
|
||||
_named_materials: &HashMap<String, Material>,
|
||||
loc: &FileLoc,
|
||||
arena: &Arena,
|
||||
) -> Result<Material> {
|
||||
todo!()
|
||||
let eta = parameters.get_spectrum_texture_or_null("eta", SpectrumType::Unbounded);
|
||||
let k = parameters.get_spectrum_texture_or_null("k", SpectrumType::Unbounded);
|
||||
let reflectance =
|
||||
parameters.get_spectrum_texture_or_null("reflectance", SpectrumType::Albedo);
|
||||
let (eta, k) = if reflectance.is_some() {
|
||||
if eta.is_some() || k.is_some() {
|
||||
bail!(
|
||||
"{}: For the coated conductor material, both \"reflectance\" \
|
||||
and \"eta\"/\"k\" cannot be provided simultaneously.",
|
||||
loc
|
||||
);
|
||||
}
|
||||
(None, None)
|
||||
} else {
|
||||
let eta = eta.unwrap_or_else(|| {
|
||||
let s = get_named_spectrum("metal-Cu-eta").expect("Missing copper spectrum");
|
||||
Arc::new(SpectrumTexture::Constant(SpectrumConstantTexture::new(s)))
|
||||
});
|
||||
let k = k.unwrap_or_else(|| {
|
||||
let s = get_named_spectrum("metal-Cu-k").expect("Missing copper spectrum");
|
||||
Arc::new(SpectrumTexture::Constant(SpectrumConstantTexture::new(s)))
|
||||
});
|
||||
(Some(eta), Some(k))
|
||||
};
|
||||
|
||||
let u_roughness = parameters.get_float_texture("roughness", 0.)?;
|
||||
let v_roughness = parameters.get_float_texture("roughness", 0.)?;
|
||||
let displacement = parameters.get_float_texture_or_null("displacement")?;
|
||||
let remap_roughness = parameters.get_one_bool("remaproughness", true)?;
|
||||
eprintln!("ConductorMaterial::create eta={:?} k={:?} reflectance={:?}", eta.is_some(), k.is_some(), reflectance.is_some());
|
||||
|
||||
let material = Self::new(
|
||||
arena.upload(normal_map),
|
||||
arena.upload(reflectance),
|
||||
arena.upload(eta),
|
||||
arena.upload(k),
|
||||
arena.upload(u_roughness),
|
||||
arena.upload(v_roughness),
|
||||
arena.upload(displacement),
|
||||
remap_roughness,
|
||||
);
|
||||
|
||||
arena.alloc(material);
|
||||
Ok(Material::Conductor(material))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@ use crate::core::texture::{FloatTextureTrait, SpectrumTextureTrait};
|
|||
use crate::utils::{FileLoc, TextureParameterDictionary};
|
||||
use crate::Arena;
|
||||
use anyhow::Result;
|
||||
use shared::core::spectrum::Spectrum;
|
||||
use shared::core::texture::{SpectrumType, TextureEvalContext};
|
||||
use shared::spectra::{SampledSpectrum, SampledWavelengths};
|
||||
use shared::spectra::{SampledSpectrum, SampledWavelengths, ConstantSpectrum};
|
||||
use shared::utils::Transform;
|
||||
use shared::Float;
|
||||
use std::sync::Arc;
|
||||
|
|
@ -70,11 +71,32 @@ pub struct SpectrumScaledTexture {
|
|||
impl CreateSpectrumTexture for SpectrumScaledTexture {
|
||||
fn create(
|
||||
_render_from_texture: Transform,
|
||||
_parameters: TextureParameterDictionary,
|
||||
_spectrum_type: SpectrumType,
|
||||
parameters: TextureParameterDictionary,
|
||||
spectrum_type: SpectrumType,
|
||||
_loc: FileLoc,
|
||||
) -> Result<SpectrumTexture> {
|
||||
todo!()
|
||||
let one = Spectrum::Constant(ConstantSpectrum::new(1.0));
|
||||
let tex = parameters
|
||||
.get_spectrum_texture("tex", Some(one), spectrum_type)
|
||||
.ok_or_else(|| anyhow::anyhow!("{}: missing \"tex\" parameter", _loc))?;
|
||||
let scale = parameters.get_float_texture("scale", 1.0)?;
|
||||
|
||||
if let FloatTexture::Constant(ref cscale) = *scale {
|
||||
let cs = cscale.value;
|
||||
if cs == 1.0 {
|
||||
return Ok((*tex).clone());
|
||||
}
|
||||
if let SpectrumTexture::Image(ref image) = *tex {
|
||||
let mut image_copy = image.clone();
|
||||
image_copy.base.multiply_scale(cs);
|
||||
return Ok(SpectrumTexture::Image(image_copy));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(SpectrumTexture::Scaled(SpectrumScaledTexture {
|
||||
tex,
|
||||
scale,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,533 +1,472 @@
|
|||
use crate::utils::backend::GpuAllocator;
|
||||
use crate::Arena;
|
||||
use shared::core::geometry::{Normal3f, Point3f, Vector3f};
|
||||
use shared::{Float, Ptr};
|
||||
use shared::shapes::TriangleMesh;
|
||||
use shared::{Float, Transform};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct SDVertex {
|
||||
pub p: Point3f,
|
||||
pub start_face: Ptr<SDFace>,
|
||||
pub child: Ptr<SDVertex>,
|
||||
pub regular: bool,
|
||||
pub boundary: bool,
|
||||
const NULL: u32 = u32::MAX;
|
||||
|
||||
#[repr(C)]
|
||||
struct SDVertex {
|
||||
p: Point3f,
|
||||
start_face: u32,
|
||||
child: u32,
|
||||
regular: bool,
|
||||
boundary: bool,
|
||||
}
|
||||
|
||||
impl SDVertex {
|
||||
pub fn new(p: Point3f) -> Self {
|
||||
Self {
|
||||
p,
|
||||
start_face: Ptr::null(),
|
||||
child: Ptr::null(),
|
||||
regular: false,
|
||||
boundary: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SDFace {
|
||||
pub v: [Ptr<SDVertex>; 3],
|
||||
pub f: [Ptr<SDFace>; 3],
|
||||
pub children: [Ptr<SDFace>; 4],
|
||||
#[repr(C)]
|
||||
struct SDFace {
|
||||
v: [u32; 3],
|
||||
f: [u32; 3],
|
||||
children: [u32; 4],
|
||||
}
|
||||
|
||||
impl SDFace {
|
||||
pub fn new(v0: Ptr<SDVertex>, v1: Ptr<SDVertex>, v2: Ptr<SDVertex>) -> Self {
|
||||
Self {
|
||||
v: [v0, v1, v2],
|
||||
f: [Ptr::null(); 3],
|
||||
children: [Ptr::null(); 4],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vnum(&self, vert: Ptr<SDVertex>) -> usize {
|
||||
fn vnum(&self, vert: u32) -> usize {
|
||||
for i in 0..3 {
|
||||
if self.v[i] == vert {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
panic!("Basic logic error in SDFace::vnum()");
|
||||
panic!("SDFace::vnum: vertex {} not in face", vert);
|
||||
}
|
||||
|
||||
pub fn next_face(&self, vert: Ptr<SDVertex>) -> Ptr<SDFace> {
|
||||
self.f[self.vnum(vert)]
|
||||
}
|
||||
fn next_face(&self, vert: u32) -> u32 { self.f[self.vnum(vert)] }
|
||||
fn prev_face(&self, vert: u32) -> u32 { self.f[prev(self.vnum(vert))] }
|
||||
fn next_vert(&self, vert: u32) -> u32 { self.v[next(self.vnum(vert))] }
|
||||
fn prev_vert(&self, vert: u32) -> u32 { self.v[prev(self.vnum(vert))] }
|
||||
|
||||
pub fn prev_face(&self, vert: Ptr<SDVertex>) -> Ptr<SDFace> {
|
||||
self.f[prev(self.vnum(vert))]
|
||||
}
|
||||
|
||||
pub fn next_vert(&self, vert: Ptr<SDVertex>) -> Ptr<SDVertex> {
|
||||
self.v[next(self.vnum(vert))]
|
||||
}
|
||||
|
||||
pub fn prev_vert(&self, vert: Ptr<SDVertex>) -> Ptr<SDVertex> {
|
||||
self.v[prev(self.vnum(vert))]
|
||||
}
|
||||
|
||||
pub fn other_vert(&self, v0: Ptr<SDVertex>, v1: Ptr<SDVertex>) -> Ptr<SDVertex> {
|
||||
fn other_vert(&self, v0: u32, v1: u32) -> u32 {
|
||||
for i in 0..3 {
|
||||
if self.v[i] != v0 && self.v[i] != v1 {
|
||||
return self.v[i];
|
||||
}
|
||||
}
|
||||
panic!("Basic logic error in SDFace::other_vert()");
|
||||
panic!("SDFace::other_vert: face doesn't contain both vertices");
|
||||
}
|
||||
}
|
||||
|
||||
const fn next(i: usize) -> usize {
|
||||
(i + 1) % 3
|
||||
}
|
||||
#[inline(always)]
|
||||
const fn next(i: usize) -> usize { (i + 1) % 3 }
|
||||
|
||||
const fn prev(i: usize) -> usize {
|
||||
(i + 2) % 3
|
||||
}
|
||||
#[inline(always)]
|
||||
const fn prev(i: usize) -> usize { (i + 2) % 3 }
|
||||
|
||||
fn canonical_key<T>(v0: Ptr<T>, v1: Ptr<T>) -> (usize, usize) {
|
||||
let a = v0.as_ptr() as usize;
|
||||
let b = v1.as_ptr() as usize;
|
||||
if a <= b {
|
||||
(a, b)
|
||||
} else {
|
||||
(b, a)
|
||||
#[derive(Hash, Eq, PartialEq, Copy, Clone)]
|
||||
struct EdgeKey(u32, u32);
|
||||
|
||||
impl EdgeKey {
|
||||
fn new(a: u32, b: u32) -> Self {
|
||||
if a <= b { Self(a, b) } else { Self(b, a) }
|
||||
}
|
||||
}
|
||||
|
||||
fn beta(valence: usize) -> Float {
|
||||
if valence == 3 {
|
||||
3.0 / 16.0
|
||||
} else {
|
||||
3.0 / (8.0 * valence as Float)
|
||||
}
|
||||
if valence == 3 { 3.0 / 16.0 } else { 3.0 / (8.0 * valence as Float) }
|
||||
}
|
||||
|
||||
fn loop_gamma(valence: usize) -> Float {
|
||||
1.0 / (valence as Float + 3.0 / (8.0 * beta(valence)))
|
||||
}
|
||||
|
||||
fn valence(v: Ptr<SDVertex>) -> usize {
|
||||
let vertex = v;
|
||||
let start = vertex.start_face;
|
||||
if start.is_null() {
|
||||
return 0;
|
||||
}
|
||||
fn valence(verts: &[SDVertex], faces: &[SDFace], vi: u32) -> usize {
|
||||
let v = &verts[vi as usize];
|
||||
let start = v.start_face;
|
||||
debug_assert_ne!(start, NULL);
|
||||
|
||||
if !vertex.boundary {
|
||||
let mut nf = 1;
|
||||
let mut f = start;
|
||||
loop {
|
||||
f = f.next_face(v);
|
||||
if f.is_null() {
|
||||
panic!("interior vertex with broken face loop");
|
||||
}
|
||||
if f == start {
|
||||
break;
|
||||
}
|
||||
if !v.boundary {
|
||||
let mut nf = 1usize;
|
||||
let mut fi = faces[start as usize].next_face(vi);
|
||||
while fi != start {
|
||||
assert_ne!(fi, NULL, "interior vertex with broken face loop");
|
||||
nf += 1;
|
||||
fi = faces[fi as usize].next_face(vi);
|
||||
}
|
||||
nf
|
||||
} else {
|
||||
let mut nf = 1;
|
||||
let mut f = start;
|
||||
while !f.next_face(v).is_null() {
|
||||
f = f.next_face(v);
|
||||
let mut nf = 1usize;
|
||||
let mut fi = faces[start as usize].next_face(vi);
|
||||
while fi != NULL {
|
||||
nf += 1;
|
||||
fi = faces[fi as usize].next_face(vi);
|
||||
}
|
||||
f = start;
|
||||
while !f.prev_face(v).is_null() {
|
||||
f = f.prev_face(v);
|
||||
fi = faces[start as usize].prev_face(vi);
|
||||
while fi != NULL {
|
||||
nf += 1;
|
||||
fi = faces[fi as usize].prev_face(vi);
|
||||
}
|
||||
nf + 1
|
||||
}
|
||||
}
|
||||
|
||||
fn one_ring(v: Ptr<SDVertex>, out: &mut [Point3f]) {
|
||||
let vertex = v;
|
||||
if !vertex.boundary {
|
||||
let start = vertex.start_face;
|
||||
let mut face = start;
|
||||
let mut i = 0;
|
||||
fn one_ring(verts: &[SDVertex], faces: &[SDFace], vi: u32) -> Vec<Point3f> {
|
||||
let v = &verts[vi as usize];
|
||||
let mut ring = Vec::new();
|
||||
|
||||
if !v.boundary {
|
||||
let start = v.start_face;
|
||||
let mut fi = start;
|
||||
loop {
|
||||
out[i] = face.next_vert(v).p;
|
||||
i += 1;
|
||||
face = face.next_face(v);
|
||||
if face == start {
|
||||
break;
|
||||
}
|
||||
ring.push(verts[faces[fi as usize].next_vert(vi) as usize].p);
|
||||
fi = faces[fi as usize].next_face(vi);
|
||||
if fi == start { break; }
|
||||
}
|
||||
} else {
|
||||
let start = vertex.start_face;
|
||||
let mut face = start;
|
||||
while !face.next_face(v).is_null() {
|
||||
face = face.next_face(v);
|
||||
}
|
||||
out[0] = face.next_vert(v).p;
|
||||
let mut i = 1;
|
||||
// Walk forward to the last face in the fan
|
||||
let mut fi = v.start_face;
|
||||
loop {
|
||||
out[i] = face.prev_vert(v).p;
|
||||
i += 1;
|
||||
let pf = face.prev_face(v);
|
||||
if pf.is_null() {
|
||||
break;
|
||||
}
|
||||
face = pf;
|
||||
let nf = faces[fi as usize].next_face(vi);
|
||||
if nf == NULL { break; }
|
||||
fi = nf;
|
||||
}
|
||||
ring.push(verts[faces[fi as usize].next_vert(vi) as usize].p);
|
||||
loop {
|
||||
ring.push(verts[faces[fi as usize].prev_vert(vi) as usize].p);
|
||||
let pf = faces[fi as usize].prev_face(vi);
|
||||
if pf == NULL { break; }
|
||||
fi = pf;
|
||||
}
|
||||
}
|
||||
ring
|
||||
}
|
||||
|
||||
fn weight_one_ring(v: Ptr<SDVertex>, beta: Float) -> Point3f {
|
||||
let valence = valence(v);
|
||||
let mut p_ring = vec![Point3f::default(); valence];
|
||||
one_ring(v, &mut p_ring);
|
||||
|
||||
let vertex = v;
|
||||
let mut p = vertex.p * (1.0 - valence as Float * beta);
|
||||
for i in 0..valence {
|
||||
p += p_ring[i] * beta;
|
||||
fn weight_one_ring(verts: &[SDVertex], faces: &[SDFace], vi: u32, beta: Float) -> Point3f {
|
||||
let ring = one_ring(verts, faces, vi);
|
||||
let val = ring.len();
|
||||
let mut acc = (1.0 - val as Float * beta) * Vector3f::from(verts[vi as usize].p);
|
||||
for r in &ring {
|
||||
acc += beta * Vector3f::from(*r);
|
||||
}
|
||||
p
|
||||
Point3f::from(acc)
|
||||
}
|
||||
|
||||
fn weight_boundary(v: Ptr<SDVertex>, beta: Float) -> Point3f {
|
||||
let valence = valence(v);
|
||||
let mut p_ring = vec![Point3f::default(); valence];
|
||||
one_ring(v, &mut p_ring);
|
||||
|
||||
let vertex = v;
|
||||
let mut p = vertex.p * (1.0 - 2.0 * beta);
|
||||
p += p_ring[0] * beta;
|
||||
p += p_ring[valence - 1] * beta;
|
||||
p
|
||||
fn weight_boundary(verts: &[SDVertex], faces: &[SDFace], vi: u32, beta: Float) -> Point3f {
|
||||
let ring = one_ring(verts, faces, vi);
|
||||
let val = ring.len();
|
||||
let acc = (1.0 - 2.0 * beta) * Vector3f::from(verts[vi as usize].p)
|
||||
+ beta * Vector3f::from(ring[0])
|
||||
+ beta * Vector3f::from(ring[val - 1]);
|
||||
Point3f::from(acc)
|
||||
}
|
||||
|
||||
pub fn loop_subdivide<A: GpuAllocator>(
|
||||
arena: &Arena<A>,
|
||||
pub fn loop_subdivide(
|
||||
_arena: &Arena,
|
||||
render_from_object: &Transform,
|
||||
reverse_orientation: bool,
|
||||
n_levels: usize,
|
||||
vertex_indices: &[usize],
|
||||
p: &[Point3f],
|
||||
points: &[Point3f],
|
||||
) -> TriangleMesh {
|
||||
let mut vertices: Vec<Ptr<SDVertex>> = Vec::with_capacity(p.len());
|
||||
for &pos in p {
|
||||
vertices.push(arena.alloc(SDVertex::new(pos)));
|
||||
}
|
||||
let n_faces_init = vertex_indices.len() / 3;
|
||||
|
||||
let n_faces = vertex_indices.len() / 3;
|
||||
let mut faces: Vec<Ptr<SDFace>> = Vec::with_capacity(n_faces);
|
||||
for i in 0..n_faces {
|
||||
let v0 = vertices[vertex_indices[3 * i]];
|
||||
let v1 = vertices[vertex_indices[3 * i + 1]];
|
||||
let v2 = vertices[vertex_indices[3 * i + 2]];
|
||||
faces.push(arena.alloc(SDFace::new(v0, v1, v2)));
|
||||
}
|
||||
let mut verts: Vec<SDVertex> = points
|
||||
.iter()
|
||||
.map(|&p| SDVertex {
|
||||
p,
|
||||
start_face: NULL,
|
||||
child: NULL,
|
||||
regular: false,
|
||||
boundary: false,
|
||||
})
|
||||
.collect();
|
||||
|
||||
for &f in &faces {
|
||||
let face = f;
|
||||
let mut faces: Vec<SDFace> = (0..n_faces_init)
|
||||
.map(|i| {
|
||||
let base = i * 3;
|
||||
SDFace {
|
||||
v: [
|
||||
vertex_indices[base] as u32,
|
||||
vertex_indices[base + 1] as u32,
|
||||
vertex_indices[base + 2] as u32,
|
||||
],
|
||||
f: [NULL; 3],
|
||||
children: [NULL; 4],
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
for fi in 0..n_faces_init {
|
||||
for j in 0..3 {
|
||||
face.v[j].get_mut().unwrap().start_face = f;
|
||||
verts[faces[fi].v[j] as usize].start_face = fi as u32;
|
||||
}
|
||||
}
|
||||
|
||||
let mut edges: HashMap<(usize, usize), (Ptr<SDFace>, usize)> = HashMap::new();
|
||||
for &f in &faces {
|
||||
let face = f;
|
||||
for edge_num in 0..3 {
|
||||
let v0 = face.v[edge_num];
|
||||
let v1 = face.v[next(edge_num)];
|
||||
let key = canonical_key(v0, v1);
|
||||
{
|
||||
let mut edge_map: HashMap<EdgeKey, (u32, usize)> =
|
||||
HashMap::with_capacity(n_faces_init * 3 / 2);
|
||||
|
||||
if let Some(&(first_face, first_edge_num)) = edges.get(&key) {
|
||||
first_face.get_mut().unwrap().f[first_edge_num] = f;
|
||||
f.get_mut().f[edge_num] = first_face;
|
||||
edges.remove(&key);
|
||||
} else {
|
||||
edges.insert(key, (f, edge_num));
|
||||
}
|
||||
}
|
||||
}
|
||||
for fi in 0..n_faces_init {
|
||||
for edge_num in 0..3 {
|
||||
let v0 = faces[fi].v[edge_num];
|
||||
let v1 = faces[fi].v[next(edge_num)];
|
||||
let key = EdgeKey::new(v0, v1);
|
||||
|
||||
for &v in &vertices {
|
||||
let vertex = v.get_mut().unwrap();
|
||||
let start = vertex.start_face;
|
||||
let mut f = start;
|
||||
let mut is_boundary = false;
|
||||
loop {
|
||||
let nf = f.next_face(v);
|
||||
if nf.is_null() {
|
||||
is_boundary = true;
|
||||
break;
|
||||
}
|
||||
f = nf;
|
||||
if f == start {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let val = valence(v);
|
||||
vertex.boundary = is_boundary;
|
||||
vertex.regular = if !is_boundary && val == 6 {
|
||||
true
|
||||
} else if is_boundary && val == 4 {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
}
|
||||
|
||||
// -- Subdivision levels ---------------------------------------------------
|
||||
let mut f = faces;
|
||||
let mut v = vertices;
|
||||
|
||||
for _ in 0..n_levels {
|
||||
let mut new_faces: Vec<Ptr<SDFace>> = Vec::new();
|
||||
let mut new_vertices: Vec<Ptr<SDVertex>> = Vec::new();
|
||||
|
||||
// Allocate vertex children
|
||||
for &vertex_ptr in &v {
|
||||
let vertex = vertex_ptr;
|
||||
let child = arena.alloc(SDVertex {
|
||||
p: Point3f::default(),
|
||||
start_face: Ptr::null(),
|
||||
child: Ptr::null(),
|
||||
regular: vertex.regular,
|
||||
boundary: vertex.boundary,
|
||||
});
|
||||
vertex_ptr.get_mut().unwrap().child = child;
|
||||
new_vertices.push(child);
|
||||
}
|
||||
|
||||
for &face_ptr in &f {
|
||||
for k in 0..4 {
|
||||
let child = arena.alloc(SDFace::new(Ptr::null(), Ptr::null(), Ptr::null()));
|
||||
face_ptr.get_mut().unwrap().children[k] = child;
|
||||
new_faces.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
for &vertex_ptr in &v {
|
||||
let vertex = vertex_ptr;
|
||||
let child = vertex.child;
|
||||
let new_p = if !vertex.boundary {
|
||||
if vertex.regular {
|
||||
weight_one_ring(vertex_ptr, 1.0 / 16.0)
|
||||
if let Some(&(other_fi, other_edge)) = edge_map.get(&key) {
|
||||
faces[other_fi as usize].f[other_edge] = fi as u32;
|
||||
faces[fi].f[edge_num] = other_fi;
|
||||
edge_map.remove(&key);
|
||||
} else {
|
||||
let val = valence(vertex_ptr);
|
||||
weight_one_ring(vertex_ptr, beta(val))
|
||||
edge_map.insert(key, (fi as u32, edge_num));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Classify vertices as boundary/interior and regular/extraordinary
|
||||
for vi in 0..verts.len() {
|
||||
let start = verts[vi].start_face;
|
||||
let mut fi = start;
|
||||
let is_boundary = loop {
|
||||
let nf = faces[fi as usize].next_face(vi as u32);
|
||||
if nf == NULL { break true; }
|
||||
fi = nf;
|
||||
if fi == start { break false; }
|
||||
};
|
||||
verts[vi].boundary = is_boundary;
|
||||
let val = valence(&verts, &faces, vi as u32);
|
||||
verts[vi].regular = if !is_boundary { val == 6 } else { val == 4 };
|
||||
}
|
||||
|
||||
let mut live_verts: Vec<u32> = (0..verts.len() as u32).collect();
|
||||
let mut live_faces: Vec<u32> = (0..faces.len() as u32).collect();
|
||||
|
||||
for _level in 0..n_levels {
|
||||
let old_verts = live_verts.clone();
|
||||
let old_faces = live_faces.clone();
|
||||
let mut new_verts: Vec<u32> = Vec::with_capacity(old_verts.len() + old_faces.len() * 3);
|
||||
let mut new_faces: Vec<u32> = Vec::with_capacity(old_faces.len() * 4);
|
||||
|
||||
// Allocate child (even) vertices — one per existing vertex
|
||||
for &vi in &old_verts {
|
||||
let child_id = verts.len() as u32;
|
||||
verts.push(SDVertex {
|
||||
p: Point3f::default(),
|
||||
start_face: NULL,
|
||||
child: NULL,
|
||||
regular: verts[vi as usize].regular,
|
||||
boundary: verts[vi as usize].boundary,
|
||||
});
|
||||
verts[vi as usize].child = child_id;
|
||||
new_verts.push(child_id);
|
||||
}
|
||||
|
||||
// Allocate 4 child faces per existing face
|
||||
for &fi in &old_faces {
|
||||
let base = faces.len() as u32;
|
||||
for _ in 0..4 {
|
||||
faces.push(SDFace {
|
||||
v: [NULL; 3],
|
||||
f: [NULL; 3],
|
||||
children: [NULL; 4],
|
||||
});
|
||||
}
|
||||
faces[fi as usize].children = [base, base + 1, base + 2, base + 3];
|
||||
for k in 0..4u32 {
|
||||
new_faces.push(base + k);
|
||||
}
|
||||
}
|
||||
|
||||
// Reposition even vertices using the Loop stencil
|
||||
for &vi in &old_verts {
|
||||
let child = verts[vi as usize].child;
|
||||
let new_p = if !verts[vi as usize].boundary {
|
||||
if verts[vi as usize].regular {
|
||||
weight_one_ring(&verts, &faces, vi, 1.0 / 16.0)
|
||||
} else {
|
||||
let val = valence(&verts, &faces, vi);
|
||||
weight_one_ring(&verts, &faces, vi, beta(val))
|
||||
}
|
||||
} else {
|
||||
weight_boundary(vertex_ptr, 1.0 / 8.0)
|
||||
weight_boundary(&verts, &faces, vi, 1.0 / 8.0)
|
||||
};
|
||||
child.get_mut().unwrap().p = new_p;
|
||||
verts[child as usize].p = new_p;
|
||||
}
|
||||
|
||||
let mut edge_verts: HashMap<(usize, usize), Ptr<SDVertex>> = HashMap::new();
|
||||
for &face_ptr in &f {
|
||||
let face = face_ptr;
|
||||
// Create odd (edge) vertices
|
||||
let mut edge_verts: HashMap<EdgeKey, u32> = HashMap::new();
|
||||
|
||||
for &fi in &old_faces {
|
||||
for k in 0..3 {
|
||||
let v0 = face.v[k];
|
||||
let v1 = face.v[next(k)];
|
||||
let key = canonical_key(v0, v1);
|
||||
let v0 = faces[fi as usize].v[k];
|
||||
let v1 = faces[fi as usize].v[next(k)];
|
||||
let key = EdgeKey::new(v0, v1);
|
||||
|
||||
if !edge_verts.contains_key(&key) {
|
||||
let is_boundary = face.f[k].is_null();
|
||||
let start_face = face.children[3];
|
||||
if edge_verts.contains_key(&key) { continue; }
|
||||
|
||||
let new_p = if is_boundary {
|
||||
let p0 = v0.p;
|
||||
let p1 = v1.p;
|
||||
p0 * 0.5 + p1 * 0.5
|
||||
} else {
|
||||
let p0 = v0.p;
|
||||
let p1 = v1.p;
|
||||
let p2 = face.other_vert(v0, v1).p;
|
||||
let f2 = face.f[k];
|
||||
let p3 = f2.other_vert(v0, v1).p;
|
||||
p0 * (3.0 / 8.0) + p1 * (3.0 / 8.0) + p2 * (1.0 / 8.0) + p3 * (1.0 / 8.0)
|
||||
};
|
||||
let is_boundary = faces[fi as usize].f[k] == NULL;
|
||||
let new_vi = verts.len() as u32;
|
||||
|
||||
let vert = arena.alloc(SDVertex {
|
||||
p: new_p,
|
||||
start_face,
|
||||
child: Ptr::null(),
|
||||
regular: true,
|
||||
boundary: is_boundary,
|
||||
});
|
||||
edge_verts.insert(key, vert);
|
||||
new_vertices.push(vert);
|
||||
}
|
||||
let new_p = if is_boundary {
|
||||
Point3f::from(
|
||||
0.5 * Vector3f::from(verts[v0 as usize].p)
|
||||
+ 0.5 * Vector3f::from(verts[v1 as usize].p),
|
||||
)
|
||||
} else {
|
||||
let neighbor_fi = faces[fi as usize].f[k];
|
||||
let other_a = faces[fi as usize].other_vert(v0, v1);
|
||||
let other_b = faces[neighbor_fi as usize].other_vert(v0, v1);
|
||||
Point3f::from(
|
||||
(3.0 / 8.0) * Vector3f::from(verts[v0 as usize].p)
|
||||
+ (3.0 / 8.0) * Vector3f::from(verts[v1 as usize].p)
|
||||
+ (1.0 / 8.0) * Vector3f::from(verts[other_a as usize].p)
|
||||
+ (1.0 / 8.0) * Vector3f::from(verts[other_b as usize].p),
|
||||
)
|
||||
};
|
||||
|
||||
verts.push(SDVertex {
|
||||
p: new_p,
|
||||
start_face: faces[fi as usize].children[3],
|
||||
child: NULL,
|
||||
regular: true,
|
||||
boundary: is_boundary,
|
||||
});
|
||||
new_verts.push(new_vi);
|
||||
edge_verts.insert(key, new_vi);
|
||||
}
|
||||
}
|
||||
|
||||
for &vertex_ptr in &v {
|
||||
let vertex = vertex_ptr;
|
||||
let start_face = vertex.start_face;
|
||||
let vert_num = start_face.vnum(vertex_ptr);
|
||||
let child = vertex.child;
|
||||
let child_start_face = start_face.children[vert_num];
|
||||
child.get_mut().unwrap().start_face = child_start_face;
|
||||
// Snapshot parent arrays before writing into children to avoid
|
||||
// reading stale data from the same Vec.
|
||||
|
||||
// Even vertex start_face pointers
|
||||
for &vi in &old_verts {
|
||||
let sf = verts[vi as usize].start_face;
|
||||
let vnum = faces[sf as usize].vnum(vi);
|
||||
let child = verts[vi as usize].child;
|
||||
verts[child as usize].start_face = faces[sf as usize].children[vnum];
|
||||
}
|
||||
|
||||
for &face_ptr in &f {
|
||||
let face = face_ptr;
|
||||
// Copy the data we need so we don't hold a borrow into the parent
|
||||
// while we mutably borrow its children.
|
||||
let face_children = face.children;
|
||||
let face_f = face.f;
|
||||
let face_v = face.v;
|
||||
// Face neighbor pointers
|
||||
for &fi in &old_faces {
|
||||
let children = faces[fi as usize].children;
|
||||
let face_f = faces[fi as usize].f;
|
||||
let face_v = faces[fi as usize].v;
|
||||
|
||||
for j in 0..3 {
|
||||
let c3 = face_children[3];
|
||||
let c_j = face_children[j];
|
||||
let c_next_j = face_children[next(j)];
|
||||
for j in 0..3usize {
|
||||
// Center child (children[3]) neighbors the three corner children
|
||||
faces[children[3] as usize].f[j] = children[next(j)];
|
||||
faces[children[j] as usize].f[next(j)] = children[3];
|
||||
|
||||
// Sibling links
|
||||
if !c3.is_null() {
|
||||
c3.get_mut().unwrap().f[j] = c_next_j;
|
||||
}
|
||||
if !c_j.is_null() {
|
||||
c_j.get_mut().unwrap().f[next(j)] = c3;
|
||||
}
|
||||
|
||||
// Neighbor links
|
||||
// Corner child j's f[j] = neighbor face's child at the shared vertex
|
||||
let f2 = face_f[j];
|
||||
if !f2.is_null() {
|
||||
let f2_vnum = f2.vnum(face_v[j]);
|
||||
let f2_child = f2.children[f2_vnum];
|
||||
if !c_j.is_null() {
|
||||
c_j.get_mut().unwrap().f[j] = f2_child;
|
||||
}
|
||||
} else if !c_j.is_null() {
|
||||
c_j.get_mut().unwrap().f[j] = Ptr::null();
|
||||
}
|
||||
faces[children[j] as usize].f[j] = if f2 != NULL {
|
||||
let vnum2 = faces[f2 as usize].vnum(face_v[j]);
|
||||
faces[f2 as usize].children[vnum2]
|
||||
} else {
|
||||
NULL
|
||||
};
|
||||
|
||||
let f2_prev = face_f[prev(j)];
|
||||
if !f2_prev.is_null() {
|
||||
let f2_vnum = f2_prev.vnum(face_v[j]);
|
||||
let f2_child = f2_prev.children[f2_vnum];
|
||||
if !c_j.is_null() {
|
||||
c_j.get_mut().unwrap().f[prev(j)] = f2_child;
|
||||
}
|
||||
} else if !c_j.is_null() {
|
||||
c_j.get_mut().unwrap().f[prev(j)] = Ptr::null();
|
||||
}
|
||||
let f2 = face_f[prev(j)];
|
||||
faces[children[j] as usize].f[prev(j)] = if f2 != NULL {
|
||||
let vnum2 = faces[f2 as usize].vnum(face_v[j]);
|
||||
faces[f2 as usize].children[vnum2]
|
||||
} else {
|
||||
NULL
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Update face vertex pointers
|
||||
for &face_ptr in &f {
|
||||
let face = face_ptr;
|
||||
let face_v = face.v;
|
||||
let face_children = face.children;
|
||||
// Face vertex pointers
|
||||
for &fi in &old_faces {
|
||||
let children = faces[fi as usize].children;
|
||||
let face_v = faces[fi as usize].v;
|
||||
|
||||
for j in 0..3 {
|
||||
let v_j_child = face_v[j].child;
|
||||
let c_j = face_children[j];
|
||||
if !c_j.is_null() {
|
||||
c_j.get_mut().unwrap().v[j] = v_j_child;
|
||||
}
|
||||
for j in 0..3usize {
|
||||
let child_v = verts[face_v[j] as usize].child;
|
||||
let edge_v = edge_verts[&EdgeKey::new(face_v[j], face_v[next(j)])];
|
||||
|
||||
let key = canonical_key(face_v[j], face_v[next(j)]);
|
||||
let vert = edge_verts[&key];
|
||||
|
||||
let c_next_j = face_children[next(j)];
|
||||
let c3 = face_children[3];
|
||||
|
||||
if !c_j.is_null() {
|
||||
c_j.get_mut().unwrap().v[next(j)] = vert;
|
||||
}
|
||||
if !c_next_j.is_null() {
|
||||
c_next_j.get_mut().unwrap().v[j] = vert;
|
||||
}
|
||||
if !c3.is_null() {
|
||||
c3.get_mut().unwrap().v[j] = vert;
|
||||
}
|
||||
faces[children[j] as usize].v[j] = child_v;
|
||||
faces[children[j] as usize].v[next(j)] = edge_v;
|
||||
faces[children[next(j)] as usize].v[j] = edge_v;
|
||||
faces[children[3] as usize].v[j] = edge_v;
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare for next level
|
||||
f = new_faces;
|
||||
v = new_vertices;
|
||||
live_verts = new_verts;
|
||||
live_faces = new_faces;
|
||||
}
|
||||
|
||||
let mut p_limit: Vec<Point3f> = Vec::with_capacity(v.len());
|
||||
for &vertex_ptr in &v {
|
||||
let vertex = vertex_ptr;
|
||||
if vertex.boundary {
|
||||
p_limit.push(weight_boundary(vertex_ptr, 1.0 / 5.0));
|
||||
let n_final = live_verts.len();
|
||||
let mut p_limit: Vec<Point3f> = Vec::with_capacity(n_final);
|
||||
|
||||
for &vi in &live_verts {
|
||||
if verts[vi as usize].boundary {
|
||||
p_limit.push(weight_boundary(&verts, &faces, vi, 1.0 / 5.0));
|
||||
} else {
|
||||
let val = valence(vertex_ptr);
|
||||
p_limit.push(weight_one_ring(vertex_ptr, loop_gamma(val)));
|
||||
let val = valence(&verts, &faces, vi);
|
||||
p_limit.push(weight_one_ring(&verts, &faces, vi, loop_gamma(val)));
|
||||
}
|
||||
}
|
||||
for (i, &vertex_ptr) in v.iter().enumerate() {
|
||||
vertex_ptr.get_mut().unwrap().p = p_limit[i];
|
||||
for (i, &vi) in live_verts.iter().enumerate() {
|
||||
verts[vi as usize].p = p_limit[i];
|
||||
}
|
||||
|
||||
let mut ns: Vec<Normal3f> = Vec::with_capacity(v.len());
|
||||
let mut p_ring: Vec<Point3f> = Vec::with_capacity(16);
|
||||
let pi = std::f64::consts::PI as Float;
|
||||
let mut normals: Vec<Normal3f> = Vec::with_capacity(n_final);
|
||||
|
||||
for &vertex_ptr in &v {
|
||||
let vertex = vertex_ptr;
|
||||
let valence = valence(vertex_ptr);
|
||||
p_ring.resize(valence, Point3f::default());
|
||||
one_ring(vertex_ptr, &mut p_ring[..valence]);
|
||||
for &vi in &live_verts {
|
||||
let ring = one_ring(&verts, &faces, vi);
|
||||
let val = ring.len();
|
||||
let vert_p = verts[vi as usize].p;
|
||||
|
||||
let mut s = Vector3f::default();
|
||||
let mut t = Vector3f::default();
|
||||
|
||||
if !vertex.boundary {
|
||||
for j in 0..valence {
|
||||
let angle = 2.0 * std::f64::consts::PI * j as f64 / valence as f64;
|
||||
s += Vector3f::from(p_ring[j]) * angle.cos() as Float;
|
||||
t += Vector3f::from(p_ring[j]) * angle.sin() as Float;
|
||||
let (s, t) = if !verts[vi as usize].boundary {
|
||||
let mut s = Vector3f::default();
|
||||
let mut t = Vector3f::default();
|
||||
for j in 0..val {
|
||||
let angle = 2.0 * pi * j as Float / val as Float;
|
||||
s += angle.cos() * Vector3f::from(ring[j]);
|
||||
t += angle.sin() * Vector3f::from(ring[j]);
|
||||
}
|
||||
(s, t)
|
||||
} else {
|
||||
s = Vector3f::from(p_ring[valence - 1] - p_ring[0]);
|
||||
if valence == 2 {
|
||||
t = Vector3f::from(p_ring[0] + p_ring[1] - vertex_ptr.p * 2.0);
|
||||
} else if valence == 3 {
|
||||
t = Vector3f::from(p_ring[1] - vertex_ptr.p);
|
||||
} else if valence == 4 {
|
||||
t = Vector3f::from(
|
||||
p_ring[0] * -1.0
|
||||
+ p_ring[1] * 2.0
|
||||
+ p_ring[2] * 2.0
|
||||
+ p_ring[3] * -1.0
|
||||
+ vertex_ptr.p * -2.0,
|
||||
);
|
||||
let s = Vector3f::from(ring[val - 1]) - Vector3f::from(ring[0]);
|
||||
let t = if val == 2 {
|
||||
Vector3f::from(ring[0]) + Vector3f::from(ring[1])
|
||||
- 2.0 * Vector3f::from(vert_p)
|
||||
} else if val == 3 {
|
||||
Vector3f::from(ring[1]) - Vector3f::from(vert_p)
|
||||
} else if val == 4 {
|
||||
-1.0 * Vector3f::from(ring[0])
|
||||
+ 2.0 * Vector3f::from(ring[1])
|
||||
+ 2.0 * Vector3f::from(ring[2])
|
||||
- 1.0 * Vector3f::from(ring[3])
|
||||
- 2.0 * Vector3f::from(vert_p)
|
||||
} else {
|
||||
let theta = std::f64::consts::PI / (valence - 1) as f64;
|
||||
t = Vector3f::from(p_ring[0] + p_ring[valence - 1].into()) * theta.sin() as Float;
|
||||
for k in 1..(valence - 1) {
|
||||
let wt = (2.0 * theta.cos() - 2.0) * ((k as f64) * theta).sin();
|
||||
t += Vector3f::from(p_ring[k]) * wt as Float;
|
||||
let theta = pi / (val - 1) as Float;
|
||||
let mut t = theta.sin()
|
||||
* (Vector3f::from(ring[0]) + Vector3f::from(ring[val - 1]));
|
||||
for k in 1..(val - 1) {
|
||||
let wt = (2.0 * theta.cos() - 2.0) * (k as Float * theta).sin();
|
||||
t += wt * Vector3f::from(ring[k]);
|
||||
}
|
||||
t = -t;
|
||||
}
|
||||
}
|
||||
ns.push(Normal3f::from(Vector3f::cross(s, t)));
|
||||
-t
|
||||
};
|
||||
(s, t)
|
||||
};
|
||||
|
||||
normals.push(Normal3f::from(s.cross(t)));
|
||||
}
|
||||
|
||||
let ntris = f.len();
|
||||
let mut verts: Vec<usize> = Vec::with_capacity(3 * ntris);
|
||||
let mut used_verts: HashMap<Ptr<SDVertex>, usize> = HashMap::new();
|
||||
for (i, &vertex_ptr) in v.iter().enumerate() {
|
||||
used_verts.insert(vertex_ptr, i);
|
||||
let mut vert_remap: HashMap<u32, i32> = HashMap::with_capacity(n_final);
|
||||
for (i, &vi) in live_verts.iter().enumerate() {
|
||||
vert_remap.insert(vi, i as i32);
|
||||
}
|
||||
for &face_ptr in &f {
|
||||
let face = face_ptr;
|
||||
|
||||
let mut indices: Vec<i32> = Vec::with_capacity(live_faces.len() * 3);
|
||||
for &fi in &live_faces {
|
||||
for j in 0..3 {
|
||||
verts.push(used_verts[&face.v[j]]);
|
||||
indices.push(vert_remap[&faces[fi as usize].v[j]]);
|
||||
}
|
||||
}
|
||||
|
||||
TriangleMesh::new(
|
||||
render_from_object,
|
||||
reverse_orientation,
|
||||
&verts,
|
||||
&indices,
|
||||
&p_limit,
|
||||
&normals,
|
||||
&[],
|
||||
&ns,
|
||||
&[],
|
||||
&[],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::core::spectrum::SPECTRUM_FILE_CACHE;
|
|||
use crate::core::texture::{FloatTexture, SpectrumTexture};
|
||||
use crate::spectra::data::get_named_spectrum;
|
||||
use crate::spectra::piecewise::ReadFromFile;
|
||||
use crate::utils::FileLoc;
|
||||
use crate::utils::{FileLoc, resolve_filename};
|
||||
use anyhow::{bail, Result};
|
||||
use shared::core::color::RGB;
|
||||
use shared::core::geometry::{Normal3f, Point2f, Point3f, Vector2f, Vector3f};
|
||||
|
|
@ -597,7 +597,13 @@ impl ParameterDictionary {
|
|||
match param.type_name.as_str() {
|
||||
"rgb" | "color" => self.extract_rgb_spectrum(param, spectrum_type),
|
||||
"blackbody" => self.extract_file_spectrum(param),
|
||||
"spectrum" => self.extract_sampled_spectrum(param),
|
||||
"spectrum" => {
|
||||
if !param.strings.is_empty() {
|
||||
self.extract_file_spectrum(param)
|
||||
} else {
|
||||
self.extract_sampled_spectrum(param)
|
||||
}
|
||||
}
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
|
|
@ -695,7 +701,10 @@ impl ParameterDictionary {
|
|||
.map(|s| {
|
||||
get_named_spectrum(s)
|
||||
.ok_or(())
|
||||
.or_else(|_| read_spectrum_from_file(s).map_err(|_| ()))
|
||||
.or_else(|_| {
|
||||
let resolved = resolve_filename(s);
|
||||
read_spectrum_from_file(&resolved).map_err(|_| ())
|
||||
})
|
||||
.unwrap_or_else(|_| panic!("{}: {}: unable to read spectrum", param.loc, s))
|
||||
})
|
||||
.collect()
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ use std::io::{self, Read};
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::Arena;
|
||||
use crate::utils::error::FileLoc;
|
||||
use crate::utils::parameters::{ParameterDictionary, ParsedParameter, ParsedParameterVector};
|
||||
use crate::Arena;
|
||||
use shared::Float;
|
||||
|
||||
pub trait ParserTarget {
|
||||
|
|
@ -886,9 +886,11 @@ impl<'a> SceneParser<'a> {
|
|||
let mut val_type = match type_name {
|
||||
"integer" => ValType::Int,
|
||||
"bool" => ValType::Bool,
|
||||
"float" | "point" | "vector" | "normal" | "color" | "spectrum" | "rgb"
|
||||
| "blackbody" => ValType::Float,
|
||||
"float" | "point" | "vector" | "normal" | "color" | "rgb" | "blackbody" => {
|
||||
ValType::Float
|
||||
}
|
||||
"string" | "texture" => ValType::String,
|
||||
"spectrum" => ValType::Unknown,
|
||||
_ => ValType::Unknown,
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue