Missing SpectrumTextureTrait implementations, placeholders for now. Continuing fixing errors
This commit is contained in:
parent
14418472d5
commit
b6b17a8c7e
60 changed files with 1306 additions and 612 deletions
|
|
@ -428,9 +428,7 @@ impl BxDFTrait for NormalizedFresnelBxDF {
|
||||||
BxDFFlags::REFLECTION | BxDFFlags::DIFFUSE
|
BxDFFlags::REFLECTION | BxDFFlags::DIFFUSE
|
||||||
}
|
}
|
||||||
|
|
||||||
fn regularize(&mut self) {
|
fn regularize(&mut self) {}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn as_any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
|
|
@ -462,9 +460,7 @@ impl BxDFTrait for EmptyBxDF {
|
||||||
BxDFFlags::UNSET
|
BxDFFlags::UNSET
|
||||||
}
|
}
|
||||||
|
|
||||||
fn regularize(&mut self) {
|
fn regularize(&mut self) {}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn as_any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
|
|
|
||||||
|
|
@ -117,9 +117,9 @@ pub struct CameraBase {
|
||||||
pub medium: Ptr<Medium>,
|
pub medium: Ptr<Medium>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[enum_dispatch(CameraTrait)]
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
#[enum_dispatch(CameraTrait)]
|
||||||
pub enum Camera {
|
pub enum Camera {
|
||||||
Perspective(PerspectiveCamera),
|
Perspective(PerspectiveCamera),
|
||||||
Orthographic(OrthographicCamera),
|
Orthographic(OrthographicCamera),
|
||||||
|
|
@ -141,7 +141,7 @@ pub trait CameraTrait {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&*self.base().film
|
&self.base().film
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sample_time(&self, u: Float) -> Float {
|
fn sample_time(&self, u: Float) -> Float {
|
||||||
|
|
|
||||||
|
|
@ -116,9 +116,9 @@ impl RGBFilm {
|
||||||
|
|
||||||
let pixel = &self.pixels[p_film];
|
let pixel = &self.pixels[p_film];
|
||||||
for c in 0..3 {
|
for c in 0..3 {
|
||||||
pixel.rgb_sum[c].add((weight * rgb[c as u32]) as f32);
|
pixel.rgb_sum[c].add(weight * rgb[c as u32]);
|
||||||
}
|
}
|
||||||
pixel.weight_sum.add(weight as f32);
|
pixel.weight_sum.add(weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_splat(&mut self, p: Point2f, l: SampledSpectrum, lambda: &SampledWavelengths) {
|
pub fn add_splat(&mut self, p: Point2f, l: SampledSpectrum, lambda: &SampledWavelengths) {
|
||||||
|
|
@ -353,6 +353,9 @@ pub struct SpectralFilm {
|
||||||
pub bucket_splats: *mut AtomicFloat,
|
pub bucket_splats: *mut AtomicFloat,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for SpectralFilm {}
|
||||||
|
unsafe impl Sync for SpectralFilm {}
|
||||||
|
|
||||||
impl SpectralFilm {
|
impl SpectralFilm {
|
||||||
pub fn base(&self) -> &FilmBase {
|
pub fn base(&self) -> &FilmBase {
|
||||||
&self.base
|
&self.base
|
||||||
|
|
@ -474,7 +477,7 @@ pub struct FilmBase {
|
||||||
pub pixel_bounds: Bounds2i,
|
pub pixel_bounds: Bounds2i,
|
||||||
pub filter: Filter,
|
pub filter: Filter,
|
||||||
pub diagonal: Float,
|
pub diagonal: Float,
|
||||||
pub sensor: *const PixelSensor,
|
pub sensor: Ptr<PixelSensor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|
@ -486,6 +489,9 @@ pub enum Film {
|
||||||
Spectral(SpectralFilm),
|
Spectral(SpectralFilm),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for Film {}
|
||||||
|
unsafe impl Sync for Film {}
|
||||||
|
|
||||||
impl Film {
|
impl Film {
|
||||||
pub fn base(&self) -> &FilmBase {
|
pub fn base(&self) -> &FilmBase {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,7 @@ impl ImageAccess for DeviceImage {
|
||||||
self.base().encoding.to_linear_scalar(raw_u8)
|
self.base().encoding.to_linear_scalar(raw_u8)
|
||||||
}
|
}
|
||||||
Pixels::F16(ptr) => {
|
Pixels::F16(ptr) => {
|
||||||
let half_bits: u16 = *ptr.add(offset as usize) as u16;
|
let half_bits: u16 = *ptr.add(offset as usize);
|
||||||
f16_to_f32(half_bits)
|
f16_to_f32(half_bits)
|
||||||
}
|
}
|
||||||
Pixels::F32(ptr) => *ptr.add(offset as usize),
|
Pixels::F32(ptr) => *ptr.add(offset as usize),
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,11 @@ pub trait PrimitiveTrait {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct GeometricPrimitive {
|
pub struct GeometricPrimitive {
|
||||||
shape: Ptr<Shape>,
|
pub shape: Ptr<Shape>,
|
||||||
material: Ptr<Material>,
|
pub material: Ptr<Material>,
|
||||||
area_light: Ptr<Light>,
|
pub area_light: Ptr<Light>,
|
||||||
medium_interface: MediumInterface,
|
pub medium_interface: MediumInterface,
|
||||||
alpha: Ptr<GPUFloatTexture>,
|
pub alpha: Ptr<GPUFloatTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for GeometricPrimitive {}
|
unsafe impl Send for GeometricPrimitive {}
|
||||||
|
|
@ -91,8 +91,22 @@ impl PrimitiveTrait for GeometricPrimitive {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct SimplePrimitive {
|
pub struct SimplePrimitive {
|
||||||
shape: Ptr<Shape>,
|
pub shape: Ptr<Shape>,
|
||||||
material: Ptr<Material>,
|
pub material: Ptr<Material>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrimitiveTrait for SimplePrimitive {
|
||||||
|
fn bounds(&self) -> Bounds3f {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intersect(&self, r: &Ray, t_max: Option<Float>) -> Option<ShapeIntersection> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intersect_p(&self, r: &Ray, t_max: Option<Float>) -> bool {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -221,6 +235,7 @@ impl PrimitiveTrait for KdTreeAggregate {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[enum_dispatch(PrimitiveTrait)]
|
#[enum_dispatch(PrimitiveTrait)]
|
||||||
pub enum Primitive {
|
pub enum Primitive {
|
||||||
|
Simple(SimplePrimitive),
|
||||||
Geometric(GeometricPrimitive),
|
Geometric(GeometricPrimitive),
|
||||||
Transformed(TransformedPrimitive),
|
Transformed(TransformedPrimitive),
|
||||||
Animated(AnimatedPrimitive),
|
Animated(AnimatedPrimitive),
|
||||||
|
|
|
||||||
|
|
@ -350,7 +350,6 @@ pub enum GPUFloatTexture {
|
||||||
FBm(FBmTexture),
|
FBm(FBmTexture),
|
||||||
Windy(WindyTexture),
|
Windy(WindyTexture),
|
||||||
Wrinkled(WrinkledTexture),
|
Wrinkled(WrinkledTexture),
|
||||||
Ptex(GPUFloatPtexTexture),
|
|
||||||
Image(GPUFloatImageTexture),
|
Image(GPUFloatImageTexture),
|
||||||
Mix(GPUFloatMixTexture),
|
Mix(GPUFloatMixTexture),
|
||||||
}
|
}
|
||||||
|
|
@ -367,7 +366,6 @@ impl GPUFloatTexture {
|
||||||
GPUFloatTexture::FBm(t) => t.evaluate(ctx),
|
GPUFloatTexture::FBm(t) => t.evaluate(ctx),
|
||||||
GPUFloatTexture::Windy(t) => t.evaluate(ctx),
|
GPUFloatTexture::Windy(t) => t.evaluate(ctx),
|
||||||
GPUFloatTexture::Wrinkled(t) => t.evaluate(ctx),
|
GPUFloatTexture::Wrinkled(t) => t.evaluate(ctx),
|
||||||
GPUFloatTexture::Ptex(t) => t.evaluate(ctx),
|
|
||||||
GPUFloatTexture::Image(t) => t.evaluate(ctx),
|
GPUFloatTexture::Image(t) => t.evaluate(ctx),
|
||||||
GPUFloatTexture::Mix(t) => t.evaluate(ctx),
|
GPUFloatTexture::Mix(t) => t.evaluate(ctx),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -392,7 +392,11 @@ impl FilmBaseHost for FilmBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FilmHost {
|
#[enum_dispatch]
|
||||||
|
pub trait FilmTrait: Sync {
|
||||||
|
fn base(&self) -> &FilmBase;
|
||||||
|
fn get_pixel_rgb(&self, p: Point2i, splat_scale: Option<Float>) -> RGB;
|
||||||
|
fn get_filename(&self) -> &str;
|
||||||
fn write_image(&self, metadata: &ImageMetadata, splat_scale: Float) {
|
fn write_image(&self, metadata: &ImageMetadata, splat_scale: Float) {
|
||||||
let image = self.get_image(metadata, splat_scale);
|
let image = self.get_image(metadata, splat_scale);
|
||||||
image
|
image
|
||||||
|
|
@ -472,7 +476,32 @@ pub trait FilmHost {
|
||||||
|
|
||||||
image
|
image
|
||||||
}
|
}
|
||||||
fn get_filename(&self) -> &str;
|
}
|
||||||
|
|
||||||
|
impl FilmTrait for Film {
|
||||||
|
fn base(&self) -> &FilmBase {
|
||||||
|
match self {
|
||||||
|
Film::RGB(f) => &f.base,
|
||||||
|
Film::GBuffer(f) => &f.base,
|
||||||
|
Film::Spectral(f) => &f.base,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_pixel_rgb(&self, p: Point2i, splat_scale: Option<Float>) -> RGB {
|
||||||
|
match self {
|
||||||
|
Film::RGB(f) => f.get_pixel_rgb(p, splat_scale),
|
||||||
|
Film::GBuffer(f) => f.get_pixel_rgb(p, splat_scale),
|
||||||
|
Film::Spectral(f) => f.get_pixel_rgb(p, splat_scale),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_filename(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Film::RGB(f) => &f.filename,
|
||||||
|
Film::GBuffer(f) => &f.filename,
|
||||||
|
Film::Spectral(f) => &f.filename,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FilmFactory {
|
pub trait FilmFactory {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::utils::containers::Array2D;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use half::f16;
|
use half::f16;
|
||||||
use shared::Float;
|
use shared::Float;
|
||||||
|
|
@ -5,7 +6,6 @@ use shared::core::color::ColorEncoding;
|
||||||
use shared::core::color::LINEAR;
|
use shared::core::color::LINEAR;
|
||||||
use shared::core::geometry::{Bounds2f, Point2f, Point2i};
|
use shared::core::geometry::{Bounds2f, Point2f, Point2i};
|
||||||
use shared::core::image::{DeviceImage, ImageBase, PixelFormat, Pixels, WrapMode, WrapMode2D};
|
use shared::core::image::{DeviceImage, ImageBase, PixelFormat, Pixels, WrapMode, WrapMode2D};
|
||||||
use shared::utils::containers::DeviceArray2D;
|
|
||||||
use shared::utils::math::square;
|
use shared::utils::math::square;
|
||||||
use smallvec::{SmallVec, smallvec};
|
use smallvec::{SmallVec, smallvec};
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
@ -470,14 +470,14 @@ impl Image {
|
||||||
Self::from_storage(new_storage, res, new_names, self.encoding())
|
Self::from_storage(new_storage, res, new_names, self.encoding())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_sampling_distribution<F>(&self, dxd_a: F, domain: Bounds2f) -> DeviceArray2D<Float>
|
pub fn get_sampling_distribution<F>(&self, dxd_a: F, domain: Bounds2f) -> Array2D<Float>
|
||||||
where
|
where
|
||||||
F: Fn(Point2f) -> Float + Sync + Send,
|
F: Fn(Point2f) -> Float + Sync + Send,
|
||||||
{
|
{
|
||||||
let width = self.resolution().x();
|
let width = self.resolution().x();
|
||||||
let height = self.resolution().y();
|
let height = self.resolution().y();
|
||||||
|
|
||||||
let mut dist = DeviceArray2D::new_with_dims(width as usize, height as usize);
|
let mut dist = Array2D::new_dims(width, height);
|
||||||
|
|
||||||
dist.values
|
dist.values
|
||||||
.par_chunks_mut(width as usize)
|
.par_chunks_mut(width as usize)
|
||||||
|
|
@ -500,7 +500,7 @@ impl Image {
|
||||||
dist
|
dist
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_sampling_distribution_uniform(&self) -> DeviceArray2D<Float> {
|
pub fn get_sampling_distribution_uniform(&self) -> Array2D<Float> {
|
||||||
let default_domain = Bounds2f::from_points(Point2f::new(0.0, 0.0), Point2f::new(1.0, 1.0));
|
let default_domain = Bounds2f::from_points(Point2f::new(0.0, 0.0), Point2f::new(1.0, 1.0));
|
||||||
|
|
||||||
self.get_sampling_distribution(|_| 1.0, default_domain)
|
self.get_sampling_distribution(|_| 1.0, default_domain)
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,21 @@
|
||||||
use shared::core::light::Light;
|
|
||||||
use crate::core::spectrum::SPECTRUM_CACHE;
|
use crate::core::spectrum::SPECTRUM_CACHE;
|
||||||
use crate::core::texture::FloatTexture;
|
use crate::core::texture::FloatTexture;
|
||||||
|
use crate::spectra::DenselySampledSpectrumBuffer;
|
||||||
use crate::utils::containers::InternCache;
|
use crate::utils::containers::InternCache;
|
||||||
use crate::utils::{Arena, FileLoc, ParameterDictionary};
|
use crate::utils::{Arena, FileLoc, ParameterDictionary};
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
use shared::core::camera::CameraTransform;
|
use shared::core::camera::CameraTransform;
|
||||||
|
use shared::core::light::Light;
|
||||||
use shared::core::medium::Medium;
|
use shared::core::medium::Medium;
|
||||||
use shared::core::shape::Shape;
|
use shared::core::shape::Shape;
|
||||||
use shared::core::spectrum::Spectrum;
|
use shared::core::spectrum::Spectrum;
|
||||||
use shared::lights::*;
|
use shared::lights::*;
|
||||||
use shared::spectra::{DenselySampledSpectrum, RGBColorSpace};
|
use shared::spectra::RGBColorSpace;
|
||||||
use shared::utils::Transform;
|
use shared::utils::Transform;
|
||||||
|
|
||||||
pub fn lookup_spectrum(s: &Spectrum) -> DenselySampledSpectrum {
|
pub fn lookup_spectrum(s: &Spectrum) -> DenselySampledSpectrumBuffer {
|
||||||
let cache = SPECTRUM_CACHE.get_or_init(InternCache::new);
|
let cache = SPECTRUM_CACHE.get_or_init(InternCache::new);
|
||||||
let dense_spectrum = DenselySampledSpectrum::from_spectrum(s);
|
let dense_spectrum = DenselySampledSpectrumBuffer::from_spectrum(s);
|
||||||
cache.lookup(dense_spectrum).as_ref()
|
cache.lookup(dense_spectrum).as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,42 +40,46 @@ impl MaterialFactory for Material {
|
||||||
) -> Result<Material> {
|
) -> Result<Material> {
|
||||||
match name {
|
match name {
|
||||||
"diffuse" => {
|
"diffuse" => {
|
||||||
DiffuseMaterial::create(parameters, normal_map, named_materials, loc, arena)?
|
DiffuseMaterial::create(parameters, normal_map, &named_materials, &loc, arena)
|
||||||
}
|
}
|
||||||
"coateddiffuse" => {
|
"coateddiffuse" => {
|
||||||
CoatedDiffuseMaterial::create(parameters, normal_map, named_materials, loc, arena)?
|
CoatedDiffuseMaterial::create(parameters, normal_map, &named_materials, &loc, arena)
|
||||||
}
|
}
|
||||||
"coatedconductor" => CoatedConductorMaterial::create(
|
"coatedconductor" => CoatedConductorMaterial::create(
|
||||||
parameters,
|
parameters,
|
||||||
normal_map,
|
normal_map,
|
||||||
named_materials,
|
&named_materials,
|
||||||
loc,
|
&loc,
|
||||||
arena,
|
arena,
|
||||||
)?,
|
),
|
||||||
"diffusetransmission" => DiffuseTransmissionMaterial::create(
|
"diffusetransmission" => DiffuseTransmissionMaterial::create(
|
||||||
parameters,
|
parameters,
|
||||||
normal_map,
|
normal_map,
|
||||||
named_materials,
|
&named_materials,
|
||||||
loc,
|
&loc,
|
||||||
arena,
|
arena,
|
||||||
)?,
|
),
|
||||||
"dielectric" => {
|
"dielectric" => {
|
||||||
DielectricMaterial::create(parameters, normal_map, named_materials, loc, arena)?
|
DielectricMaterial::create(parameters, normal_map, &named_materials, &loc, arena)
|
||||||
}
|
}
|
||||||
"thindielectric" => {
|
"thindielectric" => ThinDielectricMaterial::create(
|
||||||
ThinDielectricMaterial::create(parameters, normal_map, named_materials, loc, arena)?
|
parameters,
|
||||||
}
|
normal_map,
|
||||||
"hair" => HairMaterial::create(parameters, normal_map, named_materials, loc, arena)?,
|
&named_materials,
|
||||||
|
&loc,
|
||||||
|
arena,
|
||||||
|
),
|
||||||
|
"hair" => HairMaterial::create(parameters, normal_map, &named_materials, &loc, arena),
|
||||||
"conductor" => {
|
"conductor" => {
|
||||||
ConductorMaterial::create(parameters, normal_map, named_materials, loc, arena)?
|
ConductorMaterial::create(parameters, normal_map, &named_materials, &loc, arena)
|
||||||
}
|
}
|
||||||
"measured" => {
|
"measured" => {
|
||||||
MeasuredMaterial::create(parameters, normal_map, named_materials, loc, arena)?
|
MeasuredMaterial::create(parameters, normal_map, &named_materials, &loc, arena)
|
||||||
}
|
}
|
||||||
"subsurface" => {
|
"subsurface" => {
|
||||||
SubsurfaceMaterial::create(parameters, normal_map, named_materials, loc, arena)?
|
SubsurfaceMaterial::create(parameters, normal_map, &named_materials, &loc, arena)
|
||||||
}
|
}
|
||||||
"mix" => MixMaterial::create(parameters, normal_map, named_materials, loc, arena)?,
|
"mix" => MixMaterial::create(parameters, normal_map, &named_materials, &loc, arena),
|
||||||
|
|
||||||
_ => Err(anyhow!("Material type '{}' unknown at {}", $name, $loc)),
|
_ => Err(anyhow!("Material type '{}' unknown at {}", $name, $loc)),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::spectra::dense::DenselySampledSpectrumBuffer;
|
use crate::spectra::dense::DenselySampledSpectrumBuffer;
|
||||||
use shared::core::geometry::{Bounds3f, Point3i};
|
use shared::core::geometry::{Bounds3f, Point3i};
|
||||||
use shared::core::medium::{GridMedium, HGPhaseFunction, HomogeneousMedium, RGBGridMedium};
|
use shared::core::medium::{GridMedium, HGPhaseFunction, HomogeneousMedium, RGBGridMedium};
|
||||||
use shared::core::spectrum::Spectrum;
|
use shared::core::spectrum::{Spectrum, SpectrumTrait};
|
||||||
use shared::spectra::{DenselySampledSpectrum, RGBIlluminantSpectrum, RGBUnboundedSpectrum};
|
use shared::spectra::{DenselySampledSpectrum, RGBIlluminantSpectrum, RGBUnboundedSpectrum};
|
||||||
use shared::utils::Transform;
|
use shared::utils::Transform;
|
||||||
use shared::utils::containers::SampledGrid;
|
use shared::utils::containers::SampledGrid;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ pub mod image;
|
||||||
pub mod light;
|
pub mod light;
|
||||||
pub mod material;
|
pub mod material;
|
||||||
pub mod medium;
|
pub mod medium;
|
||||||
|
pub mod primitive;
|
||||||
pub mod sampler;
|
pub mod sampler;
|
||||||
pub mod sampler;
|
pub mod sampler;
|
||||||
pub mod scene;
|
pub mod scene;
|
||||||
|
|
|
||||||
40
src/core/primitive.rs
Normal file
40
src/core/primitive.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
use shared::core::{
|
||||||
|
light::Light,
|
||||||
|
material::{self, Material},
|
||||||
|
medium::MediumInterface,
|
||||||
|
primitive::{GeometricPrimitive, SimplePrimitive},
|
||||||
|
shape::Shape,
|
||||||
|
};
|
||||||
|
|
||||||
|
use shared::utils::Ptr;
|
||||||
|
|
||||||
|
use crate::core::texture::FloatTexture;
|
||||||
|
|
||||||
|
pub trait CreateSimplePrimitive {
|
||||||
|
fn new(shape: Ptr<Shape>, material: Ptr<Material>) -> SimplePrimitive {
|
||||||
|
SimplePrimitive { shape, material }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreateSimplePrimitive for SimplePrimitive {}
|
||||||
|
|
||||||
|
pub trait CreateGeometricPrimitive {
|
||||||
|
fn new(
|
||||||
|
shape: Ptr<Shape>,
|
||||||
|
material: Ptr<Material>,
|
||||||
|
area_light: Ptr<Light>,
|
||||||
|
medium_interface: MediumInterface,
|
||||||
|
alpha: Ptr<GPUFloatTexture>,
|
||||||
|
) -> GeometricPrimitive {
|
||||||
|
GeometricPrimitive {
|
||||||
|
shape,
|
||||||
|
material,
|
||||||
|
area_light,
|
||||||
|
medium_interface,
|
||||||
|
alpha,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreateGeometricPrimitive for GeometricPrimitive {}
|
||||||
|
|
||||||
|
|
@ -3,7 +3,7 @@ use crate::utils::{FileLoc, ParameterDictionary};
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
use shared::core::geometry::Point2i;
|
use shared::core::geometry::Point2i;
|
||||||
use shared::core::sampler::{
|
use shared::core::sampler::{
|
||||||
HaltonSampler, IndependentSampler, PaddedSobolSampler, Sampler, SobolSampler,
|
HaltonSampler, IndependentSampler, PaddedSobolSampler, Sampler, SamplerTrait, SobolSampler,
|
||||||
StratifiedSampler, ZSobolSampler,
|
StratifiedSampler, ZSobolSampler,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -553,7 +553,7 @@ impl ParserTarget for BasicSceneBuilder {
|
||||||
&mut self.spectrum_texture_names
|
&mut self.spectrum_texture_names
|
||||||
};
|
};
|
||||||
|
|
||||||
if names.contains(name) {
|
if names.contains(&name) {
|
||||||
self.error_exit_deferred(&loc, &format!("Redefining texture \"{}\".", name));
|
self.error_exit_deferred(&loc, &format!("Redefining texture \"{}\".", name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -561,7 +561,7 @@ impl ParserTarget for BasicSceneBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
let base = SceneEntity {
|
let base = SceneEntity {
|
||||||
name: tex_name,
|
name: tex_name.to_string(),
|
||||||
parameters: dict,
|
parameters: dict,
|
||||||
loc,
|
loc,
|
||||||
};
|
};
|
||||||
|
|
@ -578,9 +578,9 @@ impl ParserTarget for BasicSceneBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn material(&mut self, name: &str, params: &ParsedParameterVector, loc: FileLoc) {
|
fn material(&mut self, name: &str, params: &ParsedParameterVector, loc: FileLoc) {
|
||||||
self.verify_world("material", loc);
|
self.verify_world("material", &loc);
|
||||||
let entity = SceneEntity {
|
let entity = SceneEntity {
|
||||||
name,
|
name: name.to_string(),
|
||||||
loc,
|
loc,
|
||||||
parameters: params,
|
parameters: params,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,14 @@
|
||||||
use super::entities::*;
|
use super::entities::*;
|
||||||
use super::state::*;
|
use super::state::*;
|
||||||
|
use crate::core::camera::CameraFactory;
|
||||||
use crate::core::filter::FilterFactory;
|
use crate::core::filter::FilterFactory;
|
||||||
use crate::core::image::{Image, io::ImageIO};
|
use crate::core::image::{Image, io::ImageIO};
|
||||||
use crate::core::material::MaterialFactory;
|
use crate::core::material::MaterialFactory;
|
||||||
|
use crate::core::primitive::{CreateGeometricPrimitive, CreateSimplePrimitive};
|
||||||
|
use crate::core::sampler::SamplerFactory;
|
||||||
|
use crate::core::shape::ShapeFactory;
|
||||||
use crate::core::texture::{FloatTexture, SpectrumTexture};
|
use crate::core::texture::{FloatTexture, SpectrumTexture};
|
||||||
|
use crate::utils::arena;
|
||||||
use crate::utils::arena::Arena;
|
use crate::utils::arena::Arena;
|
||||||
use crate::utils::error::FileLoc;
|
use crate::utils::error::FileLoc;
|
||||||
use crate::utils::parallel::run_async;
|
use crate::utils::parallel::run_async;
|
||||||
|
|
@ -13,6 +18,7 @@ use parking_lot::Mutex;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use shared::core::camera::Camera;
|
use shared::core::camera::Camera;
|
||||||
use shared::core::color::ColorEncoding;
|
use shared::core::color::ColorEncoding;
|
||||||
|
use shared::core::color::LINEAR;
|
||||||
use shared::core::film::Film;
|
use shared::core::film::Film;
|
||||||
use shared::core::filter::Filter;
|
use shared::core::filter::Filter;
|
||||||
use shared::core::light::Light;
|
use shared::core::light::Light;
|
||||||
|
|
@ -142,7 +148,7 @@ impl BasicScene {
|
||||||
let sampler_film = Arc::clone(&film_instance);
|
let sampler_film = Arc::clone(&film_instance);
|
||||||
let sampler_job = run_async(move || {
|
let sampler_job = run_async(move || {
|
||||||
let res = sampler_film.as_ref().base().full_resolution;
|
let res = sampler_film.as_ref().base().full_resolution;
|
||||||
Sampler::create(&sampler.name, &sampler.parameters, res, &sampler.loc)
|
Sampler::create(&sampler.name, &sampler.parameters, res, &sampler.loc, arena)
|
||||||
.expect("Sampler was not correctly created")
|
.expect("Sampler was not correctly created")
|
||||||
});
|
});
|
||||||
self.sampler_state.lock().job = Some(sampler_job);
|
self.sampler_state.lock().job = Some(sampler_job);
|
||||||
|
|
@ -154,10 +160,11 @@ impl BasicScene {
|
||||||
Camera::create(
|
Camera::create(
|
||||||
&camera.base.name,
|
&camera.base.name,
|
||||||
&camera.base.parameters,
|
&camera.base.parameters,
|
||||||
medium,
|
|
||||||
&camera.camera_transform,
|
&camera.camera_transform,
|
||||||
|
medium,
|
||||||
camera_film,
|
camera_film,
|
||||||
&camera.base.loc,
|
&camera.base.loc,
|
||||||
|
arena,
|
||||||
)
|
)
|
||||||
.expect("Failed to create camera")
|
.expect("Failed to create camera")
|
||||||
});
|
});
|
||||||
|
|
@ -221,15 +228,19 @@ impl BasicScene {
|
||||||
|
|
||||||
let texture_clone = texture.clone();
|
let texture_clone = texture.clone();
|
||||||
let job = run_async(move || {
|
let job = run_async(move || {
|
||||||
let render_from_texture = texture_clone.render_from_object.start_transform();
|
let render_from_texture = texture_clone.render_from_object.start_transform;
|
||||||
let tex_dict = TextureParameterDictionary::new(&texture_clone.base.parameters, None);
|
let tex_dict =
|
||||||
|
TextureParameterDictionary::new(texture_clone.base.parameters.into(), None);
|
||||||
Arc::new(FloatTexture::create(
|
let texture = FloatTexture::create(
|
||||||
&texture_clone.base.name,
|
&texture_clone.base.name,
|
||||||
&render_from_texture,
|
&render_from_texture,
|
||||||
&tex_dict,
|
tex_dict,
|
||||||
&texture_clone.base.loc,
|
texture_clone.base.loc,
|
||||||
))
|
arena,
|
||||||
|
)
|
||||||
|
.expect("Could not create Float texture");
|
||||||
|
|
||||||
|
Arc::new(texture)
|
||||||
});
|
});
|
||||||
|
|
||||||
state.float_texture_jobs.insert(name, job);
|
state.float_texture_jobs.insert(name, job);
|
||||||
|
|
@ -275,16 +286,20 @@ impl BasicScene {
|
||||||
|
|
||||||
let texture_clone = texture.clone();
|
let texture_clone = texture.clone();
|
||||||
let job = run_async(move || {
|
let job = run_async(move || {
|
||||||
let render_from_texture = texture_clone.render_from_object.start_transform();
|
let render_from_texture = texture_clone.render_from_object.start_transform;
|
||||||
let tex_dict = TextureParameterDictionary::new(&texture_clone.base.parameters, None);
|
let tex_dict =
|
||||||
|
TextureParameterDictionary::new(texture_clone.base.parameters.into(), None);
|
||||||
Arc::new(SpectrumTexture::create(
|
let texture = SpectrumTexture::create(
|
||||||
&texture_clone.base.name,
|
&texture_clone.base.name,
|
||||||
&render_from_texture,
|
&render_from_texture,
|
||||||
&tex_dict,
|
tex_dict,
|
||||||
SpectrumType::Albedo,
|
SpectrumType::Albedo,
|
||||||
&texture_clone.base.loc,
|
texture_clone.base.loc,
|
||||||
))
|
arena,
|
||||||
|
)
|
||||||
|
.expect("Could not crate spectrum texture.");
|
||||||
|
|
||||||
|
Arc::new(texture)
|
||||||
});
|
});
|
||||||
|
|
||||||
state.spectrum_texture_jobs.insert(name, job);
|
state.spectrum_texture_jobs.insert(name, job);
|
||||||
|
|
@ -337,37 +352,47 @@ impl BasicScene {
|
||||||
// Create serial textures (need access to already-loaded textures)
|
// Create serial textures (need access to already-loaded textures)
|
||||||
let named = NamedTextures {
|
let named = NamedTextures {
|
||||||
float_textures: float_textures.clone(),
|
float_textures: float_textures.clone(),
|
||||||
spectrum_textures: spectrum_textures.clone(),
|
albedo_spectrum_textures: spectrum_textures.clone(),
|
||||||
|
illuminant_spectrum_textures: spectrum_textures.clone(),
|
||||||
|
unbounded_spectrum_textures: spectrum_textures.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (name, entity) in state.serial_float_textures.drain(..) {
|
for (name, entity) in state.serial_float_textures.drain(..) {
|
||||||
let render_from_texture = entity.render_from_object.start_transform();
|
let render_from_texture = entity.render_from_object.start_transform;
|
||||||
let tex_dict = TextureParameterDictionary::new(&entity.base.parameters, Some(&named));
|
let tex_dict =
|
||||||
|
TextureParameterDictionary::new(entity.base.parameters.into(), Some(named));
|
||||||
let tex = FloatTexture::create(
|
let tex = FloatTexture::create(
|
||||||
&entity.base.name,
|
&entity.base.name,
|
||||||
&render_from_texture,
|
render_from_texture,
|
||||||
&tex_dict,
|
tex_dict,
|
||||||
&entity.base.loc,
|
entity.base.loc,
|
||||||
);
|
arena,
|
||||||
|
)
|
||||||
|
.expect("Could not create float texture");
|
||||||
float_textures.insert(name, Arc::new(tex));
|
float_textures.insert(name, Arc::new(tex));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, entity) in state.serial_spectrum_textures.drain(..) {
|
for (name, entity) in state.serial_spectrum_textures.drain(..) {
|
||||||
let render_from_texture = entity.render_from_object.start_transform();
|
let render_from_texture = entity.render_from_object.start_transform;
|
||||||
let tex_dict = TextureParameterDictionary::new(&entity.base.parameters, Some(&named));
|
let tex_dict =
|
||||||
|
TextureParameterDictionary::new(entity.base.parameters.into(), Some(named));
|
||||||
let tex = SpectrumTexture::create(
|
let tex = SpectrumTexture::create(
|
||||||
&entity.base.name,
|
&entity.base.name,
|
||||||
&render_from_texture,
|
render_from_texture,
|
||||||
&tex_dict,
|
tex_dict,
|
||||||
SpectrumType::Albedo,
|
SpectrumType::Albedo,
|
||||||
&entity.base.loc,
|
entity.base.loc,
|
||||||
);
|
arena,
|
||||||
|
)
|
||||||
|
.expect("Could not create spectrum texture");
|
||||||
spectrum_textures.insert(name, Arc::new(tex));
|
spectrum_textures.insert(name, Arc::new(tex));
|
||||||
}
|
}
|
||||||
|
|
||||||
NamedTextures {
|
NamedTextures {
|
||||||
float_textures,
|
float_textures,
|
||||||
spectrum_textures,
|
albedo_spectrum_textures: spectrum_textures,
|
||||||
|
unbounded_spectrum_textures: spectrum_textures,
|
||||||
|
illuminant_spectrum_textures: spectrum_textures,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -410,15 +435,18 @@ impl BasicScene {
|
||||||
}
|
}
|
||||||
|
|
||||||
let normal_map = self.get_normal_map(&state, &entity.parameters);
|
let normal_map = self.get_normal_map(&state, &entity.parameters);
|
||||||
let tex_dict = TextureParameterDictionary::new(&entity.parameters, Some(textures));
|
let tex_dict =
|
||||||
|
TextureParameterDictionary::new(entity.parameters.into(), Some(*textures));
|
||||||
|
|
||||||
let mat = Material::create(
|
let mat = Material::create(
|
||||||
&mat_type,
|
&mat_type,
|
||||||
&tex_dict,
|
&tex_dict,
|
||||||
normal_map,
|
normal_map,
|
||||||
&named_materials,
|
named_materials,
|
||||||
&entity.loc,
|
entity.loc,
|
||||||
);
|
arena,
|
||||||
|
)
|
||||||
|
.expect("Could not create material");
|
||||||
|
|
||||||
named_materials.insert(name.clone(), mat);
|
named_materials.insert(name.clone(), mat);
|
||||||
}
|
}
|
||||||
|
|
@ -427,25 +455,24 @@ impl BasicScene {
|
||||||
|
|
||||||
for entity in &state.materials {
|
for entity in &state.materials {
|
||||||
let normal_map = self.get_normal_map(&state, &entity.parameters);
|
let normal_map = self.get_normal_map(&state, &entity.parameters);
|
||||||
let tex_dict = TextureParameterDictionary::new(&entity.parameters, Some(textures));
|
let tex_dict =
|
||||||
|
TextureParameterDictionary::new(entity.parameters.into(), Some(*textures));
|
||||||
|
|
||||||
let mat = Material::create(
|
let mat = Material::create(
|
||||||
&entity.name,
|
&entity.name,
|
||||||
&tex_dict,
|
&tex_dict,
|
||||||
normal_map,
|
normal_map,
|
||||||
&named_materials,
|
named_materials,
|
||||||
&entity.loc,
|
entity.loc,
|
||||||
);
|
arena,
|
||||||
|
)
|
||||||
|
.expect("Could not create material");
|
||||||
materials.push(mat);
|
materials.push(mat);
|
||||||
}
|
}
|
||||||
|
|
||||||
(named_materials, materials)
|
(named_materials, materials)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================================================================
|
|
||||||
// Finalization: Aggregate
|
|
||||||
// ========================================================================
|
|
||||||
|
|
||||||
pub fn create_aggregate(
|
pub fn create_aggregate(
|
||||||
&self,
|
&self,
|
||||||
arena: &mut Arena,
|
arena: &mut Arena,
|
||||||
|
|
@ -494,12 +521,13 @@ impl BasicScene {
|
||||||
.map(|sh| {
|
.map(|sh| {
|
||||||
Shape::create(
|
Shape::create(
|
||||||
&sh.base.name,
|
&sh.base.name,
|
||||||
sh.render_from_object.as_ref(),
|
*sh.render_from_object.as_ref(),
|
||||||
sh.object_from_render.as_ref(),
|
*sh.object_from_render.as_ref(),
|
||||||
sh.reverse_orientation,
|
sh.reverse_orientation,
|
||||||
&sh.base.parameters,
|
sh.base.parameters,
|
||||||
&lookup.textures.float_textures,
|
lookup.textures.float_textures,
|
||||||
&sh.base.loc,
|
sh.base.loc,
|
||||||
|
arena,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|
@ -515,12 +543,13 @@ impl BasicScene {
|
||||||
.map(|sh| {
|
.map(|sh| {
|
||||||
Shape::create(
|
Shape::create(
|
||||||
&sh.transformed_base.base.name,
|
&sh.transformed_base.base.name,
|
||||||
sh.identity.as_ref(),
|
*sh.identity.as_ref(),
|
||||||
sh.identity.as_ref(),
|
*sh.identity.as_ref(),
|
||||||
sh.reverse_orientation,
|
sh.reverse_orientation,
|
||||||
&sh.transformed_base.base.parameters,
|
sh.transformed_base.base.parameters,
|
||||||
&lookup.textures.float_textures,
|
lookup.textures.float_textures,
|
||||||
&sh.transformed_base.base.loc,
|
sh.transformed_base.base.loc,
|
||||||
|
arena,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|
@ -546,11 +575,19 @@ impl BasicScene {
|
||||||
&lookup.textures.float_textures,
|
&lookup.textures.float_textures,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mtl = lookup.resolve_material(&entity.material, &entity.base.loc);
|
let mtl = lookup
|
||||||
|
.resolve_material(&entity.material, &entity.base.loc)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let mi = MediumInterface::new(
|
let mi = MediumInterface::new(
|
||||||
lookup.find_medium(&entity.inside_medium, &entity.base.loc),
|
lookup
|
||||||
lookup.find_medium(&entity.outside_medium, &entity.base.loc),
|
.find_medium(&entity.inside_medium, &entity.base.loc)
|
||||||
|
.unwrap()
|
||||||
|
.as_ref(),
|
||||||
|
lookup
|
||||||
|
.find_medium(&entity.outside_medium, &entity.base.loc)
|
||||||
|
.unwrap()
|
||||||
|
.as_ref(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let shape_lights_opt = lookup.shape_lights.get(&i);
|
let shape_lights_opt = lookup.shape_lights.get(&i);
|
||||||
|
|
@ -569,17 +606,17 @@ impl BasicScene {
|
||||||
|
|
||||||
let prim =
|
let prim =
|
||||||
if area_light.is_none() && !mi.is_medium_transition() && alpha_tex.is_none() {
|
if area_light.is_none() && !mi.is_medium_transition() && alpha_tex.is_none() {
|
||||||
let p = SimplePrimitive::new(shape_ptr, mtl);
|
let p = SimplePrimitive::new(shape_ptr, Ptr::from(&mtl));
|
||||||
Primitive::Simple(arena.alloc(p))
|
Primitive::Simple(p)
|
||||||
} else {
|
} else {
|
||||||
let p = GeometricPrimitive::new(
|
let p = GeometricPrimitive::new(
|
||||||
shape_ptr,
|
shape_ptr,
|
||||||
mtl,
|
Ptr::from(&mtl),
|
||||||
area_light,
|
area_light,
|
||||||
mi.clone(),
|
mi.clone(),
|
||||||
alpha_tex.clone(),
|
alpha_tex.clone(),
|
||||||
);
|
);
|
||||||
Primitive::Geometric(arena.alloc(p))
|
Primitive::Geometric(p)
|
||||||
};
|
};
|
||||||
|
|
||||||
primitives.push(prim);
|
primitives.push(prim);
|
||||||
|
|
@ -617,7 +654,7 @@ impl BasicScene {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
// Private helpers
|
// Helpers
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
||||||
fn get_singleton<T: Send + 'static>(
|
fn get_singleton<T: Send + 'static>(
|
||||||
|
|
@ -655,18 +692,18 @@ impl BasicScene {
|
||||||
let filename_clone = filename.clone();
|
let filename_clone = filename.clone();
|
||||||
let job = run_async(move || {
|
let job = run_async(move || {
|
||||||
let path = std::path::Path::new(&filename_clone);
|
let path = std::path::Path::new(&filename_clone);
|
||||||
let immeta = Image::read(path, Some(ColorEncoding::Linear))
|
let immeta = Image::read(path, Some(LINEAR)).expect(&format!(
|
||||||
.unwrap_or_else(|e| panic!("{}: unable to read normal map: {}", filename_clone, e));
|
"{}: normal map must contain R, G, B channels",
|
||||||
|
filename_clone
|
||||||
|
));
|
||||||
|
|
||||||
let rgb_desc = immeta
|
let rgb_desc = immeta
|
||||||
.image
|
.image
|
||||||
.get_channel_desc(&["R", "G", "B"])
|
.get_channel_desc(&["R", "G", "B"])
|
||||||
.unwrap_or_else(|| {
|
.expect(&format!(
|
||||||
panic!(
|
|
||||||
"{}: normal map must contain R, G, B channels",
|
"{}: normal map must contain R, G, B channels",
|
||||||
filename_clone
|
filename_clone
|
||||||
)
|
));
|
||||||
});
|
|
||||||
|
|
||||||
Arc::new(immeta.image.select_channels(&rgb_desc))
|
Arc::new(immeta.image.select_channels(&rgb_desc))
|
||||||
});
|
});
|
||||||
|
|
@ -692,21 +729,21 @@ impl BasicScene {
|
||||||
loc: &FileLoc,
|
loc: &FileLoc,
|
||||||
textures: &HashMap<String, Arc<FloatTexture>>,
|
textures: &HashMap<String, Arc<FloatTexture>>,
|
||||||
) -> Option<Arc<FloatTexture>> {
|
) -> Option<Arc<FloatTexture>> {
|
||||||
if let Some(name) = params.get_texture("alpha") {
|
let name = params.get_texture("alpha");
|
||||||
match textures.get(&name) {
|
match textures.get(&name) {
|
||||||
Some(tex) => Some(tex.clone()),
|
Some(tex) => Some(tex.clone()),
|
||||||
None => panic!("{:?}: Alpha texture '{}' not found", loc, name),
|
None => panic!("{:?}: Alpha texture '{}' not found", loc, name),
|
||||||
}
|
}
|
||||||
} else {
|
// } else {
|
||||||
let alpha_val = params.get_one_float("alpha", 1.0);
|
// let alpha_val = params.get_one_float("alpha", 1.0);
|
||||||
if alpha_val < 1.0 {
|
// if alpha_val < 1.0 {
|
||||||
Some(Arc::new(FloatTexture::Constant(FloatConstantTexture::new(
|
// Some(Arc::new(FloatTexture::Constant(FloatConstantTexture::new(
|
||||||
alpha_val,
|
// alpha_val,
|
||||||
))))
|
// ))))
|
||||||
} else {
|
// } else {
|
||||||
None
|
// None
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_medium(&self, name: &str, loc: &FileLoc) -> Option<Arc<Medium>> {
|
pub fn get_medium(&self, name: &str, loc: &FileLoc) -> Option<Arc<Medium>> {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use shared::core::options::get_options;
|
||||||
use shared::core::shape::*;
|
use shared::core::shape::*;
|
||||||
use shared::shapes::*;
|
use shared::shapes::*;
|
||||||
// use shared::spectra::*;
|
// use shared::spectra::*;
|
||||||
|
use anyhow::Result;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use shared::utils::Transform;
|
use shared::utils::Transform;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
@ -19,10 +20,10 @@ pub trait CreateShape {
|
||||||
object_from_render: Transform,
|
object_from_render: Transform,
|
||||||
reverse_orientation: bool,
|
reverse_orientation: bool,
|
||||||
parameters: ParameterDictionary,
|
parameters: ParameterDictionary,
|
||||||
float_textures: HashMap<String, FloatTexture>,
|
float_textures: HashMap<String, Arc<FloatTexture>>,
|
||||||
loc: FileLoc,
|
loc: FileLoc,
|
||||||
arena: &mut Arena,
|
arena: &mut Arena,
|
||||||
) -> Result<Vec<Shape>, String>;
|
) -> Result<Vec<Shape>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ShapeFactory {
|
pub trait ShapeFactory {
|
||||||
|
|
@ -32,10 +33,10 @@ pub trait ShapeFactory {
|
||||||
object_from_render: Transform,
|
object_from_render: Transform,
|
||||||
reverse_orientation: bool,
|
reverse_orientation: bool,
|
||||||
parameters: ParameterDictionary,
|
parameters: ParameterDictionary,
|
||||||
float_textures: HashMap<String, FloatTexture>,
|
float_textures: HashMap<String, Arc<FloatTexture>>,
|
||||||
loc: FileLoc,
|
loc: FileLoc,
|
||||||
arena: &mut Arena,
|
arena: &mut Arena,
|
||||||
) -> Result<Vec<Shape>, String>;
|
) -> Result<Vec<Shape>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShapeFactory for Shape {
|
impl ShapeFactory for Shape {
|
||||||
|
|
@ -45,10 +46,10 @@ impl ShapeFactory for Shape {
|
||||||
object_from_render: Transform,
|
object_from_render: Transform,
|
||||||
reverse_orientation: bool,
|
reverse_orientation: bool,
|
||||||
parameters: ParameterDictionary,
|
parameters: ParameterDictionary,
|
||||||
float_textures: HashMap<String, FloatTexture>,
|
float_textures: HashMap<String, Arc<FloatTexture>>,
|
||||||
loc: FileLoc,
|
loc: FileLoc,
|
||||||
arena: &mut Arena,
|
arena: &mut Arena,
|
||||||
) -> Result<Vec<Shape>, String> {
|
) -> Result<Vec<Shape>> {
|
||||||
match name {
|
match name {
|
||||||
"sphere" => SphereShape::create(
|
"sphere" => SphereShape::create(
|
||||||
render_from_object,
|
render_from_object,
|
||||||
|
|
@ -58,7 +59,7 @@ impl ShapeFactory for Shape {
|
||||||
float_textures,
|
float_textures,
|
||||||
loc,
|
loc,
|
||||||
arena,
|
arena,
|
||||||
)?,
|
),
|
||||||
"cylinder" => CylinderShape::create(
|
"cylinder" => CylinderShape::create(
|
||||||
render_from_object,
|
render_from_object,
|
||||||
object_from_render,
|
object_from_render,
|
||||||
|
|
@ -67,7 +68,7 @@ impl ShapeFactory for Shape {
|
||||||
float_textures,
|
float_textures,
|
||||||
loc,
|
loc,
|
||||||
arena,
|
arena,
|
||||||
)?,
|
),
|
||||||
"disk" => DiskShape::create(
|
"disk" => DiskShape::create(
|
||||||
render_from_object,
|
render_from_object,
|
||||||
object_from_render,
|
object_from_render,
|
||||||
|
|
@ -76,7 +77,7 @@ impl ShapeFactory for Shape {
|
||||||
float_textures,
|
float_textures,
|
||||||
loc,
|
loc,
|
||||||
arena,
|
arena,
|
||||||
)?,
|
),
|
||||||
"bilinearmesh" => BilinearPatchShape::create(
|
"bilinearmesh" => BilinearPatchShape::create(
|
||||||
render_from_object,
|
render_from_object,
|
||||||
object_from_render,
|
object_from_render,
|
||||||
|
|
@ -85,7 +86,7 @@ impl ShapeFactory for Shape {
|
||||||
float_textures,
|
float_textures,
|
||||||
loc,
|
loc,
|
||||||
arena,
|
arena,
|
||||||
)?,
|
),
|
||||||
"trianglemesh" => TriangleShape::create(
|
"trianglemesh" => TriangleShape::create(
|
||||||
render_from_object,
|
render_from_object,
|
||||||
object_from_render,
|
object_from_render,
|
||||||
|
|
@ -94,14 +95,24 @@ impl ShapeFactory for Shape {
|
||||||
float_textures,
|
float_textures,
|
||||||
loc,
|
loc,
|
||||||
arena,
|
arena,
|
||||||
)?,
|
),
|
||||||
"plymesh" => {
|
"plymesh" => {
|
||||||
let filename = resolve_filename(parameters.get_one_string("filename", ""));
|
// let filename = resolve_filename(¶meters.get_one_string("filename", ""));
|
||||||
let ply_mesh = TriQuadMesh::read_ply(filename);
|
// let ply_mesh = TriQuadMesh::read_ply(filename);
|
||||||
let mut edge_length = parameters.get_one_float("edgelength", 1.);
|
// let mut edge_length = parameters.get_one_float("edgelength", 1.);
|
||||||
edge_length *= get_options().displacement_edge_scale;
|
// edge_length *= get_options().displacement_edge_scale;
|
||||||
let displacement_tex_name = parameters.get_texture("displacement");
|
// let displacement_tex_name = parameters.get_texture("displacement");
|
||||||
|
TriangleShape::create(
|
||||||
|
render_from_object,
|
||||||
|
object_from_render,
|
||||||
|
reverse_orientation,
|
||||||
|
parameters,
|
||||||
|
float_textures,
|
||||||
|
loc,
|
||||||
|
arena,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
_ => Err(anyhow!("Unknown shape name")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,17 +7,20 @@ use shared::spectra::DenselySampledSpectrum;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
pub static SPECTRUM_CACHE: LazyLock<Mutex<HashMap<String, Spectrum>>> =
|
pub static SPECTRUM_CACHE: LazyLock<InternCache<DenselySampledSpectrum>> =
|
||||||
|
LazyLock::new(InternCache::new);
|
||||||
|
|
||||||
|
pub static SPECTRUM_FILE_CACHE: LazyLock<Mutex<HashMap<String, Spectrum>>> =
|
||||||
LazyLock::new(|| Mutex::new(HashMap::new()));
|
LazyLock::new(|| Mutex::new(HashMap::new()));
|
||||||
|
|
||||||
fn get_spectrum_cache() -> &'static InternCache<DenselySampledSpectrum> {
|
pub fn get_spectrum_cache() -> &'static InternCache<DenselySampledSpectrum> {
|
||||||
SPECTRUM_CACHE.get_or_init(InternCache::new)
|
&SPECTRUM_CACHE
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spectrum_to_photometric(s: Spectrum) -> Float {
|
pub fn spectrum_to_photometric(s: Spectrum) -> Float {
|
||||||
let effective_spectrum = match s {
|
let effective_spectrum = match s {
|
||||||
Spectrum::RGBIlluminant(ill) => &Spectrum::Dense(ill.illuminant),
|
Spectrum::RGBIlluminant(ill) => &Spectrum::Dense(*ill.illuminant),
|
||||||
_ => s,
|
_ => &s,
|
||||||
};
|
};
|
||||||
effective_spectrum.inner_product(cie_y)
|
effective_spectrum.inner_product(&cie_y())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@ use crate::textures::*;
|
||||||
use crate::utils::mipmap::MIPMap;
|
use crate::utils::mipmap::MIPMap;
|
||||||
use crate::utils::mipmap::MIPMapFilterOptions;
|
use crate::utils::mipmap::MIPMapFilterOptions;
|
||||||
use crate::utils::{Arena, FileLoc, TextureParameterDictionary};
|
use crate::utils::{Arena, FileLoc, TextureParameterDictionary};
|
||||||
|
use anyhow::{Result, anyhow};
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use shared::Float;
|
use shared::Float;
|
||||||
use shared::core::color::ColorEncoding;
|
use shared::core::color::ColorEncoding;
|
||||||
use shared::core::geometry::Vector3f;
|
use shared::core::geometry::Vector3f;
|
||||||
use shared::core::image::WrapMode;
|
use shared::core::image::WrapMode;
|
||||||
|
use shared::core::texture::SpectrumType;
|
||||||
use shared::core::texture::{
|
use shared::core::texture::{
|
||||||
CylindricalMapping, PlanarMapping, SphericalMapping, TextureEvalContext, TextureMapping2D,
|
CylindricalMapping, PlanarMapping, SphericalMapping, TextureEvalContext, TextureMapping2D,
|
||||||
UVMapping,
|
UVMapping,
|
||||||
|
|
@ -17,10 +19,12 @@ use shared::utils::Transform;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, Mutex, OnceLock};
|
use std::sync::{Arc, Mutex, OnceLock};
|
||||||
|
|
||||||
|
#[enum_dispatch]
|
||||||
pub trait FloatTextureTrait {
|
pub trait FloatTextureTrait {
|
||||||
fn evaluate(&self, ctx: &TextureEvalContext) -> Float;
|
fn evaluate(&self, ctx: &TextureEvalContext) -> Float;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[enum_dispatch]
|
||||||
pub trait SpectrumTextureTrait {
|
pub trait SpectrumTextureTrait {
|
||||||
fn evaluate(&self, _ctx: &TextureEvalContext, _lambda: &SampledWavelengths) -> SampledSpectrum;
|
fn evaluate(&self, _ctx: &TextureEvalContext, _lambda: &SampledWavelengths) -> SampledSpectrum;
|
||||||
}
|
}
|
||||||
|
|
@ -37,11 +41,16 @@ pub enum FloatTexture {
|
||||||
Checkerboard(FloatCheckerboardTexture),
|
Checkerboard(FloatCheckerboardTexture),
|
||||||
Dots(FloatDotsTexture),
|
Dots(FloatDotsTexture),
|
||||||
FBm(FBmTexture),
|
FBm(FBmTexture),
|
||||||
// Ptex(FloatPtexTexture),
|
|
||||||
Windy(WindyTexture),
|
Windy(WindyTexture),
|
||||||
Wrinkled(WrinkledTexture),
|
Wrinkled(WrinkledTexture),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FloatTextureTrait for FloatDotsTexture {
|
||||||
|
fn evaluate(&self, _ctx: &shared::core::texture::TextureEvalContext) -> shared::Float {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FloatTextureTrait for Arc<FloatTexture> {
|
impl FloatTextureTrait for Arc<FloatTexture> {
|
||||||
fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
|
fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
|
||||||
self.as_ref().evaluate(ctx)
|
self.as_ref().evaluate(ctx)
|
||||||
|
|
@ -51,63 +60,26 @@ impl FloatTextureTrait for Arc<FloatTexture> {
|
||||||
impl FloatTexture {
|
impl FloatTexture {
|
||||||
pub fn create(
|
pub fn create(
|
||||||
name: &str,
|
name: &str,
|
||||||
render_from_texture: &Transform,
|
render_from_texture: Transform,
|
||||||
params: &TextureParameterDictionary,
|
params: TextureParameterDictionary,
|
||||||
loc: &FileLoc,
|
loc: FileLoc,
|
||||||
arena: &mut Arena,
|
arena: &mut Arena,
|
||||||
) -> Result<Self, String> {
|
) -> Result<Self> {
|
||||||
match name {
|
match name {
|
||||||
"constant" => {
|
"constant" => FloatConstantTexture::create(render_from_texture, params, loc),
|
||||||
let tex = FloatConstantTexture::create(render_from_texture, params, loc);
|
"scale" => FloatScaledTexture::create(&render_from_texture, ¶ms, &loc, arena),
|
||||||
Ok(FloatTexture::Constant(tex))
|
"mix" => FloatMixTexture::create(&render_from_texture, ¶ms, &loc, arena),
|
||||||
}
|
|
||||||
"scale" => Ok(FloatScaledTexture::create(
|
|
||||||
render_from_texture,
|
|
||||||
params,
|
|
||||||
loc,
|
|
||||||
arena,
|
|
||||||
)),
|
|
||||||
"mix" => {
|
|
||||||
let tex = FloatMixTexture::create(render_from_texture, params, loc, arena);
|
|
||||||
Ok(FloatTexture::Mix(tex))
|
|
||||||
}
|
|
||||||
"directionmix" => {
|
"directionmix" => {
|
||||||
let tex = FloatDirectionMixTexture::create(render_from_texture, params, loc, arena);
|
FloatDirectionMixTexture::create(&render_from_texture, ¶ms, &loc, arena)
|
||||||
Ok(FloatTexture::DirectionMix(tex))
|
|
||||||
}
|
}
|
||||||
"bilerp" => {
|
"bilerp" => FloatBilerpTexture::create(render_from_texture, params, loc),
|
||||||
let tex = FloatBilerpTexture::create(render_from_texture, params, loc);
|
"imagemap" => FloatImageTexture::create(render_from_texture, params, loc),
|
||||||
Ok(FloatTexture::Bilerp(tex))
|
"checkerboard" => FloatCheckerboardTexture::create(render_from_texture, params, loc),
|
||||||
}
|
"dots" => FloatDotsTexture::create(render_from_texture, params, loc),
|
||||||
"imagemap" => {
|
"fbm" => FBmTexture::create(render_from_texture, params, loc),
|
||||||
let tex = FloatImageTexture::create(render_from_texture, params, loc);
|
"wrinkled" => WrinkledTexture::create(render_from_texture, params, loc),
|
||||||
Ok(FloatTexture::Image(tex))
|
"windy" => WindyTexture::create(render_from_texture, params, loc),
|
||||||
}
|
_ => Err(anyhow!("Float texture type '{}' unknown at {}", name, loc)),
|
||||||
"checkerboard" => {
|
|
||||||
let tex = FloatCheckerboardTexture::create(render_from_texture, params, loc);
|
|
||||||
Ok(FloatTexture::Checkerboard(tex))
|
|
||||||
}
|
|
||||||
"dots" => {
|
|
||||||
let tex = FloatDotsTexture::create(render_from_texture, params, loc);
|
|
||||||
Ok(FloatTexture::Dots(tex))
|
|
||||||
}
|
|
||||||
"fbm" => {
|
|
||||||
let tex = FBmTexture::create(render_from_texture, params, loc);
|
|
||||||
Ok(FloatTexture::FBm(tex))
|
|
||||||
}
|
|
||||||
"wrinkled" => {
|
|
||||||
let tex = WrinkledTexture::create(render_from_texture, params, loc);
|
|
||||||
Ok(FloatTexture::Wrinkled(tex))
|
|
||||||
}
|
|
||||||
"windy" => {
|
|
||||||
let tex = WindyTexture::create(render_from_texture, params, loc);
|
|
||||||
Ok(FloatTexture::Windy(tex))
|
|
||||||
}
|
|
||||||
"ptex" => {
|
|
||||||
let tex = FloatPtexTexture::create(render_from_texture, params, loc);
|
|
||||||
Ok(FloatTexture::Ptex(tex))
|
|
||||||
}
|
|
||||||
_ => Err(format!("Float texture type '{}' unknown at {}", name, loc)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -129,12 +101,70 @@ pub enum SpectrumTexture {
|
||||||
Scaled(SpectrumScaledTexture),
|
Scaled(SpectrumScaledTexture),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait CreateSpectrumTexture {
|
||||||
|
fn create(
|
||||||
|
render_from_texture: Transform,
|
||||||
|
parameters: TextureParameterDictionary,
|
||||||
|
spectrum_type: SpectrumType,
|
||||||
|
loc: FileLoc,
|
||||||
|
) -> Result<SpectrumTexture>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpectrumTexture {
|
||||||
|
pub fn create(
|
||||||
|
name: &str,
|
||||||
|
render_from_texture: Transform,
|
||||||
|
params: TextureParameterDictionary,
|
||||||
|
spectrum_type: SpectrumType,
|
||||||
|
loc: FileLoc,
|
||||||
|
_arena: &mut Arena,
|
||||||
|
) -> Result<Self> {
|
||||||
|
match name {
|
||||||
|
"constant" => {
|
||||||
|
SpectrumConstantTexture::create(render_from_texture, params, spectrum_type, loc)
|
||||||
|
}
|
||||||
|
"scale" => {
|
||||||
|
SpectrumScaledTexture::create(render_from_texture, params, spectrum_type, loc)
|
||||||
|
}
|
||||||
|
"mix" => SpectrumMixTexture::create(render_from_texture, params, spectrum_type, loc),
|
||||||
|
"directionmix" => {
|
||||||
|
SpectrumDirectionMixTexture::create(render_from_texture, params, spectrum_type, loc)
|
||||||
|
}
|
||||||
|
"bilerp" => {
|
||||||
|
SpectrumBilerpTexture::create(render_from_texture, params, spectrum_type, loc)
|
||||||
|
}
|
||||||
|
"imagemap" => {
|
||||||
|
SpectrumImageTexture::create(render_from_texture, params, spectrum_type, loc)
|
||||||
|
}
|
||||||
|
"checkerboard" => {
|
||||||
|
SpectrumCheckerboardTexture::create(render_from_texture, params, spectrum_type, loc)
|
||||||
|
}
|
||||||
|
"dots" => SpectrumDotsTexture::create(render_from_texture, params, spectrum_type, loc),
|
||||||
|
_ => Err(anyhow!(
|
||||||
|
"Spectrum texture type '{}' unknown at {}",
|
||||||
|
name,
|
||||||
|
loc
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SpectrumTextureTrait for Arc<SpectrumTexture> {
|
impl SpectrumTextureTrait for Arc<SpectrumTexture> {
|
||||||
fn evaluate(&self, ctx: &TextureEvalContext, lambda: &SampledWavelengths) -> SampledSpectrum {
|
fn evaluate(&self, ctx: &TextureEvalContext, lambda: &SampledWavelengths) -> SampledSpectrum {
|
||||||
self.as_ref().evaluate(ctx, lambda)
|
self.as_ref().evaluate(ctx, lambda)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SpectrumTextureTrait for SpectrumDotsTexture {
|
||||||
|
fn evaluate(
|
||||||
|
&self,
|
||||||
|
_ctx: &shared::core::texture::TextureEvalContext,
|
||||||
|
_lambda: &shared::spectra::SampledWavelengths,
|
||||||
|
) -> shared::spectra::SampledSpectrum {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait CreateTextureMapping {
|
pub trait CreateTextureMapping {
|
||||||
fn create(
|
fn create(
|
||||||
params: &TextureParameterDictionary,
|
params: &TextureParameterDictionary,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::core::filter::CreateFilterSampler;
|
||||||
use shared::Float;
|
use shared::Float;
|
||||||
use shared::core::filter::FilterSampler;
|
use shared::core::filter::FilterSampler;
|
||||||
use shared::core::geometry::{Point2f, Vector2f};
|
use shared::core::geometry::{Point2f, Vector2f};
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::core::filter::CreateFilterSampler;
|
||||||
use shared::Float;
|
use shared::Float;
|
||||||
use shared::core::filter::FilterSampler;
|
use shared::core::filter::FilterSampler;
|
||||||
use shared::core::geometry::{Point2f, Vector2f};
|
use shared::core::geometry::{Point2f, Vector2f};
|
||||||
|
|
|
||||||
|
|
@ -57,16 +57,16 @@ pub static REC2020_COEFFS: Lazy<&[Float]> =
|
||||||
});
|
});
|
||||||
|
|
||||||
pub static SRGB_TABLE: Lazy<RGBToSpectrumTableData> =
|
pub static SRGB_TABLE: Lazy<RGBToSpectrumTableData> =
|
||||||
Lazy::new(|| RGBToSpectrumTableData::new(SRGB_SCALE, SRGB_COEFFS));
|
Lazy::new(|| RGBToSpectrumTableData::new(SRGB_SCALE.to_vec(), SRGB_COEFFS.to_vec()));
|
||||||
|
|
||||||
pub static DCI_P3_TABLE: Lazy<RGBToSpectrumTableData> =
|
pub static DCI_P3_TABLE: Lazy<RGBToSpectrumTableData> =
|
||||||
Lazy::new(|| RGBToSpectrumTableData::new(DCI_P3_SCALE, DCI_P3_COEFFS));
|
Lazy::new(|| RGBToSpectrumTableData::new(DCI_P3_SCALE.to_vec(), DCI_P3_COEFFS.to_vec()));
|
||||||
|
|
||||||
pub static REC2020_TABLE: Lazy<RGBToSpectrumTableData> =
|
pub static REC2020_TABLE: Lazy<RGBToSpectrumTableData> =
|
||||||
Lazy::new(|| RGBToSpectrumTableData::new(REC2020_SCALE, REC2020_COEFFS));
|
Lazy::new(|| RGBToSpectrumTableData::new(REC2020_SCALE.to_vec(), REC2020_COEFFS.to_vec()));
|
||||||
|
|
||||||
pub static ACES_TABLE: Lazy<RGBToSpectrumTableData> =
|
pub static ACES_TABLE: Lazy<RGBToSpectrumTableData> =
|
||||||
Lazy::new(|| RGBToSpectrumTableData::new(ACES_SCALE, ACES_COEFFS));
|
Lazy::new(|| RGBToSpectrumTableData::new(ACES_SCALE.to_vec(), ACES_COEFFS.to_vec()));
|
||||||
|
|
||||||
// pub static ACES_TABLE: Lazy<RGBToSpectrumTableData> = Lazy::new(|| {
|
// pub static ACES_TABLE: Lazy<RGBToSpectrumTableData> = Lazy::new(|| {
|
||||||
// RGBToSpectrumTableData::load(Path::new("data/"), "aces2065_1")
|
// RGBToSpectrumTableData::load(Path::new("data/"), "aces2065_1")
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use super::state::PathState;
|
||||||
use crate::core::light::Light;
|
use crate::core::light::Light;
|
||||||
use shared::core::geometry::Ray;
|
use shared::core::geometry::Ray;
|
||||||
use shared::core::interaction::{Interaction, InteractionTrait};
|
use shared::core::interaction::{Interaction, InteractionTrait};
|
||||||
use shared::core::primitive::Primitive;
|
use shared::core::primitive::{Primitive, PrimitiveTrait};
|
||||||
use shared::core::shape::ShapeIntersection;
|
use shared::core::shape::ShapeIntersection;
|
||||||
use shared::lights::LightSampler;
|
use shared::lights::LightSampler;
|
||||||
use shared::spectra::SampledWavelengths;
|
use shared::spectra::SampledWavelengths;
|
||||||
|
|
@ -41,7 +41,10 @@ impl IntegratorBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unoccluded(&self, p0: &Interaction, p1: &Interaction) -> bool {
|
pub fn unoccluded(&self, p0: &Interaction, p1: &Interaction) -> bool {
|
||||||
!self.intersect_p(&p0.spawn_ray_to_interaction(p1), Some(1. - SHADOW_EPSILON))
|
!self.intersect_p(
|
||||||
|
&p0.spawn_ray_to_interaction(*p1.get_common()),
|
||||||
|
Some(1. - SHADOW_EPSILON),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_infinite_light_contribution(
|
pub fn add_infinite_light_contribution(
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use shared::core::geometry::Point2f;
|
|
||||||
use shared::Float;
|
use shared::Float;
|
||||||
|
use shared::core::geometry::Point2f;
|
||||||
|
|
||||||
pub const N_RHO_SAMPLES: usize = 16;
|
pub const N_RHO_SAMPLES: usize = 16;
|
||||||
|
|
||||||
|
|
@ -23,20 +23,20 @@ pub static UC_RHO: [Float; N_RHO_SAMPLES] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
pub static U_RHO: [Point2f; N_RHO_SAMPLES] = [
|
pub static U_RHO: [Point2f; N_RHO_SAMPLES] = [
|
||||||
Point2f::new(0.855985, 0.570367),
|
Point2f { 0: [0.855985, 0.570367]},
|
||||||
Point2f::new(0.381823, 0.851844),
|
Point2f { 0: [0.381823, 0.851844]},
|
||||||
Point2f::new(0.285328, 0.764262),
|
Point2f { 0: [0.285328, 0.764262]},
|
||||||
Point2f::new(0.733380, 0.114073),
|
Point2f { 0: [0.733380, 0.114073]},
|
||||||
Point2f::new(0.542663, 0.344465),
|
Point2f { 0: [0.542663, 0.344465]},
|
||||||
Point2f::new(0.127274, 0.414848),
|
Point2f { 0: [0.127274, 0.414848]},
|
||||||
Point2f::new(0.964700, 0.947162),
|
Point2f { 0: [0.964700, 0.947162]},
|
||||||
Point2f::new(0.594089, 0.643463),
|
Point2f { 0: [0.594089, 0.643463]},
|
||||||
Point2f::new(0.095109, 0.170369),
|
Point2f { 0: [0.095109, 0.170369]},
|
||||||
Point2f::new(0.825444, 0.263359),
|
Point2f { 0: [0.825444, 0.263359]},
|
||||||
Point2f::new(0.429467, 0.454469),
|
Point2f { 0: [0.429467, 0.454469]},
|
||||||
Point2f::new(0.244460, 0.816459),
|
Point2f { 0: [0.244460, 0.816459]},
|
||||||
Point2f::new(0.756135, 0.731258),
|
Point2f { 0: [0.756135, 0.731258]},
|
||||||
Point2f::new(0.516165, 0.152852),
|
Point2f { 0: [0.516165, 0.152852]},
|
||||||
Point2f::new(0.180888, 0.214174),
|
Point2f { 0: [0.180888, 0.214174]},
|
||||||
Point2f::new(0.898579, 0.503897),
|
Point2f { 0: [0.898579, 0.503897]},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ use shared::core::camera::Camera;
|
||||||
use shared::core::film::VisibleSurface;
|
use shared::core::film::VisibleSurface;
|
||||||
use shared::core::geometry::{Point2i, Ray, Vector3f, VectorLike};
|
use shared::core::geometry::{Point2i, Ray, Vector3f, VectorLike};
|
||||||
use shared::core::interaction::{Interaction, InteractionTrait, SurfaceInteraction};
|
use shared::core::interaction::{Interaction, InteractionTrait, SurfaceInteraction};
|
||||||
|
use shared::core::light::LightTrait;
|
||||||
use shared::core::light::{Light, LightSampleContext};
|
use shared::core::light::{Light, LightSampleContext};
|
||||||
use shared::core::primitive::Primitive;
|
use shared::core::primitive::Primitive;
|
||||||
use shared::core::sampler::{Sampler, SamplerTrait};
|
use shared::core::sampler::{Sampler, SamplerTrait};
|
||||||
|
|
@ -92,7 +93,7 @@ impl PathIntegrator {
|
||||||
&self,
|
&self,
|
||||||
intr: &SurfaceInteraction,
|
intr: &SurfaceInteraction,
|
||||||
bsdf: &BSDF,
|
bsdf: &BSDF,
|
||||||
state: &PathState,
|
_state: &PathState,
|
||||||
lambda: &SampledWavelengths,
|
lambda: &SampledWavelengths,
|
||||||
sampler: &mut Sampler,
|
sampler: &mut Sampler,
|
||||||
) -> SampledSpectrum {
|
) -> SampledSpectrum {
|
||||||
|
|
@ -102,34 +103,34 @@ impl PathIntegrator {
|
||||||
.light_sampler
|
.light_sampler
|
||||||
.sample_with_context(&ctx, sampler.get1d())
|
.sample_with_context(&ctx, sampler.get1d())
|
||||||
else {
|
else {
|
||||||
return SampledSpectrum::ZERO;
|
return SampledSpectrum::zero();
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(ls) = sampled.light.sample_li(&ctx, sampler.get2d(), lambda, true) else {
|
let Some(ls) = sampled.light.sample_li(&ctx, sampler.get2d(), lambda, true) else {
|
||||||
return SampledSpectrum::ZERO;
|
return SampledSpectrum::zero();
|
||||||
};
|
};
|
||||||
|
|
||||||
if ls.l.is_black() || ls.pdf == 0.0 {
|
if ls.l.is_black() || ls.pdf == 0.0 {
|
||||||
return SampledSpectrum::ZERO;
|
return SampledSpectrum::zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
let wo = intr.wo();
|
let wo = intr.wo();
|
||||||
let wi = ls.wi;
|
let wi = ls.wi;
|
||||||
|
|
||||||
let Some(f) = bsdf.f(wo, wi, TransportMode::Radiance) else {
|
let Some(f) = bsdf.f(wo, wi, TransportMode::Radiance) else {
|
||||||
return SampledSpectrum::ZERO;
|
return SampledSpectrum::zero();
|
||||||
};
|
};
|
||||||
|
|
||||||
let f = f * wi.abs_dot(intr.shading.n.into());
|
let f = f * wi.abs_dot(intr.shading.n.into());
|
||||||
if f.is_black() {
|
if f.is_black() {
|
||||||
return SampledSpectrum::ZERO;
|
return SampledSpectrum::zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self
|
if !self
|
||||||
.base
|
.base
|
||||||
.unoccluded(&Interaction::Surface(intr.clone()), &ls.p_light)
|
.unoccluded(&Interaction::Surface(intr.clone()), &ls.p_light)
|
||||||
{
|
{
|
||||||
return SampledSpectrum::ZERO;
|
return SampledSpectrum::zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
let p_l = sampled.p * ls.pdf;
|
let p_l = sampled.p * ls.pdf;
|
||||||
|
|
@ -233,7 +234,8 @@ impl RayIntegratorTrait for PathIntegrator {
|
||||||
if state.depth == 0 || state.specular_bounce {
|
if state.depth == 0 || state.specular_bounce {
|
||||||
state.l += state.beta * le;
|
state.l += state.beta * le;
|
||||||
} else if self.config.use_mis {
|
} else if self.config.use_mis {
|
||||||
if let Some(light) = &isect.area_light {
|
if !isect.area_light.is_null() {
|
||||||
|
let light = &isect.area_light;
|
||||||
let p_l = self.light_sampler.pmf_with_context(&state.prev_ctx, light)
|
let p_l = self.light_sampler.pmf_with_context(&state.prev_ctx, light)
|
||||||
* light.pdf_li(&state.prev_ctx, ray.d, true);
|
* light.pdf_li(&state.prev_ctx, ray.d, true);
|
||||||
let w_b = power_heuristic(1, state.prev_pdf, 1, p_l);
|
let w_b = power_heuristic(1, state.prev_pdf, 1, p_l);
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,18 @@
|
||||||
use super::RayIntegratorTrait;
|
use super::RayIntegratorTrait;
|
||||||
use super::base::IntegratorBase;
|
use super::base::IntegratorBase;
|
||||||
use crate::Arena;
|
use crate::Arena;
|
||||||
use crate::core::image::{Image, ImageMetadata};
|
use crate::core::camera::InitMetadata;
|
||||||
|
use crate::core::film::FilmTrait;
|
||||||
|
use crate::core::image::{Image, ImageIO, ImageMetadata};
|
||||||
use crate::spectra::get_spectra_context;
|
use crate::spectra::get_spectra_context;
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
|
use rayon::iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
||||||
use shared::Float;
|
use shared::Float;
|
||||||
use shared::core::camera::Camera;
|
use shared::core::camera::{Camera, CameraTrait};
|
||||||
use shared::core::geometry::{Bounds2i, Point2i};
|
use shared::core::geometry::{Bounds2i, Point2i, VectorLike};
|
||||||
use shared::core::options::get_options;
|
use shared::core::options::get_options;
|
||||||
use shared::core::sampler::Sampler;
|
|
||||||
use shared::core::sampler::get_camera_sample;
|
use shared::core::sampler::get_camera_sample;
|
||||||
|
use shared::core::sampler::{Sampler, SamplerTrait};
|
||||||
use shared::spectra::SampledSpectrum;
|
use shared::spectra::SampledSpectrum;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
@ -83,7 +86,7 @@ pub fn render<T>(
|
||||||
let s_index = sample_index as usize;
|
let s_index = sample_index as usize;
|
||||||
let mut tile_sampler = sampler_prototype.clone();
|
let mut tile_sampler = sampler_prototype.clone();
|
||||||
|
|
||||||
tile_sampler.start_pixel_sample(p_pixel, s_index, None);
|
tile_sampler.start_pixel_sample(p_pixel, s_index as i32, None);
|
||||||
|
|
||||||
evaluate_pixel_sample(
|
evaluate_pixel_sample(
|
||||||
integrator,
|
integrator,
|
||||||
|
|
@ -163,7 +166,7 @@ pub fn render<T>(
|
||||||
camera,
|
camera,
|
||||||
&mut sampler,
|
&mut sampler,
|
||||||
*p_pixel,
|
*p_pixel,
|
||||||
sample_index,
|
sample_index.try_into().unwrap(),
|
||||||
arena,
|
arena,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -202,7 +205,8 @@ pub fn render<T>(
|
||||||
let splat_scale = 1.0 / (wave_start as Float);
|
let splat_scale = 1.0 / (wave_start as Float);
|
||||||
|
|
||||||
let film_metadata = ImageMetadata::default();
|
let film_metadata = ImageMetadata::default();
|
||||||
let film_image = camera.get_film().get_image(&film_metadata, splat_scale);
|
let film = *camera.get_film();
|
||||||
|
let film_image = film.get_image(&film_metadata, splat_scale);
|
||||||
|
|
||||||
let (mse_values, _mse_debug_img) =
|
let (mse_values, _mse_debug_img) =
|
||||||
film_image.mse(film_image.all_channels_desc(), ref_img, false);
|
film_image.mse(film_image.all_channels_desc(), ref_img, false);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ pub struct PathState {
|
||||||
pub any_non_specular_bounces: bool,
|
pub any_non_specular_bounces: bool,
|
||||||
pub eta_scale: Float,
|
pub eta_scale: Float,
|
||||||
pub prev_ctx: LightSampleContext,
|
pub prev_ctx: LightSampleContext,
|
||||||
|
pub prev_pdf: Float,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PathState {
|
impl PathState {
|
||||||
|
|
@ -23,6 +24,7 @@ impl PathState {
|
||||||
any_non_specular_bounces: false,
|
any_non_specular_bounces: false,
|
||||||
eta_scale: 1.0,
|
eta_scale: 1.0,
|
||||||
prev_ctx: LightSampleContext::default(),
|
prev_ctx: LightSampleContext::default(),
|
||||||
|
prev_pdf: 1.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,8 @@ impl CreateDiffuseLight for DiffuseAreaLight {
|
||||||
two_sided: bool,
|
two_sided: bool,
|
||||||
fov: Float,
|
fov: Float,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let is_constant_zero = match &alpha {
|
let is_constant_zero = match &*alpha {
|
||||||
FloatTexture::Constant(tex) => tex.evaluate(&TextureEvalContext::default()) == 0.0,
|
GPUFloatTexture::Constant(tex) => tex.evaluate(&TextureEvalContext::default()) == 0.0,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -60,7 +60,7 @@ impl CreateDiffuseLight for DiffuseAreaLight {
|
||||||
|
|
||||||
let base = LightBase::new(light_type, render_from_light, medium_interface);
|
let base = LightBase::new(light_type, render_from_light, medium_interface);
|
||||||
|
|
||||||
let lemit = Ptr::from(&lookup_spectrum(&le));
|
let lemit = lookup_spectrum(&le);
|
||||||
|
|
||||||
if !image.is_null() {
|
if !image.is_null() {
|
||||||
let desc = image
|
let desc = image
|
||||||
|
|
@ -96,8 +96,8 @@ impl CreateDiffuseLight for DiffuseAreaLight {
|
||||||
image,
|
image,
|
||||||
colorspace,
|
colorspace,
|
||||||
shape,
|
shape,
|
||||||
alpha: stored_alpha,
|
alpha: stored_alpha.expect("Could not retrieve texture"),
|
||||||
lemit,
|
lemit: Ptr::from(&*lemit),
|
||||||
two_sided,
|
two_sided,
|
||||||
scale,
|
scale,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,10 @@ impl CreateDistantLight for DistantLight {
|
||||||
render_from_light,
|
render_from_light,
|
||||||
MediumInterface::empty(),
|
MediumInterface::empty(),
|
||||||
);
|
);
|
||||||
let lemit = Ptr::from(&lookup_spectrum(&le));
|
let lemit = lookup_spectrum(&le);
|
||||||
Self {
|
Self {
|
||||||
base,
|
base,
|
||||||
lemit,
|
lemit: Ptr::from(&*lemit),
|
||||||
scale,
|
scale,
|
||||||
scene_center: Point3f::default(),
|
scene_center: Point3f::default(),
|
||||||
scene_radius: 0.,
|
scene_radius: 0.,
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use crate::core::spectrum::spectrum_to_photometric;
|
||||||
use crate::core::texture::FloatTexture;
|
use crate::core::texture::FloatTexture;
|
||||||
use crate::utils::sampling::PiecewiseConstant2D;
|
use crate::utils::sampling::PiecewiseConstant2D;
|
||||||
use crate::utils::{Arena, FileLoc, ParameterDictionary, resolve_filename};
|
use crate::utils::{Arena, FileLoc, ParameterDictionary, resolve_filename};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{Result, anyhow};
|
||||||
use shared::core::geometry::Point2i;
|
use shared::core::geometry::Point2i;
|
||||||
use shared::core::light::{Light, LightBase, LightType};
|
use shared::core::light::{Light, LightBase, LightType};
|
||||||
use shared::core::medium::{Medium, MediumInterface};
|
use shared::core::medium::{Medium, MediumInterface};
|
||||||
|
|
@ -47,7 +47,7 @@ impl CreateGoniometricLight for GoniometricLight {
|
||||||
let distrib = PiecewiseConstant2D::from_image(&image);
|
let distrib = PiecewiseConstant2D::from_image(&image);
|
||||||
Self {
|
Self {
|
||||||
base,
|
base,
|
||||||
iemit,
|
iemit: *iemit,
|
||||||
scale,
|
scale,
|
||||||
image: Ptr::from(image.device_image()),
|
image: Ptr::from(image.device_image()),
|
||||||
distrib: Ptr::from(&distrib.device),
|
distrib: Ptr::from(&distrib.device),
|
||||||
|
|
@ -92,7 +92,7 @@ impl CreateLight for GoniometricLight {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.x != res.y {
|
if res.x() != res.y() {
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
loc,
|
loc,
|
||||||
"image resolution ({}, {}) is non-square; unlikely to be an equal-area map",
|
"image resolution ({}, {}) is non-square; unlikely to be an equal-area map",
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
use crate::Arena;
|
use crate::Arena;
|
||||||
use crate::core::image::{Image, ImageIO};
|
use crate::core::image::{Image, ImageIO};
|
||||||
|
use crate::core::light::lookup_spectrum;
|
||||||
use crate::core::spectrum::spectrum_to_photometric;
|
use crate::core::spectrum::spectrum_to_photometric;
|
||||||
use crate::spectra::get_spectra_context;
|
use crate::spectra::get_spectra_context;
|
||||||
use crate::utils::sampling::{PiecewiseConstant2D, WindowedPiecewiseConstant2D};
|
use crate::utils::sampling::{PiecewiseConstant2D, WindowedPiecewiseConstant2D};
|
||||||
use crate::utils::{FileLoc, ParameterDictionary, resolve_filename};
|
use crate::utils::{FileLoc, ParameterDictionary, Upload, resolve_filename};
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
|
use rayon::prelude::*;
|
||||||
use rayon::iter::{IndexedParallelIterator, ParallelIterator};
|
|
||||||
use rayon::prelude::ParallelSliceMut;
|
|
||||||
use shared::core::camera::CameraTransform;
|
use shared::core::camera::CameraTransform;
|
||||||
use shared::core::geometry::{Bounds2f, Frame, Point2f, Point2i, Point3f, VectorLike, cos_theta};
|
use shared::core::geometry::{Bounds2f, Frame, Point2f, Point2i, Point3f, VectorLike, cos_theta};
|
||||||
use shared::core::image::{DeviceImage, PixelFormat, WrapMode};
|
use shared::core::image::{PixelFormat, WrapMode};
|
||||||
use shared::core::light::{Light, LightBase, LightType};
|
use shared::core::light::{Light, LightBase, LightType};
|
||||||
use shared::core::medium::MediumInterface;
|
use shared::core::medium::MediumInterface;
|
||||||
use shared::core::spectrum::Spectrum;
|
use shared::core::spectrum::Spectrum;
|
||||||
|
|
@ -18,116 +17,58 @@ use shared::core::texture::SpectrumType;
|
||||||
use shared::lights::{ImageInfiniteLight, PortalInfiniteLight, UniformInfiniteLight};
|
use shared::lights::{ImageInfiniteLight, PortalInfiniteLight, UniformInfiniteLight};
|
||||||
use shared::spectra::RGBColorSpace;
|
use shared::spectra::RGBColorSpace;
|
||||||
use shared::utils::math::{equal_area_sphere_to_square, equal_area_square_to_sphere};
|
use shared::utils::math::{equal_area_sphere_to_square, equal_area_square_to_sphere};
|
||||||
|
use shared::utils::sampling::{DevicePiecewiseConstant2D, DeviceWindowedPiecewiseConstant2D};
|
||||||
use shared::utils::{Ptr, Transform};
|
use shared::utils::{Ptr, Transform};
|
||||||
use shared::{Float, PI};
|
use shared::{Float, PI};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use crate::core::light::lookup_spectrum;
|
|
||||||
|
|
||||||
pub trait CreateImageInfiniteLight {
|
pub trait CreateImageInfiniteLight {
|
||||||
fn new(
|
fn new(
|
||||||
render_from_light: Transform,
|
render_from_light: Transform,
|
||||||
medium_interface: MediumInterface,
|
|
||||||
scale: Float,
|
scale: Float,
|
||||||
image: Arc<DeviceImage>,
|
image: Ptr<DeviceImage>,
|
||||||
image_color_space: Arc<RGBColorSpace>,
|
image_color_space: Ptr<RGBColorSpace>,
|
||||||
|
distrib: Ptr<DevicePiecewiseConstant2D>,
|
||||||
|
compensated_distrib: Ptr<DevicePiecewiseConstant2D>,
|
||||||
) -> Self;
|
) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CreateImageInfiniteLight for ImageInfiniteLight {
|
impl CreateImageInfiniteLight for ImageInfiniteLight {
|
||||||
fn new(
|
fn new(
|
||||||
render_from_light: Transform,
|
render_from_light: Transform,
|
||||||
medium_interface: MediumInterface,
|
|
||||||
scale: Float,
|
scale: Float,
|
||||||
image: Arc<DeviceImage>,
|
image: Ptr<DeviceImage>,
|
||||||
image_color_space: Arc<RGBColorSpace>,
|
image_color_space: Ptr<RGBColorSpace>,
|
||||||
|
distrib: Ptr<DevicePiecewiseConstant2D>,
|
||||||
|
compensated_distrib: Ptr<DevicePiecewiseConstant2D>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let base = LightBase::new(
|
let base = LightBase::new(
|
||||||
LightType::Infinite,
|
LightType::Infinite,
|
||||||
render_from_light,
|
render_from_light,
|
||||||
MediumInterface::default(),
|
MediumInterface::default(),
|
||||||
);
|
);
|
||||||
|
Self {
|
||||||
let desc = image
|
|
||||||
.get_channel_desc(&["R", "G", "B"])
|
|
||||||
.expect("Image used for DiffuseAreaLight doesn't have R, G, B channels");
|
|
||||||
|
|
||||||
assert_eq!(3, desc.size());
|
|
||||||
assert!(desc.is_identity());
|
|
||||||
|
|
||||||
let res = image.resolution();
|
|
||||||
assert_eq!(
|
|
||||||
res.x(),
|
|
||||||
res.y(),
|
|
||||||
"Image resolution ({}, {}) is non-square. Unlikely to be an equal area environment map.",
|
|
||||||
res.x(),
|
|
||||||
res.y()
|
|
||||||
);
|
|
||||||
|
|
||||||
let n_u = res.x() as usize;
|
|
||||||
let n_v = res.y() as usize;
|
|
||||||
let mut data: Vec<Float> = (0..n_v)
|
|
||||||
.flat_map(|v| {
|
|
||||||
(0..n_u).map(move |u| {
|
|
||||||
image
|
|
||||||
.get_channels(Point2i::new(u as i32, v as i32))
|
|
||||||
.average()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let distrib = PiecewiseConstant2D::new(&data, n_u, n_v);
|
|
||||||
|
|
||||||
let slice = distrib.as_mut_slice();
|
|
||||||
let average = slice.iter().sum::<Float>() / slice.len() as Float;
|
|
||||||
|
|
||||||
let mut all_zero = true;
|
|
||||||
for v in slice.iter_mut() {
|
|
||||||
*v = (*v - average).max(0.0);
|
|
||||||
all_zero &= *v == 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if all_zero {
|
|
||||||
data.fill(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
let compensated_distrib = PiecewiseConstant2D::new(&data, n_u, n_v);
|
|
||||||
|
|
||||||
ImageInfiniteLight {
|
|
||||||
base,
|
base,
|
||||||
image: Ptr::from(image.device_image()),
|
image,
|
||||||
image_color_space: Ptr::from(image_color_space.as_ref()),
|
image_color_space,
|
||||||
scene_center: Point3f::default(),
|
|
||||||
scene_radius: 0.,
|
|
||||||
scale,
|
scale,
|
||||||
distrib: Ptr::from(&*distrib),
|
distrib,
|
||||||
compensated_distrib: Ptr::from(&*compensated_distrib),
|
compensated_distrib,
|
||||||
|
scene_center: Point3f::default(),
|
||||||
|
scene_radius: 0.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct InfinitePortalLightStorage {
|
|
||||||
image: Image,
|
|
||||||
distribution: WindowedPiecewiseConstant2D,
|
|
||||||
image_color_space: RGBColorSpace,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct PortalInfiniteLightHost {
|
|
||||||
pub device: PortalInfiniteLight,
|
|
||||||
pub filename: String,
|
|
||||||
_storage: Arc<InfinitePortalLightStorage>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CreatePortalInfiniteLight {
|
pub trait CreatePortalInfiniteLight {
|
||||||
fn new(
|
fn new(
|
||||||
render_from_light: Transform,
|
render_from_light: Transform,
|
||||||
scale: Float,
|
scale: Float,
|
||||||
image: Arc<Image>,
|
image: Ptr<DeviceImage>,
|
||||||
image_color_space: Arc<RGBColorSpace>,
|
image_color_space: Ptr<RGBColorSpace>,
|
||||||
points: Vec<Point3f>,
|
portal: [Point3f; 4],
|
||||||
|
portal_frame: Frame,
|
||||||
|
distribution: Ptr<DeviceWindowedPiecewiseConstant2D>,
|
||||||
) -> Self;
|
) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -135,145 +76,48 @@ impl CreatePortalInfiniteLight for PortalInfiniteLight {
|
||||||
fn new(
|
fn new(
|
||||||
render_from_light: Transform,
|
render_from_light: Transform,
|
||||||
scale: Float,
|
scale: Float,
|
||||||
image: Arc<Image>,
|
image: Ptr<DeviceImage>,
|
||||||
image_color_space: Arc<RGBColorSpace>,
|
image_color_space: Ptr<RGBColorSpace>,
|
||||||
points: Vec<Point3f>,
|
portal: [Point3f; 4],
|
||||||
|
portal_frame: Frame,
|
||||||
|
distribution: Ptr<DeviceWindowedPiecewiseConstant2D>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let base = LightBase::new(
|
let base = LightBase::new(
|
||||||
LightType::Infinite,
|
LightType::Infinite,
|
||||||
render_from_light,
|
render_from_light,
|
||||||
MediumInterface::default(),
|
MediumInterface::default(),
|
||||||
);
|
);
|
||||||
|
Self {
|
||||||
let desc = image
|
|
||||||
.get_channel_desc(&["R", "G", "B"])
|
|
||||||
.unwrap_or_else(|_| {
|
|
||||||
panic!("Image used for PortalImageInfiniteLight doesn't have R, G, B channels.",)
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(3, desc.offset.len());
|
|
||||||
let src_res = image.resolution();
|
|
||||||
if src_res.x() != src_res.y() {
|
|
||||||
panic!(
|
|
||||||
"Image resolution ({}, {}) is non-square. It's unlikely this is an equal area environment map.",
|
|
||||||
src_res.x(),
|
|
||||||
src_res.y()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if points.len() != 4 {
|
|
||||||
panic!(
|
|
||||||
"Expected 4 vertices for infinite light portal but given {}",
|
|
||||||
points.len()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let portal: [Point3f; 4] = [points[0], points[1], points[2], points[3]];
|
|
||||||
|
|
||||||
let p01 = (portal[1] - portal[0]).normalize();
|
|
||||||
let p12 = (portal[2] - portal[1]).normalize();
|
|
||||||
let p32 = (portal[2] - portal[3]).normalize();
|
|
||||||
let p03 = (portal[3] - portal[0]).normalize();
|
|
||||||
|
|
||||||
if (p01.dot(p32) - 1.0).abs() > 0.001 || (p12.dot(p03) - 1.0).abs() > 0.001 {
|
|
||||||
panic!("Infinite light portal isn't a planar quadrilateral (opposite edges)");
|
|
||||||
}
|
|
||||||
|
|
||||||
if p01.dot(p12).abs() > 0.001
|
|
||||||
|| p12.dot(p32).abs() > 0.001
|
|
||||||
|| p32.dot(p03).abs() > 0.001
|
|
||||||
|| p03.dot(p01).abs() > 0.001
|
|
||||||
{
|
|
||||||
panic!("Infinite light portal isn't a planar quadrilateral (perpendicular edges)");
|
|
||||||
}
|
|
||||||
|
|
||||||
let portal_frame = Frame::from_xy(p03, p01);
|
|
||||||
|
|
||||||
let width = src_res.x();
|
|
||||||
let height = src_res.y();
|
|
||||||
|
|
||||||
let mut new_pixels = vec![0.0 as Float; (width * height * 3) as usize];
|
|
||||||
|
|
||||||
new_pixels
|
|
||||||
.par_chunks_mut((width * 3) as usize)
|
|
||||||
.enumerate()
|
|
||||||
.for_each(|(y, row_pixels)| {
|
|
||||||
let y = y as i32;
|
|
||||||
|
|
||||||
for x in 0..width {
|
|
||||||
let uv = Point2f::new(
|
|
||||||
(x as Float + 0.5) / width as Float,
|
|
||||||
(y as Float + 0.5) / height as Float,
|
|
||||||
);
|
|
||||||
|
|
||||||
let (w_world, _) = Self::render_from_image(portal_frame, uv);
|
|
||||||
let w_local = render_from_light.apply_inverse_vector(w_world).normalize();
|
|
||||||
let uv_equi = equal_area_sphere_to_square(w_local);
|
|
||||||
|
|
||||||
let pixel_idx = (x * 3) as usize;
|
|
||||||
|
|
||||||
for c in 0..3 {
|
|
||||||
let val = image.bilerp_channel_with_wrap(
|
|
||||||
uv_equi,
|
|
||||||
c,
|
|
||||||
WrapMode::OctahedralSphere.into(),
|
|
||||||
);
|
|
||||||
row_pixels[pixel_idx + c as usize] = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let img = Image::new(
|
|
||||||
PixelFormat::F32,
|
|
||||||
src_res,
|
|
||||||
&["R", "G", "B"],
|
|
||||||
image.encoding().into(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let duv_dw_closure = |p: Point2f| -> Float {
|
|
||||||
let (_, jacobian) = Self::render_from_image(portal_frame, p);
|
|
||||||
jacobian
|
|
||||||
};
|
|
||||||
|
|
||||||
let d = img.get_sampling_distribution(
|
|
||||||
duv_dw_closure,
|
|
||||||
Bounds2f::from_points(Point2f::new(0., 0.), Point2f::new(1., 1.)),
|
|
||||||
);
|
|
||||||
|
|
||||||
let distribution = WindowedPiecewiseConstant2D::new(d);
|
|
||||||
|
|
||||||
PortalInfiniteLight {
|
|
||||||
base,
|
base,
|
||||||
image: Ptr::from(img.device_image()),
|
image,
|
||||||
image_color_space: Ptr::from(&*image_color_space),
|
image_color_space,
|
||||||
scale,
|
scale,
|
||||||
scene_center: Point3f::default(),
|
|
||||||
scene_radius: 0.,
|
|
||||||
portal,
|
portal,
|
||||||
portal_frame,
|
portal_frame,
|
||||||
distribution,
|
distribution: *distribution,
|
||||||
|
scene_center: Point3f::default(),
|
||||||
|
scene_radius: 0.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CreateUniformInfiniteLight {
|
pub trait CreateUniformInfiniteLight {
|
||||||
fn new(render_from_light: Transform, le: Spectrum, scale: Float) -> Self;
|
fn new(render_from_light: Transform, scale: Float, lemit: Ptr<DenselySampledSpectrum>) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CreateUniformInfiniteLight for UniformInfiniteLight {
|
impl CreateUniformInfiniteLight for UniformInfiniteLight {
|
||||||
fn new(render_from_light: Transform, le: Spectrum, scale: Float) -> Self {
|
fn new(render_from_light: Transform, scale: Float, lemit: Ptr<DenselySampledSpectrum>) -> Self {
|
||||||
let base = LightBase::new(
|
let base = LightBase::new(
|
||||||
LightType::Infinite,
|
LightType::Infinite,
|
||||||
render_from_light,
|
render_from_light,
|
||||||
MediumInterface::default(),
|
MediumInterface::default(),
|
||||||
);
|
);
|
||||||
let lemit = Ptr::from(&lookup_spectrum(&le));
|
|
||||||
Self {
|
Self {
|
||||||
base,
|
base,
|
||||||
lemit,
|
lemit,
|
||||||
scale,
|
scale,
|
||||||
scene_center: Point3f::default(),
|
scene_center: Point3f::default(),
|
||||||
scene_radius: 0.,
|
scene_radius: 0.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -281,7 +125,7 @@ impl CreateUniformInfiniteLight for UniformInfiniteLight {
|
||||||
pub fn create(
|
pub fn create(
|
||||||
arena: &mut Arena,
|
arena: &mut Arena,
|
||||||
render_from_light: Transform,
|
render_from_light: Transform,
|
||||||
medium: MediumInterface,
|
_medium: MediumInterface,
|
||||||
camera_transform: CameraTransform,
|
camera_transform: CameraTransform,
|
||||||
parameters: &ParameterDictionary,
|
parameters: &ParameterDictionary,
|
||||||
colorspace: &RGBColorSpace,
|
colorspace: &RGBColorSpace,
|
||||||
|
|
@ -301,6 +145,7 @@ pub fn create(
|
||||||
return Err(anyhow!(loc, "cannot specify both \"L\" and \"filename\""));
|
return Err(anyhow!(loc, "cannot specify both \"L\" and \"filename\""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Uniform infinite light (no image)
|
||||||
if !has_file && !has_portal {
|
if !has_file && !has_portal {
|
||||||
let spectrum = if has_spectrum {
|
let spectrum = if has_spectrum {
|
||||||
scale /= spectrum_to_photometric(l[0]);
|
scale /= spectrum_to_photometric(l[0]);
|
||||||
|
|
@ -313,13 +158,13 @@ pub fn create(
|
||||||
scale *= e_v / PI;
|
scale *= e_v / PI;
|
||||||
}
|
}
|
||||||
|
|
||||||
let light = UniformInfiniteLight::new(render_from_light, spectrum, scale);
|
let lemit = lookup_spectrum(&spectrum);
|
||||||
|
let light = UniformInfiniteLight::new(render_from_light, scale, lemit.upload(arena));
|
||||||
return Ok(Light::InfiniteUniform(light));
|
return Ok(Light::InfiniteUniform(light));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image based
|
// Image-based lights
|
||||||
|
let (image, image_cs) = load_image(&filename, &l, colorspace, loc)?;
|
||||||
let (image, image_cs) = load_image_or_constant(&filename, &l, colorspace, loc)?;
|
|
||||||
|
|
||||||
scale /= spectrum_to_photometric(Spectrum::Dense(image_cs.illuminant));
|
scale /= spectrum_to_photometric(Spectrum::Dense(image_cs.illuminant));
|
||||||
|
|
||||||
|
|
@ -328,26 +173,194 @@ pub fn create(
|
||||||
scale *= e_v / k_e;
|
scale *= e_v / k_e;
|
||||||
}
|
}
|
||||||
|
|
||||||
// let image_ptr = image.upload(arena);
|
|
||||||
// let cs_ptr = image_cs.upload(arena);
|
|
||||||
|
|
||||||
if has_portal {
|
if has_portal {
|
||||||
let portal_render: Vec<Point3f> = portal
|
create_portal_light(
|
||||||
.iter()
|
arena,
|
||||||
.map(|p| camera_transform.camera_from_world(0.0).apply_to_point(*p))
|
render_from_light,
|
||||||
.collect();
|
scale,
|
||||||
|
image,
|
||||||
let (portal_ptr, portal_len) = arena.alloc_slice(&portal_render);
|
image_cs,
|
||||||
let light =
|
&portal,
|
||||||
PortalInfiniteLight::new(render_from_light, scale, image.into(), cs, portal_render);
|
camera_transform,
|
||||||
Ok(Light::InfinitePortal(light))
|
loc,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
let light = ImageInfiniteLight::new(render_from_light, medium, scale, image, cs);
|
create_image_light(arena, render_from_light, scale, image, image_cs)
|
||||||
Ok(Light::InfiniteImage(light))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_image_or_constant(
|
fn create_image_light(
|
||||||
|
arena: &mut Arena,
|
||||||
|
render_from_light: Transform,
|
||||||
|
scale: Float,
|
||||||
|
image: Image,
|
||||||
|
image_cs: RGBColorSpace,
|
||||||
|
) -> Result<Light> {
|
||||||
|
let res = image.resolution();
|
||||||
|
assert_eq!(
|
||||||
|
res.x(),
|
||||||
|
res.y(),
|
||||||
|
"Image must be square for equal-area mapping"
|
||||||
|
);
|
||||||
|
|
||||||
|
let (n_u, n_v) = (res.x() as usize, res.y() as usize);
|
||||||
|
|
||||||
|
// Extract luminance data
|
||||||
|
let mut data: Vec<Float> = (0..n_v)
|
||||||
|
.flat_map(|v| {
|
||||||
|
(0..n_u).map(move |u| {
|
||||||
|
image
|
||||||
|
.get_channels(Point2i::new(u as i32, v as i32))
|
||||||
|
.average()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let distrib = PiecewiseConstant2D::new(&data, n_u, n_v);
|
||||||
|
|
||||||
|
// Build compensated distribution
|
||||||
|
let average = data.iter().sum::<Float>() / data.len() as Float;
|
||||||
|
let mut all_zero = true;
|
||||||
|
for v in &mut data {
|
||||||
|
*v = (*v - average).max(0.0);
|
||||||
|
all_zero &= *v == 0.0;
|
||||||
|
}
|
||||||
|
if all_zero {
|
||||||
|
data.fill(1.0);
|
||||||
|
}
|
||||||
|
let compensated_distrib = PiecewiseConstant2D::new(&data, n_u, n_v);
|
||||||
|
|
||||||
|
let light = ImageInfiniteLight::new(
|
||||||
|
render_from_light,
|
||||||
|
scale,
|
||||||
|
image.upload(arena),
|
||||||
|
image_cs.upload(arena),
|
||||||
|
distrib.upload(arena),
|
||||||
|
compensated_distrib.upload(arena),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(Light::InfiniteImage(light))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_portal_light(
|
||||||
|
arena: &mut Arena,
|
||||||
|
render_from_light: Transform,
|
||||||
|
scale: Float,
|
||||||
|
image: Image,
|
||||||
|
image_cs: RGBColorSpace,
|
||||||
|
portal_points: &[Point3f],
|
||||||
|
camera_transform: CameraTransform,
|
||||||
|
loc: &FileLoc,
|
||||||
|
) -> Result<Light> {
|
||||||
|
let res = image.resolution();
|
||||||
|
if res.x() != res.y() {
|
||||||
|
return Err(anyhow!(loc, "Portal light image must be square"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate portal
|
||||||
|
if portal_points.len() != 4 {
|
||||||
|
return Err(anyhow!(
|
||||||
|
loc,
|
||||||
|
"Portal requires exactly 4 vertices, got {}",
|
||||||
|
portal_points.len()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let portal: [Point3f; 4] = portal_points
|
||||||
|
.iter()
|
||||||
|
.map(|p| camera_transform.camera_from_world(0.0).apply_to_point(*p))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let portal_frame = validate_and_build_portal_frame(&portal, loc)?;
|
||||||
|
|
||||||
|
// Remap image through portal
|
||||||
|
let remapped = remap_image_through_portal(&image, &render_from_light, &portal_frame);
|
||||||
|
|
||||||
|
// Build distribution
|
||||||
|
let duv_dw = |p: Point2f| -> Float {
|
||||||
|
let (_, jacobian) = PortalInfiniteLight::render_from_image(portal_frame, p);
|
||||||
|
jacobian
|
||||||
|
};
|
||||||
|
let d = remapped.get_sampling_distribution(
|
||||||
|
duv_dw,
|
||||||
|
Bounds2f::from_points(Point2f::zero(), Point2f::fill(1.)),
|
||||||
|
);
|
||||||
|
let distribution = WindowedPiecewiseConstant2D::new(d);
|
||||||
|
|
||||||
|
let light = PortalInfiniteLight::new(
|
||||||
|
render_from_light,
|
||||||
|
scale,
|
||||||
|
remapped.upload(arena),
|
||||||
|
image_cs.upload(arena),
|
||||||
|
portal,
|
||||||
|
portal_frame,
|
||||||
|
distribution.upload(arena),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(Light::InfinitePortal(light))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_and_build_portal_frame(portal: &[Point3f; 4], loc: &FileLoc) -> Result<Frame> {
|
||||||
|
let p01 = (portal[1] - portal[0]).normalize();
|
||||||
|
let p12 = (portal[2] - portal[1]).normalize();
|
||||||
|
let p32 = (portal[2] - portal[3]).normalize();
|
||||||
|
let p03 = (portal[3] - portal[0]).normalize();
|
||||||
|
|
||||||
|
if (p01.dot(p32) - 1.0).abs() > 0.001 || (p12.dot(p03) - 1.0).abs() > 0.001 {
|
||||||
|
return Err(anyhow!(loc, "Portal edges not parallel"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if p01.dot(p12).abs() > 0.001
|
||||||
|
|| p12.dot(p32).abs() > 0.001
|
||||||
|
|| p32.dot(p03).abs() > 0.001
|
||||||
|
|| p03.dot(p01).abs() > 0.001
|
||||||
|
{
|
||||||
|
return Err(anyhow!(loc, "Portal edges not perpendicular"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Frame::from_xy(p03, p01))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remap_image_through_portal(
|
||||||
|
image: &Image,
|
||||||
|
render_from_light: &Transform,
|
||||||
|
portal_frame: &Frame,
|
||||||
|
) -> Image {
|
||||||
|
let res = image.resolution();
|
||||||
|
let (width, height) = (res.x() as usize, res.y() as usize);
|
||||||
|
|
||||||
|
let mut pixels = vec![0.0f32; width * height * 3];
|
||||||
|
|
||||||
|
pixels
|
||||||
|
.par_chunks_mut(width * 3)
|
||||||
|
.enumerate()
|
||||||
|
.for_each(|(y, row)| {
|
||||||
|
for x in 0..width {
|
||||||
|
let uv = Point2f::new(
|
||||||
|
(x as Float + 0.5) / width as Float,
|
||||||
|
(y as Float + 0.5) / height as Float,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (w_world, _) = PortalInfiniteLight::render_from_image(*portal_frame, uv);
|
||||||
|
let w_local = render_from_light.apply_inverse_vector(w_world).normalize();
|
||||||
|
let uv_equi = equal_area_sphere_to_square(w_local);
|
||||||
|
|
||||||
|
for c in 0..3 {
|
||||||
|
row[x * 3 + c] = image.bilerp_channel_with_wrap(
|
||||||
|
uv_equi,
|
||||||
|
c as i32,
|
||||||
|
WrapMode::OctahedralSphere.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Image::from_f32(pixels, res, &["R", "G", "B"])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_image(
|
||||||
filename: &str,
|
filename: &str,
|
||||||
l: &[Spectrum],
|
l: &[Spectrum],
|
||||||
colorspace: &RGBColorSpace,
|
colorspace: &RGBColorSpace,
|
||||||
|
|
@ -355,52 +368,51 @@ fn load_image_or_constant(
|
||||||
) -> Result<(Image, RGBColorSpace)> {
|
) -> Result<(Image, RGBColorSpace)> {
|
||||||
if filename.is_empty() {
|
if filename.is_empty() {
|
||||||
let stdspec = get_spectra_context();
|
let stdspec = get_spectra_context();
|
||||||
let rgb = &l[0].to_rgb(colorspace, &stdspec);
|
let rgb = l[0].to_rgb(colorspace, &stdspec);
|
||||||
let rgb_values = [rgb.r, rgb.g, rgb.b];
|
let image =
|
||||||
let image = Image::new_constant(Point2i::new(1, 1), &["R", "G", "B"], &rgb_values);
|
Image::new_constant(Point2i::new(1, 1), &["R", "G", "B"], &[rgb.r, rgb.g, rgb.b]);
|
||||||
Ok((image, colorspace.clone()))
|
return Ok((image, colorspace.clone()));
|
||||||
} else {
|
}
|
||||||
let im = Image::read(Path::new(&filename), None)
|
|
||||||
|
let im = Image::read(Path::new(filename), None)
|
||||||
.map_err(|e| anyhow!(loc, "failed to load '{}': {}", filename, e))?;
|
.map_err(|e| anyhow!(loc, "failed to load '{}': {}", filename, e))?;
|
||||||
|
|
||||||
if im.image.has_any_infinite_pixels() || im.image.has_any_nan_pixels() {
|
if im.image.has_any_infinite_pixels() || im.image.has_any_nan_pixels() {
|
||||||
return Err(anyhow!(loc, "image '{}' has invalid pixels", filename));
|
return Err(anyhow!(loc, "image '{}' has invalid pixels", filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
im.image
|
let desc = im
|
||||||
|
.image
|
||||||
.get_channel_desc(&["R", "G", "B"])
|
.get_channel_desc(&["R", "G", "B"])
|
||||||
.map_err(|_| anyhow!(loc, "image '{}' must have R, G, B channels", filename))?;
|
.map_err(|_| anyhow!(loc, "image '{}' must have R, G, B channels", filename))?;
|
||||||
|
|
||||||
let cs = im.metadata.colorspace.unwrap_or_else(|| colorspace.clone());
|
let cs = im.metadata.colorspace.unwrap_or_else(|| colorspace.clone());
|
||||||
let image_desc = im.image.get_channel_desc(&["R", "G", "B"])?;
|
Ok((im.image.select_channels(&desc), cs))
|
||||||
let selected = im.image.select_channels(&image_desc);
|
|
||||||
|
|
||||||
Ok((selected, cs))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_hemisphere_illuminance(image: &Image, cs: &RGBColorSpace) -> Float {
|
fn compute_hemisphere_illuminance(image: &Image, cs: &RGBColorSpace) -> Float {
|
||||||
let lum = cs.luminance_vector();
|
let lum = cs.luminance_vector();
|
||||||
let res = image.resolution();
|
let res = image.resolution();
|
||||||
let mut sum = 0.0;
|
|
||||||
|
|
||||||
for y in 0..res.y() {
|
let sum: Float = (0..res.y())
|
||||||
let v = (y as Float + 0.5) / res.y() as Float;
|
.flat_map(|y| (0..res.x()).map(move |x| (x, y)))
|
||||||
for x in 0..res.x() {
|
.filter_map(|(x, y)| {
|
||||||
let u = (x as Float + 0.5) / res.x() as Float;
|
let u = (x as Float + 0.5) / res.x() as Float;
|
||||||
|
let v = (y as Float + 0.5) / res.y() as Float;
|
||||||
let w = equal_area_square_to_sphere(Point2f::new(u, v));
|
let w = equal_area_square_to_sphere(Point2f::new(u, v));
|
||||||
|
|
||||||
if w.z() <= 0.0 {
|
if w.z() <= 0.0 {
|
||||||
continue;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let r = image.get_channel(Point2i::new(x, y), 0);
|
let p = Point2i::new(x, y);
|
||||||
let g = image.get_channel(Point2i::new(x, y), 1);
|
let r = image.get_channel(p, 0);
|
||||||
let b = image.get_channel(Point2i::new(x, y), 2);
|
let g = image.get_channel(p, 1);
|
||||||
|
let b = image.get_channel(p, 2);
|
||||||
|
|
||||||
sum += (r * lum[0] + g * lum[1] + b * lum[2]) * cos_theta(w);
|
Some((r * lum[0] + g * lum[1] + b * lum[2]) * cos_theta(w))
|
||||||
}
|
})
|
||||||
}
|
.sum();
|
||||||
|
|
||||||
sum * 2.0 * PI / (res.x() * res.y()) as Float
|
sum * 2.0 * PI / (res.x() * res.y()) as Float
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ impl CreatePointLight for PointLight {
|
||||||
render_from_light,
|
render_from_light,
|
||||||
medium_interface,
|
medium_interface,
|
||||||
);
|
);
|
||||||
let i = Ptr::from(lookup_spectrum(&le));
|
let i = Ptr::from(&*lookup_spectrum(&le));
|
||||||
|
|
||||||
Self { base, scale, i }
|
Self { base, scale, i }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ pub trait CreateProjectionLight {
|
||||||
scale: Float,
|
scale: Float,
|
||||||
image: Ptr<DeviceImage>,
|
image: Ptr<DeviceImage>,
|
||||||
image_color_space: Ptr<RGBColorSpace>,
|
image_color_space: Ptr<RGBColorSpace>,
|
||||||
|
distrib: Ptr<DeviceWindowedPiecewiseConstant2D>,
|
||||||
fov: Float,
|
fov: Float,
|
||||||
) -> Self;
|
) -> Self;
|
||||||
}
|
}
|
||||||
|
|
@ -38,6 +39,7 @@ impl CreateProjectionLight for ProjectionLight {
|
||||||
scale: Float,
|
scale: Float,
|
||||||
image: Ptr<DeviceImage>,
|
image: Ptr<DeviceImage>,
|
||||||
image_color_space: Ptr<RGBColorSpace>,
|
image_color_space: Ptr<RGBColorSpace>,
|
||||||
|
distrib: Ptr<DeviceWindowedPiecewiseConstant2D>,
|
||||||
fov: Float,
|
fov: Float,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let base = LightBase::new(
|
let base = LightBase::new(
|
||||||
|
|
@ -45,30 +47,25 @@ impl CreateProjectionLight for ProjectionLight {
|
||||||
render_from_light,
|
render_from_light,
|
||||||
medium_interface,
|
medium_interface,
|
||||||
);
|
);
|
||||||
let aspect = image.resolution().x() as Float / image.resolution().y() as Float;
|
|
||||||
let screen_bounds = if aspect > 1. {
|
let res = image.resolution();
|
||||||
Bounds2f::from_points(Point2f::new(-aspect, -1.), Point2f::new(aspect, 1.))
|
let aspect = res.x() as Float / res.y() as Float;
|
||||||
|
let screen_bounds = if aspect > 1.0 {
|
||||||
|
Bounds2f::from_points(Point2f::new(-aspect, -1.0), Point2f::new(aspect, 1.0))
|
||||||
} else {
|
} else {
|
||||||
Bounds2f::from_points(
|
Bounds2f::from_points(
|
||||||
Point2f::new(-1., 1. / aspect),
|
Point2f::new(-1.0, -1.0 / aspect),
|
||||||
Point2f::new(1., 1. / aspect),
|
Point2f::new(1.0, 1.0 / aspect),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let hither = 1e-3;
|
let hither = 1e-3;
|
||||||
let screen_from_light = Transform::perspective(fov, hither, 1e30).unwrap();
|
let screen_from_light = Transform::perspective(fov, hither, 1e30).unwrap();
|
||||||
let light_from_screen = screen_from_light.inverse();
|
let light_from_screen = screen_from_light.inverse();
|
||||||
let opposite = (radians(fov) / 2.).tan();
|
|
||||||
let aspect_ratio = if aspect > 1. { aspect } else { 1. / aspect };
|
|
||||||
let a = 4. * square(opposite) * aspect_ratio;
|
|
||||||
let dwda = |p: Point2f| {
|
|
||||||
let w =
|
|
||||||
Vector3f::from(light_from_screen.apply_to_point(Point3f::new(p.x(), p.y(), 0.)));
|
|
||||||
cos_theta(w.normalize()).powi(3)
|
|
||||||
};
|
|
||||||
|
|
||||||
let d = image.get_sampling_distribution(dwda, screen_bounds);
|
let opposite = (radians(fov) / 2.0).tan();
|
||||||
let distrib = Ptr::from(&PiecewiseConstant2D::from_image(image).device);
|
let aspect_ratio = if aspect > 1.0 { aspect } else { 1.0 / aspect };
|
||||||
|
let a = 4.0 * square(opposite) * aspect_ratio;
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
base,
|
base,
|
||||||
|
|
@ -143,12 +140,23 @@ impl CreateLight for ProjectionLight {
|
||||||
let flip = Transform::scale(1., -1., 1.);
|
let flip = Transform::scale(1., -1., 1.);
|
||||||
let render_from_light_flip = render_from_light * flip;
|
let render_from_light_flip = render_from_light * flip;
|
||||||
|
|
||||||
|
let dwda = |p: Point2f| {
|
||||||
|
let w =
|
||||||
|
Vector3f::from(light_from_screen.apply_to_point(Point3f::new(p.x(), p.y(), 0.0)));
|
||||||
|
cos_theta(w.normalize()).powi(3)
|
||||||
|
};
|
||||||
|
|
||||||
|
let d = image.get_sampling_distribution(dwda, screen_bounds);
|
||||||
|
let distrib =
|
||||||
|
PiecewiseConstant2D::new(d.as_slice(), d.x_size() as usize, d.y_size() as usize);
|
||||||
|
|
||||||
let specific = ProjectionLight::new(
|
let specific = ProjectionLight::new(
|
||||||
render_from_light_flip,
|
render_from_light_flip,
|
||||||
medium.into(),
|
medium.into(),
|
||||||
scale,
|
scale,
|
||||||
image.upload(arena),
|
image.upload(arena),
|
||||||
colorspace.upload(arena),
|
colorspace.upload(arena),
|
||||||
|
distrib.upload(arena),
|
||||||
fov,
|
fov,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ impl CreateSpotLight for SpotLight {
|
||||||
MediumInterface::empty(),
|
MediumInterface::empty(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let iemit = Ptr::from(&lookup_spectrum(&le));
|
let iemit = Ptr::from(&*lookup_spectrum(&le));
|
||||||
Self {
|
Self {
|
||||||
base,
|
base,
|
||||||
iemit,
|
iemit,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::core::image::Image;
|
use crate::core::image::Image;
|
||||||
use crate::core::material::CreateMaterial;
|
use crate::core::material::CreateMaterial;
|
||||||
use crate::spectra::get_colorspace_context;
|
use crate::spectra::{get_colorspace_context, get_colorspace_device};
|
||||||
use crate::utils::{Arena, FileLoc, TextureParameterDictionary, Upload};
|
use crate::utils::{Arena, FileLoc, TextureParameterDictionary, Upload};
|
||||||
use shared::bxdfs::HairBxDF;
|
use shared::bxdfs::HairBxDF;
|
||||||
use shared::core::material::Material;
|
use shared::core::material::Material;
|
||||||
|
|
@ -33,10 +33,9 @@ impl CreateMaterial for HairMaterial {
|
||||||
|
|
||||||
// Default distribution if nothing is spceified
|
// Default distribution if nothing is spceified
|
||||||
let sigma_a = if sigma_a.is_none() && !reflectance.is_none() && !has_melanin {
|
let sigma_a = if sigma_a.is_none() && !reflectance.is_none() && !has_melanin {
|
||||||
let stdcs = get_colorspace_context();
|
let stdcs = get_colorspace_device();
|
||||||
let default_rgb = HairBxDF::sigma_a_from_concentration(1.3, 0.0, stdcs);
|
let default_rgb = HairBxDF::sigma_a_from_concentration(1.3, 0.0, stdcs);
|
||||||
let spectrum =
|
let spectrum = Spectrum::RGBUnbounded(default_rgb);
|
||||||
Spectrum::RGBUnbounded(RGBUnboundedSpectrum::new(stdcs.srgb, default_rgb));
|
|
||||||
let texture = SpectrumTexture::Constant(SpectrumConstantTexture::new(spectrum));
|
let texture = SpectrumTexture::Constant(SpectrumConstantTexture::new(spectrum));
|
||||||
Some(Arc::new(texture))
|
Some(Arc::new(texture))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -73,3 +72,15 @@ impl CreateMaterial for SubsurfaceMaterial {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CreateMaterial for MeasuredMaterial {
|
||||||
|
fn create(
|
||||||
|
_parameters: &TextureParameterDictionary,
|
||||||
|
_normal_map: Option<Arc<Image>>,
|
||||||
|
_named_materials: &HashMap<String, Material>,
|
||||||
|
_loc: &FileLoc,
|
||||||
|
_arena: &mut Arena,
|
||||||
|
) -> Result<Material> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,5 @@ pub mod complex;
|
||||||
pub mod conductor;
|
pub mod conductor;
|
||||||
pub mod dielectric;
|
pub mod dielectric;
|
||||||
pub mod diffuse;
|
pub mod diffuse;
|
||||||
|
pub mod measured;
|
||||||
pub mod mix;
|
pub mod mix;
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,8 @@ pub mod halton;
|
||||||
pub mod independent;
|
pub mod independent;
|
||||||
pub mod sobol;
|
pub mod sobol;
|
||||||
pub mod stratified;
|
pub mod stratified;
|
||||||
|
|
||||||
|
pub use halton::*;
|
||||||
|
pub use independent::*;
|
||||||
|
pub use sobol::*;
|
||||||
|
pub use stratified::*;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use crate::core::texture::FloatTexture;
|
||||||
use crate::shapes::mesh::BilinearPatchMesh;
|
use crate::shapes::mesh::BilinearPatchMesh;
|
||||||
use crate::utils::sampling::PiecewiseConstant2D;
|
use crate::utils::sampling::PiecewiseConstant2D;
|
||||||
use crate::utils::{Arena, FileLoc, ParameterDictionary};
|
use crate::utils::{Arena, FileLoc, ParameterDictionary};
|
||||||
|
use anyhow::Result;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use shared::core::shape::Shape;
|
use shared::core::shape::Shape;
|
||||||
use shared::shapes::BilinearPatchShape;
|
use shared::shapes::BilinearPatchShape;
|
||||||
|
|
@ -18,10 +19,10 @@ impl CreateShape for BilinearPatchShape {
|
||||||
_object_from_render: Transform,
|
_object_from_render: Transform,
|
||||||
reverse_orientation: bool,
|
reverse_orientation: bool,
|
||||||
parameters: ParameterDictionary,
|
parameters: ParameterDictionary,
|
||||||
_float_textures: HashMap<String, FloatTexture>,
|
_float_textures: HashMap<String, Arc<FloatTexture>>,
|
||||||
_loc: FileLoc,
|
_loc: FileLoc,
|
||||||
_arena: &mut Arena,
|
_arena: &mut Arena,
|
||||||
) -> Result<Vec<Shape>, String> {
|
) -> Result<Vec<Shape>> {
|
||||||
let mut vertex_indices = parameters.get_int_array("indices");
|
let mut vertex_indices = parameters.get_int_array("indices");
|
||||||
let p = parameters.get_point3f_array("P");
|
let p = parameters.get_point3f_array("P");
|
||||||
let mut uv = parameters.get_point2f_array("uv");
|
let mut uv = parameters.get_point2f_array("uv");
|
||||||
|
|
@ -32,10 +33,9 @@ impl CreateShape for BilinearPatchShape {
|
||||||
if p.len() == 4 {
|
if p.len() == 4 {
|
||||||
vertex_indices = vec![0, 1, 2, 3];
|
vertex_indices = vec![0, 1, 2, 3];
|
||||||
} else {
|
} else {
|
||||||
return Err(
|
return Err(anyhow!(
|
||||||
"Vertex indices \"indices\" must be provided with bilinear patch mesh shape."
|
"Vertex indices \"indices\" must be provided with bilinear patch mesh shape."
|
||||||
.into(),
|
));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else if vertex_indices.len() % 4 != 0 {
|
} else if vertex_indices.len() % 4 != 0 {
|
||||||
let excess = vertex_indices.len() % 4;
|
let excess = vertex_indices.len() % 4;
|
||||||
|
|
@ -49,9 +49,9 @@ impl CreateShape for BilinearPatchShape {
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.is_empty() {
|
if p.is_empty() {
|
||||||
return Err(
|
return Err(anyhow!(
|
||||||
"Vertex positions \"P\" must be provided with bilinear patch mesh shape.".into(),
|
"Vertex positions \"P\" must be provided with bilinear patch mesh shape."
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !uv.is_empty() && uv.len() != p.len() {
|
if !uv.is_empty() && uv.len() != p.len() {
|
||||||
|
|
@ -66,7 +66,7 @@ impl CreateShape for BilinearPatchShape {
|
||||||
|
|
||||||
for (_, &idx) in vertex_indices.iter().enumerate() {
|
for (_, &idx) in vertex_indices.iter().enumerate() {
|
||||||
if idx < 0 || idx as usize >= p.len() {
|
if idx < 0 || idx as usize >= p.len() {
|
||||||
return Err(format!(
|
return Err(anyhow!(
|
||||||
"Bilinear patch mesh has out-of-bounds vertex index {} ({} \"P\" values were given). Discarding this mesh.",
|
"Bilinear patch mesh has out-of-bounds vertex index {} ({} \"P\" values were given). Discarding this mesh.",
|
||||||
idx,
|
idx,
|
||||||
p.len()
|
p.len()
|
||||||
|
|
@ -85,26 +85,22 @@ impl CreateShape for BilinearPatchShape {
|
||||||
}
|
}
|
||||||
|
|
||||||
let filename = parameters.get_one_string("emissionfilename", "");
|
let filename = parameters.get_one_string("emissionfilename", "");
|
||||||
let mut image_dist = None;
|
|
||||||
|
|
||||||
if !filename.is_empty() {
|
let image_dist = if !filename.is_empty() {
|
||||||
if !uv.is_empty() {
|
if !uv.is_empty() {
|
||||||
warn!(
|
warn!(
|
||||||
"\"emissionfilename\" is currently ignored for bilinear patches if \"uv\" coordinates have been provided--sorry!"
|
"\"emissionfilename\" is currently ignored for bilinear patches if \"uv\" coordinates have been provided--sorry!"
|
||||||
);
|
);
|
||||||
|
None
|
||||||
} else {
|
} else {
|
||||||
match Image::read(Path::new(&filename), None) {
|
let im = Image::read(Path::new(&filename), None)?;
|
||||||
Ok(mut im) => {
|
|
||||||
let mut img = im.image;
|
let mut img = im.image;
|
||||||
img.flip_y();
|
img.flip_y();
|
||||||
image_dist = Some(PiecewiseConstant2D::from_image(&img));
|
Some(PiecewiseConstant2D::from_image(&img))
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
warn!("Failed to load emission image \"{}\": {}", filename, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let host = BilinearPatchMesh::new(
|
let host = BilinearPatchMesh::new(
|
||||||
&render_from_object,
|
&render_from_object,
|
||||||
|
|
@ -113,7 +109,7 @@ impl CreateShape for BilinearPatchShape {
|
||||||
p,
|
p,
|
||||||
n,
|
n,
|
||||||
uv,
|
uv,
|
||||||
None,
|
image_dist,
|
||||||
);
|
);
|
||||||
|
|
||||||
let host_arc = Arc::new(host);
|
let host_arc = Arc::new(host);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ use crate::Arena;
|
||||||
use crate::core::shape::CreateShape;
|
use crate::core::shape::CreateShape;
|
||||||
use crate::core::texture::FloatTexture;
|
use crate::core::texture::FloatTexture;
|
||||||
use crate::utils::{FileLoc, ParameterDictionary};
|
use crate::utils::{FileLoc, ParameterDictionary};
|
||||||
|
use anyhow::{Result, anyhow};
|
||||||
use shared::Float;
|
use shared::Float;
|
||||||
use shared::core::geometry::{Normal3f, Point3f};
|
use shared::core::geometry::{Normal3f, Point3f};
|
||||||
use shared::core::shape::Shape;
|
use shared::core::shape::Shape;
|
||||||
|
|
@ -14,6 +15,7 @@ use shared::utils::splines::{
|
||||||
|
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub fn create_curve(
|
pub fn create_curve(
|
||||||
render_from_object: Transform,
|
render_from_object: Transform,
|
||||||
|
|
@ -60,17 +62,17 @@ impl CreateShape for CurveShape {
|
||||||
object_from_render: Transform,
|
object_from_render: Transform,
|
||||||
reverse_orientation: bool,
|
reverse_orientation: bool,
|
||||||
parameters: ParameterDictionary,
|
parameters: ParameterDictionary,
|
||||||
_float_textures: HashMap<String, FloatTexture>,
|
_float_textures: HashMap<String, Arc<FloatTexture>>,
|
||||||
_loc: FileLoc,
|
_loc: FileLoc,
|
||||||
_arena: &mut Arena,
|
_arena: &mut Arena,
|
||||||
) -> Result<Vec<Shape>, String> {
|
) -> Result<Vec<Shape>> {
|
||||||
let width = parameters.get_one_float("width", 1.0);
|
let width = parameters.get_one_float("width", 1.0);
|
||||||
let width0 = parameters.get_one_float("width0", width);
|
let width0 = parameters.get_one_float("width0", width);
|
||||||
let width1 = parameters.get_one_float("width1", width);
|
let width1 = parameters.get_one_float("width1", width);
|
||||||
|
|
||||||
let degree = parameters.get_one_int("degree", 3);
|
let degree = parameters.get_one_int("degree", 3);
|
||||||
if degree != 2 && degree != 3 {
|
if degree != 2 && degree != 3 {
|
||||||
return Err(format!(
|
return Err(anyhow!(
|
||||||
"Invalid degree {}: only degree 2 and 3 curves are supported.",
|
"Invalid degree {}: only degree 2 and 3 curves are supported.",
|
||||||
degree
|
degree
|
||||||
));
|
));
|
||||||
|
|
@ -78,7 +80,7 @@ impl CreateShape for CurveShape {
|
||||||
|
|
||||||
let basis = parameters.get_one_string("basis", "bezier");
|
let basis = parameters.get_one_string("basis", "bezier");
|
||||||
if basis != "bezier" && basis != "bspline" {
|
if basis != "bezier" && basis != "bspline" {
|
||||||
return Err(format!(
|
return Err(anyhow!(
|
||||||
"Invalid basis \"{}\": only \"bezier\" and \"bspline\" are supported.",
|
"Invalid basis \"{}\": only \"bezier\" and \"bspline\" are supported.",
|
||||||
basis
|
basis
|
||||||
));
|
));
|
||||||
|
|
@ -91,7 +93,7 @@ impl CreateShape for CurveShape {
|
||||||
if cp.len() <= degree as usize
|
if cp.len() <= degree as usize
|
||||||
|| ((cp.len() - 1 - degree as usize) % degree as usize) != 0
|
|| ((cp.len() - 1 - degree as usize) % degree as usize) != 0
|
||||||
{
|
{
|
||||||
return Err(format!(
|
return Err(anyhow!(
|
||||||
"Invalid number of control points {}: for the degree {} Bezier basis {} + n * {} are required.",
|
"Invalid number of control points {}: for the degree {} Bezier basis {} + n * {} are required.",
|
||||||
cp.len(),
|
cp.len(),
|
||||||
degree,
|
degree,
|
||||||
|
|
@ -102,7 +104,7 @@ impl CreateShape for CurveShape {
|
||||||
n_segments = (cp.len() - 1) / degree as usize;
|
n_segments = (cp.len() - 1) / degree as usize;
|
||||||
} else {
|
} else {
|
||||||
if cp.len() < (degree + 1) as usize {
|
if cp.len() < (degree + 1) as usize {
|
||||||
return Err(format!(
|
return Err(anyhow!(
|
||||||
"Invalid number of control points {}: for the degree {} b-spline basis, must have >= {}.",
|
"Invalid number of control points {}: for the degree {} b-spline basis, must have >= {}.",
|
||||||
cp.len(),
|
cp.len(),
|
||||||
degree,
|
degree,
|
||||||
|
|
@ -118,7 +120,7 @@ impl CreateShape for CurveShape {
|
||||||
"ribbon" => CurveType::Ribbon,
|
"ribbon" => CurveType::Ribbon,
|
||||||
"cylinder" => CurveType::Cylinder,
|
"cylinder" => CurveType::Cylinder,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(format!("Unknown curve type \"{}\".", curve_type_str));
|
return Err(anyhow!("Unknown curve type \"{}\".", curve_type_str));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -128,7 +130,7 @@ impl CreateShape for CurveShape {
|
||||||
warn!("Curve normals are only used with \"ribbon\" type curves. Discarding.");
|
warn!("Curve normals are only used with \"ribbon\" type curves. Discarding.");
|
||||||
n.clear();
|
n.clear();
|
||||||
} else if n.len() != n_segments + 1 {
|
} else if n.len() != n_segments + 1 {
|
||||||
return Err(format!(
|
return Err(anyhow!(
|
||||||
"Invalid number of normals {}: must provide {} normals for ribbon curves with {} segments.",
|
"Invalid number of normals {}: must provide {} normals for ribbon curves with {} segments.",
|
||||||
n.len(),
|
n.len(),
|
||||||
n_segments + 1,
|
n_segments + 1,
|
||||||
|
|
@ -136,9 +138,9 @@ impl CreateShape for CurveShape {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
} else if curve_type == CurveType::Ribbon {
|
} else if curve_type == CurveType::Ribbon {
|
||||||
return Err(
|
return Err(anyhow!(
|
||||||
"Must provide normals \"N\" at curve endpoints with ribbon curves.".to_string(),
|
"Must provide normals \"N\" at curve endpoints with ribbon curves."
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let use_gpu = false; // Replace with actual config check
|
let use_gpu = false; // Replace with actual config check
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
use crate::core::shape::CreateShape;
|
use crate::core::shape::CreateShape;
|
||||||
use crate::core::texture::FloatTexture;
|
use crate::core::texture::FloatTexture;
|
||||||
use crate::utils::{Arena, FileLoc, ParameterDictionary};
|
use crate::utils::{Arena, FileLoc, ParameterDictionary};
|
||||||
|
use anyhow::Result;
|
||||||
use shared::core::shape::Shape;
|
use shared::core::shape::Shape;
|
||||||
use shared::shapes::CylinderShape;
|
use shared::shapes::CylinderShape;
|
||||||
use shared::utils::Transform;
|
use shared::utils::Transform;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
impl CreateShape for CylinderShape {
|
impl CreateShape for CylinderShape {
|
||||||
fn create(
|
fn create(
|
||||||
|
|
@ -12,10 +14,10 @@ impl CreateShape for CylinderShape {
|
||||||
object_from_render: Transform,
|
object_from_render: Transform,
|
||||||
reverse_orientation: bool,
|
reverse_orientation: bool,
|
||||||
parameters: ParameterDictionary,
|
parameters: ParameterDictionary,
|
||||||
_float_textures: HashMap<String, FloatTexture>,
|
_float_textures: HashMap<String, Arc<FloatTexture>>,
|
||||||
_loc: FileLoc,
|
_loc: FileLoc,
|
||||||
arena: &mut Arena,
|
arena: &mut Arena,
|
||||||
) -> Result<Vec<Shape>, String> {
|
) -> Result<Vec<Shape>> {
|
||||||
let radius = parameters.get_one_float("radius", 1.);
|
let radius = parameters.get_one_float("radius", 1.);
|
||||||
let z_min = parameters.get_one_float("zmin", -1.);
|
let z_min = parameters.get_one_float("zmin", -1.);
|
||||||
let z_max = parameters.get_one_float("zmax", 1.);
|
let z_max = parameters.get_one_float("zmax", 1.);
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
use crate::core::shape::CreateShape;
|
use crate::core::shape::CreateShape;
|
||||||
use crate::core::texture::FloatTexture;
|
use crate::core::texture::FloatTexture;
|
||||||
use crate::utils::{Arena, FileLoc, ParameterDictionary};
|
use crate::utils::{Arena, FileLoc, ParameterDictionary};
|
||||||
|
use anyhow::Result;
|
||||||
use shared::core::shape::Shape;
|
use shared::core::shape::Shape;
|
||||||
use shared::shapes::DiskShape;
|
use shared::shapes::DiskShape;
|
||||||
use shared::utils::Transform;
|
use shared::utils::Transform;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
impl CreateShape for DiskShape {
|
impl CreateShape for DiskShape {
|
||||||
fn create(
|
fn create(
|
||||||
|
|
@ -12,10 +14,10 @@ impl CreateShape for DiskShape {
|
||||||
object_from_render: Transform,
|
object_from_render: Transform,
|
||||||
reverse_orientation: bool,
|
reverse_orientation: bool,
|
||||||
parameters: ParameterDictionary,
|
parameters: ParameterDictionary,
|
||||||
_float_textures: HashMap<String, FloatTexture>,
|
_float_textures: HashMap<String, Arc<FloatTexture>>,
|
||||||
_loc: FileLoc,
|
_loc: FileLoc,
|
||||||
arena: &mut Arena,
|
arena: &mut Arena,
|
||||||
) -> Result<Vec<Shape>, String> {
|
) -> Result<Vec<Shape>> {
|
||||||
let height = parameters.get_one_float("height", 0.);
|
let height = parameters.get_one_float("height", 0.);
|
||||||
let radius = parameters.get_one_float("radius", 1.);
|
let radius = parameters.get_one_float("radius", 1.);
|
||||||
let inner_radius = parameters.get_one_float("innerradius", 0.);
|
let inner_radius = parameters.get_one_float("innerradius", 0.);
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,16 @@ pub mod curves;
|
||||||
pub mod cylinder;
|
pub mod cylinder;
|
||||||
pub mod disk;
|
pub mod disk;
|
||||||
pub mod mesh;
|
pub mod mesh;
|
||||||
pub mod mesh;
|
|
||||||
pub mod sphere;
|
pub mod sphere;
|
||||||
pub mod triangle;
|
pub mod triangle;
|
||||||
|
|
||||||
// pub use bilinear::*;
|
pub use bilinear::*;
|
||||||
|
pub use curves::*;
|
||||||
|
pub use cylinder::*;
|
||||||
|
pub use disk::*;
|
||||||
pub use mesh::*;
|
pub use mesh::*;
|
||||||
|
pub use sphere::*;
|
||||||
|
pub use triangle::*;
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
use crate::core::shape::CreateShape;
|
use crate::core::shape::CreateShape;
|
||||||
use crate::core::texture::FloatTexture;
|
use crate::core::texture::FloatTexture;
|
||||||
use crate::utils::{Arena, FileLoc, ParameterDictionary};
|
use crate::utils::{Arena, FileLoc, ParameterDictionary};
|
||||||
|
use anyhow::Result;
|
||||||
use shared::core::shape::Shape;
|
use shared::core::shape::Shape;
|
||||||
use shared::shapes::SphereShape;
|
use shared::shapes::SphereShape;
|
||||||
use shared::utils::Transform;
|
use shared::utils::Transform;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
impl CreateShape for SphereShape {
|
impl CreateShape for SphereShape {
|
||||||
fn create(
|
fn create(
|
||||||
|
|
@ -12,10 +14,10 @@ impl CreateShape for SphereShape {
|
||||||
object_from_render: Transform,
|
object_from_render: Transform,
|
||||||
reverse_orientation: bool,
|
reverse_orientation: bool,
|
||||||
parameters: ParameterDictionary,
|
parameters: ParameterDictionary,
|
||||||
_float_textures: HashMap<String, FloatTexture>,
|
_float_textures: HashMap<String, Arc<FloatTexture>>,
|
||||||
_loc: FileLoc,
|
_loc: FileLoc,
|
||||||
arena: &mut Arena,
|
arena: &mut Arena,
|
||||||
) -> Result<Vec<Shape>, String> {
|
) -> Result<Vec<Shape>> {
|
||||||
let radius = parameters.get_one_float("radius", 1.);
|
let radius = parameters.get_one_float("radius", 1.);
|
||||||
let zmin = parameters.get_one_float("zmin", -radius);
|
let zmin = parameters.get_one_float("zmin", -radius);
|
||||||
let zmax = parameters.get_one_float("zmax", radius);
|
let zmax = parameters.get_one_float("zmax", radius);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ use crate::core::shape::{ALL_TRIANGLE_MESHES, CreateShape};
|
||||||
use crate::core::texture::FloatTexture;
|
use crate::core::texture::FloatTexture;
|
||||||
use crate::shapes::mesh::TriangleMesh;
|
use crate::shapes::mesh::TriangleMesh;
|
||||||
use crate::utils::{Arena, FileLoc, ParameterDictionary};
|
use crate::utils::{Arena, FileLoc, ParameterDictionary};
|
||||||
|
use anyhow::{Result, anyhow};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use shared::core::shape::Shape;
|
use shared::core::shape::Shape;
|
||||||
use shared::shapes::TriangleShape;
|
use shared::shapes::TriangleShape;
|
||||||
|
|
@ -15,10 +16,10 @@ impl CreateShape for TriangleShape {
|
||||||
_object_from_render: Transform,
|
_object_from_render: Transform,
|
||||||
reverse_orientation: bool,
|
reverse_orientation: bool,
|
||||||
parameters: ParameterDictionary,
|
parameters: ParameterDictionary,
|
||||||
_float_texture: HashMap<String, FloatTexture>,
|
_float_texture: HashMap<String, Arc<FloatTexture>>,
|
||||||
_loc: FileLoc,
|
_loc: FileLoc,
|
||||||
_arena: &mut Arena,
|
_arena: &mut Arena,
|
||||||
) -> Result<Vec<Shape>, String> {
|
) -> Result<Vec<Shape>> {
|
||||||
let mut vertex_indices = parameters.get_int_array("indices");
|
let mut vertex_indices = parameters.get_int_array("indices");
|
||||||
let p = parameters.get_point3f_array("P");
|
let p = parameters.get_point3f_array("P");
|
||||||
let mut uvs = parameters.get_point2f_array("uv");
|
let mut uvs = parameters.get_point2f_array("uv");
|
||||||
|
|
@ -28,9 +29,9 @@ impl CreateShape for TriangleShape {
|
||||||
if vertex_indices.is_empty() {
|
if vertex_indices.is_empty() {
|
||||||
if p.len() == 3 {
|
if p.len() == 3 {
|
||||||
} else {
|
} else {
|
||||||
return Err(
|
return Err(anyhow!(
|
||||||
"Vertex indices \"indices\" must be provided with triangle mesh.".to_string(),
|
"Vertex indices \"indices\" must be provided with triangle mesh."
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
} else if vertex_indices.len() % 3 != 0 {
|
} else if vertex_indices.len() % 3 != 0 {
|
||||||
let excess = vertex_indices.len() % 3;
|
let excess = vertex_indices.len() % 3;
|
||||||
|
|
@ -44,7 +45,9 @@ impl CreateShape for TriangleShape {
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.is_empty() {
|
if p.is_empty() {
|
||||||
return Err("Vertex positions \"P\" must be provided with triangle mesh.".to_string());
|
return Err(anyhow!(
|
||||||
|
"Vertex positions \"P\" must be provided with triangle mesh."
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !uvs.is_empty() && uvs.len() != p.len() {
|
if !uvs.is_empty() && uvs.len() != p.len() {
|
||||||
|
|
@ -65,7 +68,7 @@ impl CreateShape for TriangleShape {
|
||||||
for (_, &index) in vertex_indices.iter().enumerate() {
|
for (_, &index) in vertex_indices.iter().enumerate() {
|
||||||
// Check for negative indices (if keeping i32) or out of bounds
|
// Check for negative indices (if keeping i32) or out of bounds
|
||||||
if index < 0 || index as usize >= p.len() {
|
if index < 0 || index as usize >= p.len() {
|
||||||
return Err(format!(
|
return Err(anyhow!(
|
||||||
"TriangleMesh has out-of-bounds vertex index {} ({} \"P\" values were given). Discarding this mesh.",
|
"TriangleMesh has out-of-bounds vertex index {} ({} \"P\" values were given). Discarding this mesh.",
|
||||||
index,
|
index,
|
||||||
p.len()
|
p.len()
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use crate::spectra::colorspace::RGBColorSpaceData;
|
||||||
use shared::core::geometry::Point2f;
|
use shared::core::geometry::Point2f;
|
||||||
use shared::core::spectrum::Spectrum;
|
use shared::core::spectrum::Spectrum;
|
||||||
use shared::core::spectrum::StandardSpectra;
|
use shared::core::spectrum::StandardSpectra;
|
||||||
|
use shared::spectra::DeviceStandardColorSpaces;
|
||||||
use shared::spectra::cie::{CIE_D65, CIE_X, CIE_Y, CIE_Z};
|
use shared::spectra::cie::{CIE_D65, CIE_X, CIE_Y, CIE_Z};
|
||||||
use shared::utils::Ptr;
|
use shared::utils::Ptr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
@ -116,3 +117,12 @@ pub fn get_colorspace_context() -> StandardColorSpaces {
|
||||||
aces2065_1: ACES.clone().into(),
|
aces2065_1: ACES.clone().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_colorspace_device() -> DeviceStandardColorSpaces {
|
||||||
|
DeviceStandardColorSpaces {
|
||||||
|
srgb: Ptr::from(&SRGB.view),
|
||||||
|
dci_p3: Ptr::from(&DCI_P3.view),
|
||||||
|
rec2020: Ptr::from(&REC2020.view),
|
||||||
|
aces2065_1: Ptr::from(&ACES.view),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
57
src/textures/bilerp.rs
Normal file
57
src/textures/bilerp.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
use crate::core::texture::{CreateSpectrumTexture, FloatTextureTrait, SpectrumTextureTrait};
|
||||||
|
use anyhow::Result;
|
||||||
|
use shared::core::texture::SpectrumType;
|
||||||
|
use shared::{
|
||||||
|
textures::{FloatBilerpTexture, SpectrumBilerpTexture},
|
||||||
|
utils::Transform,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
core::texture::FloatTexture,
|
||||||
|
utils::{FileLoc, TextureParameterDictionary},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait CreateFloatBilerpTexture {
|
||||||
|
fn create(
|
||||||
|
render_from_texture: Transform,
|
||||||
|
parameters: TextureParameterDictionary,
|
||||||
|
loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreateFloatBilerpTexture for FloatBilerpTexture {
|
||||||
|
fn create(
|
||||||
|
_render_from_texture: Transform,
|
||||||
|
_parameters: TextureParameterDictionary,
|
||||||
|
_loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FloatTextureTrait for FloatBilerpTexture {
|
||||||
|
fn evaluate(&self, _ctx: &shared::core::texture::TextureEvalContext) -> shared::Float {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreateSpectrumTexture for SpectrumBilerpTexture {
|
||||||
|
fn create(
|
||||||
|
_render_from_texture: Transform,
|
||||||
|
_parameters: TextureParameterDictionary,
|
||||||
|
_spectrum_type: SpectrumType,
|
||||||
|
_loc: FileLoc,
|
||||||
|
) -> Result<SpectrumTexture> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpectrumTextureTrait for SpectrumBilerpTexture {
|
||||||
|
fn evaluate(
|
||||||
|
&self,
|
||||||
|
_ctx: &shared::core::texture::TextureEvalContext,
|
||||||
|
_lambda: &shared::spectra::SampledWavelengths,
|
||||||
|
) -> shared::spectra::SampledSpectrum {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
59
src/textures/checkerboard.rs
Normal file
59
src/textures/checkerboard.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use shared::{
|
||||||
|
core::texture::SpectrumType,
|
||||||
|
textures::{FloatCheckerboardTexture, SpectrumCheckerboardTexture},
|
||||||
|
utils::Transform,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
core::texture::{
|
||||||
|
CreateSpectrumTexture, FloatTexture, FloatTextureTrait, SpectrumTexture,
|
||||||
|
SpectrumTextureTrait,
|
||||||
|
},
|
||||||
|
utils::{FileLoc, TextureParameterDictionary},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait CreateFloatCheckerboardTexture {
|
||||||
|
fn create(
|
||||||
|
render_from_texture: Transform,
|
||||||
|
parameters: TextureParameterDictionary,
|
||||||
|
loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreateFloatCheckerboardTexture for FloatCheckerboardTexture {
|
||||||
|
fn create(
|
||||||
|
_render_from_texture: Transform,
|
||||||
|
_parameters: TextureParameterDictionary,
|
||||||
|
_loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FloatTextureTrait for FloatCheckerboardTexture {
|
||||||
|
fn evaluate(&self, _ctx: &shared::core::texture::TextureEvalContext) -> shared::Float {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreateSpectrumTexture for SpectrumCheckerboardTexture {
|
||||||
|
fn create(
|
||||||
|
_render_from_texture: Transform,
|
||||||
|
_parameters: TextureParameterDictionary,
|
||||||
|
_spectrum_type: SpectrumType,
|
||||||
|
_loc: FileLoc,
|
||||||
|
) -> Result<SpectrumTexture> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpectrumTextureTrait for SpectrumCheckerboardTexture {
|
||||||
|
fn evaluate(
|
||||||
|
&self,
|
||||||
|
_ctx: &shared::core::texture::TextureEvalContext,
|
||||||
|
_lambda: &shared::spectra::SampledWavelengths,
|
||||||
|
) -> shared::spectra::SampledSpectrum {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
59
src/textures/constant.rs
Normal file
59
src/textures/constant.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use shared::{
|
||||||
|
core::texture::{SpectrumType, TextureEvalContext},
|
||||||
|
textures::{FloatConstantTexture, SpectrumConstantTexture},
|
||||||
|
utils::Transform,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
core::texture::{
|
||||||
|
CreateSpectrumTexture, FloatTexture, FloatTextureTrait, SpectrumTextureTrait,
|
||||||
|
SpectrumTextureTrait,
|
||||||
|
},
|
||||||
|
utils::{FileLoc, TextureParameterDictionary},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait CreateFloatConstantTexture {
|
||||||
|
fn create(
|
||||||
|
render_from_texture: Transform,
|
||||||
|
parameters: TextureParameterDictionary,
|
||||||
|
loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreateFloatConstantTexture for FloatConstantTexture {
|
||||||
|
fn create(
|
||||||
|
_render_from_texture: Transform,
|
||||||
|
_parameters: TextureParameterDictionary,
|
||||||
|
_loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FloatTextureTrait for FloatConstantTexture {
|
||||||
|
fn evaluate(&self, _ctx: &TextureEvalContext) -> shared::Float {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreateSpectrumTexture for SpectrumConstantTexture {
|
||||||
|
fn create(
|
||||||
|
_render_from_texture: Transform,
|
||||||
|
_parameters: TextureParameterDictionary,
|
||||||
|
_spectrum_type: SpectrumType,
|
||||||
|
_loc: FileLoc,
|
||||||
|
) -> Result<SpectrumTexture> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpectrumTextureTrait for SpectrumConstantTexture {
|
||||||
|
fn evaluate(
|
||||||
|
&self,
|
||||||
|
_ctx: &TextureEvalContext,
|
||||||
|
_lambda: &shared::spectra::SampledWavelengths,
|
||||||
|
) -> shared::spectra::SampledSpectrum {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/textures/dots.rs
Normal file
55
src/textures/dots.rs
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use shared::{
|
||||||
|
textures::{FloatDotsTexture, SpectrumDotsTexture},
|
||||||
|
utils::Transform,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
core::texture::{CreateSpectrumTexture, FloatTexture, FloatTextureTrait, SpectrumTextureTrait},
|
||||||
|
utils::{FileLoc, TextureParameterDictionary},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait CreateFloatDotsTexture {
|
||||||
|
fn create(
|
||||||
|
render_from_texture: Transform,
|
||||||
|
parameters: TextureParameterDictionary,
|
||||||
|
loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FloatTextureTrait for FloatDotsTexture {
|
||||||
|
fn evaluate(&self, ctx: &shared::core::texture::TextureEvalContext) -> shared::Float {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreateFloatDotsTexture for FloatDotsTexture {
|
||||||
|
fn create(
|
||||||
|
_render_from_texture: Transform,
|
||||||
|
_parameters: TextureParameterDictionary,
|
||||||
|
_loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpectrumTextureTrait for SpectrumScaledTexture {
|
||||||
|
fn evaluate(
|
||||||
|
&self,
|
||||||
|
_ctx: &shared::core::texture::TextureEvalContext,
|
||||||
|
_lambda: &shared::spectra::SampledWavelengths,
|
||||||
|
) -> shared::spectra::SampledSpectrum {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreateSpectrumTexture for SpectrumDotsTexture {
|
||||||
|
fn create(
|
||||||
|
_render_from_texture: Transform,
|
||||||
|
_parameters: TextureParameterDictionary,
|
||||||
|
_spectrum_type: SpectrumType,
|
||||||
|
_loc: FileLoc,
|
||||||
|
) -> Result<SpectrumTexture> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/textures/fbm.rs
Normal file
32
src/textures/fbm.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use shared::core::texture::TextureEvalContext;
|
||||||
|
use shared::{textures::FBmTexture, utils::Transform};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
core::texture::{FloatTexture, FloatTextureTrait},
|
||||||
|
utils::{FileLoc, TextureParameterDictionary},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait CreateFBmTexture {
|
||||||
|
fn create(
|
||||||
|
render_from_texture: Transform,
|
||||||
|
parameters: TextureParameterDictionary,
|
||||||
|
loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreateFBmTexture for FBmTexture {
|
||||||
|
fn create(
|
||||||
|
_render_from_texture: Transform,
|
||||||
|
_parameters: TextureParameterDictionary,
|
||||||
|
_loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FloatTextureTrait for FBmTexture {
|
||||||
|
fn evaluate(&self, _ctx: &TextureEvalContext) -> shared::Float {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
use crate::core::texture::{FloatTextureTrait, SpectrumTextureTrait};
|
use crate::core::texture::{
|
||||||
|
CreateSpectrumTexture, FloatTexture, FloatTextureTrait, SpectrumTexture, SpectrumTextureTrait,
|
||||||
|
};
|
||||||
use crate::core::texture::{TexInfo, get_texture_cache};
|
use crate::core::texture::{TexInfo, get_texture_cache};
|
||||||
|
use crate::utils::TextureParameterDictionary;
|
||||||
use crate::utils::mipmap::{MIPMap, MIPMapFilterOptions};
|
use crate::utils::mipmap::{MIPMap, MIPMapFilterOptions};
|
||||||
|
use anyhow::Result;
|
||||||
use shared::Float;
|
use shared::Float;
|
||||||
use shared::core::color::ColorEncoding;
|
use shared::core::color::ColorEncoding;
|
||||||
use shared::core::color::RGB;
|
use shared::core::color::RGB;
|
||||||
|
|
@ -147,6 +151,17 @@ impl SpectrumTextureTrait for SpectrumImageTexture {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CreateSpectrumTexture for SpectrumImageTexture {
|
||||||
|
fn create(
|
||||||
|
_render_from_texture: Transform,
|
||||||
|
_parameters: TextureParameterDictionary,
|
||||||
|
_spectrum_type: SpectrumType,
|
||||||
|
_loc: FileLoc,
|
||||||
|
) -> Result<SpectrumTexture> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FloatImageTexture {
|
pub struct FloatImageTexture {
|
||||||
pub base: ImageTextureBase,
|
pub base: ImageTextureBase,
|
||||||
|
|
@ -181,3 +196,21 @@ impl FloatTextureTrait for FloatImageTexture {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait CreateFloatImageTexture {
|
||||||
|
fn create(
|
||||||
|
render_from_texture: Transform,
|
||||||
|
parameters: TextureParameterDictionary,
|
||||||
|
loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreateFloatImageTexture for FloatImageTexture {
|
||||||
|
fn create(
|
||||||
|
_render_from_texture: Transform,
|
||||||
|
_parameters: TextureParameterDictionary,
|
||||||
|
_loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
23
src/textures/marble.rs
Normal file
23
src/textures/marble.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
use crate::core::texture::{CreateSpectrumTexture, SpectrumTexture, SpectrumTextureTrait};
|
||||||
|
use shared::textures::MarbleTexture;
|
||||||
|
|
||||||
|
impl SpectrumTextureTrait for MarbleTexture {
|
||||||
|
fn evaluate(
|
||||||
|
&self,
|
||||||
|
_ctx: &shared::core::texture::TextureEvalContext,
|
||||||
|
_lambda: &shared::spectra::SampledWavelengths,
|
||||||
|
) -> shared::spectra::SampledSpectrum {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreateSpectrumTexture for MarbleTexture {
|
||||||
|
fn create(
|
||||||
|
render_from_texture: shared::utils::Transform,
|
||||||
|
parameters: crate::utils::TextureParameterDictionary,
|
||||||
|
spectrum_type: SpectrumType,
|
||||||
|
loc: crate::utils::FileLoc,
|
||||||
|
) -> anyhow::Result<SpectrumTexture> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::core::texture::{
|
use crate::core::texture::{
|
||||||
FloatTexture, FloatTextureTrait, SpectrumTexture, SpectrumTextureTrait,
|
CreateSpectrumTexture, FloatTexture, FloatTextureTrait, SpectrumTexture, SpectrumTextureTrait,
|
||||||
};
|
};
|
||||||
use crate::utils::{Arena, FileLoc, TextureParameterDictionary};
|
use crate::utils::{Arena, FileLoc, TextureParameterDictionary};
|
||||||
|
use anyhow::Result;
|
||||||
use shared::Float;
|
use shared::Float;
|
||||||
use shared::core::geometry::{Vector3f, VectorLike};
|
use shared::core::geometry::{Vector3f, VectorLike};
|
||||||
use shared::core::texture::TextureEvalContext;
|
use shared::core::texture::TextureEvalContext;
|
||||||
|
|
@ -30,12 +31,12 @@ impl FloatMixTexture {
|
||||||
params: &TextureParameterDictionary,
|
params: &TextureParameterDictionary,
|
||||||
_loc: &FileLoc,
|
_loc: &FileLoc,
|
||||||
_arena: &mut Arena,
|
_arena: &mut Arena,
|
||||||
) -> FloatTexture {
|
) -> Result<FloatTexture> {
|
||||||
let tex1 = params.get_float_texture("tex1", 0.);
|
let tex1 = params.get_float_texture("tex1", 0.);
|
||||||
let tex2 = params.get_float_texture("tex2", 1.);
|
let tex2 = params.get_float_texture("tex2", 1.);
|
||||||
let amount = params.get_float_texture("amount", 0.5);
|
let amount = params.get_float_texture("amount", 0.5);
|
||||||
// arena.alloc(Self::new(tex1, tex2, amount));
|
// arena.alloc(Self::new(tex1, tex2, amount));
|
||||||
FloatTexture::Mix(Self::new(tex1, tex2, amount))
|
Ok(FloatTexture::Mix(Self::new(tex1, tex2, amount)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,13 +72,13 @@ impl FloatDirectionMixTexture {
|
||||||
params: &TextureParameterDictionary,
|
params: &TextureParameterDictionary,
|
||||||
_loc: &FileLoc,
|
_loc: &FileLoc,
|
||||||
_arena: &mut Arena,
|
_arena: &mut Arena,
|
||||||
) -> FloatTexture {
|
) -> Result<FloatTexture> {
|
||||||
let dir_raw = params.get_one_vector3f("dir", Vector3f::new(0., 1., 0.));
|
let dir_raw = params.get_one_vector3f("dir", Vector3f::new(0., 1., 0.));
|
||||||
let dir = render_from_texture.apply_to_vector(dir_raw).normalize();
|
let dir = render_from_texture.apply_to_vector(dir_raw).normalize();
|
||||||
let tex1 = params.get_float_texture("tex1", 0.);
|
let tex1 = params.get_float_texture("tex1", 0.);
|
||||||
let tex2 = params.get_float_texture("tex2", 1.);
|
let tex2 = params.get_float_texture("tex2", 1.);
|
||||||
// arena.alloc(Self::new(tex1, tex2, dir))
|
// arena.alloc(Self::new(tex1, tex2, dir))
|
||||||
FloatTexture::DirectionMix(Self::new(tex1, tex2, dir))
|
Ok(FloatTexture::DirectionMix(Self::new(tex1, tex2, dir)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,6 +95,17 @@ pub struct SpectrumMixTexture {
|
||||||
pub amount: Arc<FloatTexture>,
|
pub amount: Arc<FloatTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CreateSpectrumTexture for SpectrumMixTexture {
|
||||||
|
fn create(
|
||||||
|
render_from_texture: Transform,
|
||||||
|
parameters: TextureParameterDictionary,
|
||||||
|
spectrum_type: SpectrumType,
|
||||||
|
loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SpectrumTextureTrait for SpectrumMixTexture {
|
impl SpectrumTextureTrait for SpectrumMixTexture {
|
||||||
fn evaluate(&self, _ctx: &TextureEvalContext, _lambda: &SampledWavelengths) -> SampledSpectrum {
|
fn evaluate(&self, _ctx: &TextureEvalContext, _lambda: &SampledWavelengths) -> SampledSpectrum {
|
||||||
todo!()
|
todo!()
|
||||||
|
|
@ -107,6 +119,17 @@ pub struct SpectrumDirectionMixTexture {
|
||||||
pub dir: Vector3f,
|
pub dir: Vector3f,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CreateSpectrumTexture for SpectrumDirectionMixTexture {
|
||||||
|
fn create(
|
||||||
|
render_from_texture: Transform,
|
||||||
|
parameters: TextureParameterDictionary,
|
||||||
|
spectrum_type: SpectrumType,
|
||||||
|
loc: FileLoc,
|
||||||
|
) -> Result<SpectrumTexture> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SpectrumTextureTrait for SpectrumDirectionMixTexture {
|
impl SpectrumTextureTrait for SpectrumDirectionMixTexture {
|
||||||
fn evaluate(&self, _ctx: &TextureEvalContext, _lambda: &SampledWavelengths) -> SampledSpectrum {
|
fn evaluate(&self, _ctx: &TextureEvalContext, _lambda: &SampledWavelengths) -> SampledSpectrum {
|
||||||
todo!()
|
todo!()
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,25 @@
|
||||||
pub mod image;
|
mod bilerp;
|
||||||
pub mod mix;
|
mod checkerboard;
|
||||||
pub mod ptex;
|
mod constant;
|
||||||
pub mod scaled;
|
mod dots;
|
||||||
|
mod fbm;
|
||||||
|
mod image;
|
||||||
|
mod marble;
|
||||||
|
mod mix;
|
||||||
|
mod ptex;
|
||||||
|
mod scaled;
|
||||||
|
mod windy;
|
||||||
|
mod wrinkled;
|
||||||
|
|
||||||
|
pub use bilerp::*;
|
||||||
|
pub use checkerboard::*;
|
||||||
|
pub use constant::*;
|
||||||
|
pub use dots::*;
|
||||||
|
pub use fbm::*;
|
||||||
pub use image::*;
|
pub use image::*;
|
||||||
|
pub use marble::*;
|
||||||
pub use mix::*;
|
pub use mix::*;
|
||||||
pub use ptex::*;
|
pub use ptex::*;
|
||||||
pub use scaled::*;
|
pub use scaled::*;
|
||||||
|
pub use windy::*;
|
||||||
|
pub use wrinkled::*;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::core::texture::{FloatTexture, SpectrumTexture};
|
use crate::core::texture::{CreateSpectrumTexture, FloatTexture, SpectrumTexture};
|
||||||
use crate::core::texture::{FloatTextureTrait, SpectrumTextureTrait};
|
use crate::core::texture::{FloatTextureTrait, SpectrumTextureTrait};
|
||||||
use crate::utils::{Arena, FileLoc, TextureParameterDictionary};
|
use crate::utils::{Arena, FileLoc, TextureParameterDictionary};
|
||||||
|
use anyhow::Result;
|
||||||
use shared::Float;
|
use shared::Float;
|
||||||
use shared::core::texture::TextureEvalContext;
|
use shared::core::texture::TextureEvalContext;
|
||||||
use shared::spectra::{SampledSpectrum, SampledWavelengths};
|
use shared::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
|
|
@ -23,7 +24,7 @@ impl FloatScaledTexture {
|
||||||
params: &TextureParameterDictionary,
|
params: &TextureParameterDictionary,
|
||||||
_loc: &FileLoc,
|
_loc: &FileLoc,
|
||||||
_arena: &mut Arena,
|
_arena: &mut Arena,
|
||||||
) -> FloatTexture {
|
) -> Result<FloatTexture> {
|
||||||
let mut tex = params.get_float_texture("tex", 1.);
|
let mut tex = params.get_float_texture("tex", 1.);
|
||||||
let mut scale = params.get_float_texture("scale", 1.);
|
let mut scale = params.get_float_texture("scale", 1.);
|
||||||
|
|
||||||
|
|
@ -31,11 +32,11 @@ impl FloatScaledTexture {
|
||||||
if let FloatTexture::Constant(c_tex) = &*scale {
|
if let FloatTexture::Constant(c_tex) = &*scale {
|
||||||
let cs = c_tex.value;
|
let cs = c_tex.value;
|
||||||
if cs == 1.0 {
|
if cs == 1.0 {
|
||||||
return (*tex).clone();
|
return Ok((*tex).clone());
|
||||||
} else if let FloatTexture::Image(img_tex) = &*tex {
|
} else if let FloatTexture::Image(img_tex) = &*tex {
|
||||||
let mut image_copy = img_tex.clone();
|
let mut image_copy = img_tex.clone();
|
||||||
image_copy.base.multiply_scale(cs);
|
image_copy.base.multiply_scale(cs);
|
||||||
return FloatTexture::Image(image_copy).into();
|
return Ok(FloatTexture::Image(image_copy));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,7 +44,10 @@ impl FloatScaledTexture {
|
||||||
}
|
}
|
||||||
std::mem::swap(&mut tex, &mut scale);
|
std::mem::swap(&mut tex, &mut scale);
|
||||||
// arena.alloc(FloatScaledTexture::new(tex, scale));
|
// arena.alloc(FloatScaledTexture::new(tex, scale));
|
||||||
FloatTexture::Scaled(FloatScaledTexture::new(tex.clone(), scale.clone()))
|
Ok(FloatTexture::Scaled(FloatScaledTexture::new(
|
||||||
|
tex.clone(),
|
||||||
|
scale.clone(),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,6 +67,17 @@ pub struct SpectrumScaledTexture {
|
||||||
pub scale: Arc<FloatTexture>,
|
pub scale: Arc<FloatTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CreateSpectrumTexture for SpectrumScaledTexture {
|
||||||
|
fn create(
|
||||||
|
render_from_texture: Transform,
|
||||||
|
parameters: TextureParameterDictionary,
|
||||||
|
spectrum_type: SpectrumType,
|
||||||
|
loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SpectrumTextureTrait for SpectrumScaledTexture {
|
impl SpectrumTextureTrait for SpectrumScaledTexture {
|
||||||
fn evaluate(&self, ctx: &TextureEvalContext, lambda: &SampledWavelengths) -> SampledSpectrum {
|
fn evaluate(&self, ctx: &TextureEvalContext, lambda: &SampledWavelengths) -> SampledSpectrum {
|
||||||
let sc = self.scale.evaluate(ctx);
|
let sc = self.scale.evaluate(ctx);
|
||||||
|
|
|
||||||
31
src/textures/windy.rs
Normal file
31
src/textures/windy.rs
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use shared::{textures::WindyTexture, utils::Transform};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
core::texture::{FloatTexture, FloatTextureTrait},
|
||||||
|
utils::{FileLoc, TextureParameterDictionary},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait CreateWindyTexture {
|
||||||
|
fn create(
|
||||||
|
render_from_texture: Transform,
|
||||||
|
parameters: TextureParameterDictionary,
|
||||||
|
loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreateWindyTexture for WindyTexture {
|
||||||
|
fn create(
|
||||||
|
_render_from_texture: Transform,
|
||||||
|
_parameters: TextureParameterDictionary,
|
||||||
|
_loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FloatTextureTrait for WindyTexture {
|
||||||
|
fn evaluate(&self, _ctx: &shared::core::texture::TextureEvalContext) -> shared::Float {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/textures/wrinkled.rs
Normal file
31
src/textures/wrinkled.rs
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use shared::{textures::WrinkledTexture, utils::Transform};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
core::texture::{FloatTexture, FloatTextureTrait},
|
||||||
|
utils::{FileLoc, TextureParameterDictionary},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait CreateWrinkledTexture {
|
||||||
|
fn create(
|
||||||
|
render_from_texture: Transform,
|
||||||
|
parameters: TextureParameterDictionary,
|
||||||
|
loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreateWrinkledTexture for WrinkledTexture {
|
||||||
|
fn create(
|
||||||
|
_render_from_texture: Transform,
|
||||||
|
_parameters: TextureParameterDictionary,
|
||||||
|
_loc: FileLoc,
|
||||||
|
) -> Result<FloatTexture> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FloatTextureTrait for WrinkledTexture {
|
||||||
|
fn evaluate(&self, _ctx: &shared::core::texture::TextureEvalContext) -> shared::Float {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,18 +1,21 @@
|
||||||
use crate::core::image::Image;
|
use crate::core::image::Image;
|
||||||
use crate::core::texture::{FloatTexture, SpectrumTexture};
|
use crate::core::texture::{FloatTexture, SpectrumTexture};
|
||||||
use crate::shapes::{BilinearPatchMesh, TriangleMesh};
|
use crate::shapes::{BilinearPatchMesh, TriangleMesh};
|
||||||
|
use crate::spectra::DenselySampledSpectrumBuffer;
|
||||||
use crate::utils::mipmap::MIPMap;
|
use crate::utils::mipmap::MIPMap;
|
||||||
use crate::utils::sampling::PiecewiseConstant2D;
|
use crate::utils::sampling::{PiecewiseConstant2D, WindowedPiecewiseConstant2D};
|
||||||
use shared::core::color::RGBToSpectrumTable;
|
use shared::core::color::RGBToSpectrumTable;
|
||||||
use shared::core::image::DeviceImage;
|
use shared::core::image::DeviceImage;
|
||||||
use shared::core::shape::Shape;
|
use shared::core::shape::Shape;
|
||||||
use shared::core::spectrum::Spectrum;
|
use shared::core::spectrum::Spectrum;
|
||||||
use shared::core::texture::{GPUFloatTexture, GPUSpectrumTexture};
|
use shared::core::texture::{GPUFloatTexture, GPUSpectrumTexture};
|
||||||
use shared::spectra::{DeviceStandardColorSpaces, RGBColorSpace};
|
use shared::spectra::{DenselySampledSpectrum, DeviceStandardColorSpaces, RGBColorSpace};
|
||||||
use shared::textures::*;
|
use shared::textures::*;
|
||||||
use shared::utils::Ptr;
|
use shared::utils::Ptr;
|
||||||
use shared::utils::mesh::{DeviceBilinearPatchMesh, DeviceTriangleMesh};
|
use shared::utils::mesh::{DeviceBilinearPatchMesh, DeviceTriangleMesh};
|
||||||
use shared::utils::sampling::{DevicePiecewiseConstant1D, DevicePiecewiseConstant2D};
|
use shared::utils::sampling::{
|
||||||
|
DevicePiecewiseConstant1D, DevicePiecewiseConstant2D, DeviceWindowedPiecewiseConstant2D,
|
||||||
|
};
|
||||||
use std::alloc::Layout;
|
use std::alloc::Layout;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::slice::from_raw_parts;
|
use std::slice::from_raw_parts;
|
||||||
|
|
@ -166,6 +169,13 @@ impl Upload for Spectrum {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Upload for DenselySampledSpectrumBuffer {
|
||||||
|
type Target = DenselySampledSpectrum;
|
||||||
|
fn upload(&self, arena: &mut Arena) -> Ptr<Self::Target> {
|
||||||
|
arena.alloc(self.device)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Upload for SpectrumTexture {
|
impl Upload for SpectrumTexture {
|
||||||
type Target = GPUSpectrumTexture;
|
type Target = GPUSpectrumTexture;
|
||||||
fn upload(&self, arena: &mut Arena) -> Ptr<Self::Target> {
|
fn upload(&self, arena: &mut Arena) -> Ptr<Self::Target> {
|
||||||
|
|
@ -291,10 +301,6 @@ impl Upload for FloatTexture {
|
||||||
GPUFloatTexture::Image(gpu_image_tex)
|
GPUFloatTexture::Image(gpu_image_tex)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FloatTexture::Ptex(tex) => {
|
|
||||||
// todo!("Implement Ptex buffer upload")
|
|
||||||
// }
|
|
||||||
|
|
||||||
FloatTexture::Bilerp(tex) => GPUFloatTexture::Bilerp(tex.clone()),
|
FloatTexture::Bilerp(tex) => GPUFloatTexture::Bilerp(tex.clone()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -387,6 +393,17 @@ impl Upload for PiecewiseConstant2D {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Upload for WindowedPiecewiseConstant2D {
|
||||||
|
type Target = DeviceWindowedPiecewiseConstant2D;
|
||||||
|
fn upload(&self, arena: &mut Arena) -> Ptr<Self::Target> {
|
||||||
|
let specific = DeviceWindowedPiecewiseConstant2D {
|
||||||
|
sat: self.sat,
|
||||||
|
func: self.func,
|
||||||
|
};
|
||||||
|
arena.alloc(specific)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Upload for TriangleMesh {
|
impl Upload for TriangleMesh {
|
||||||
type Target = DeviceTriangleMesh;
|
type Target = DeviceTriangleMesh;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,35 +35,36 @@ where
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Array2D<T> {
|
pub struct Array2D<T> {
|
||||||
pub view: DeviceArray2D<T>,
|
pub device: DeviceArray2D<T>,
|
||||||
_storage: Vec<T>,
|
values: Vec<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Deref for Array2D<T> {
|
impl<T> Deref for Array2D<T> {
|
||||||
type Target = DeviceArray2D<T>;
|
type Target = DeviceArray2D<T>;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.view
|
&self.device
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> DerefMut for Array2D<T> {
|
impl<T> DerefMut for Array2D<T> {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
&mut self.view
|
&mut self.device
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Array2D<T> {
|
impl<T> Array2D<T> {
|
||||||
fn from_vec(extent: Bounds2i, mut storage: Vec<T>) -> Self {
|
pub fn as_slice(&self) -> &[T] {
|
||||||
|
&self.values
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_vec(extent: Bounds2i, mut values: Vec<T>) -> Self {
|
||||||
let width = extent.p_max.x() - extent.p_min.x();
|
let width = extent.p_max.x() - extent.p_min.x();
|
||||||
let view = DeviceArray2D {
|
let device = DeviceArray2D {
|
||||||
extent,
|
extent,
|
||||||
values: storage.as_mut_ptr(),
|
values: storage.as_mut_ptr(),
|
||||||
stride: width,
|
stride: width,
|
||||||
};
|
};
|
||||||
Self {
|
Self { device, values }
|
||||||
view,
|
|
||||||
_storage: storage,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::core::spectrum::SPECTRUM_CACHE;
|
use crate::core::spectrum::{SPECTRUM_CACHE, get_spectrum_cache};
|
||||||
use crate::core::texture::{FloatTexture, SpectrumTexture};
|
use crate::core::texture::{FloatTexture, SpectrumTexture};
|
||||||
use crate::spectra::data::get_named_spectrum;
|
use crate::spectra::data::get_named_spectrum;
|
||||||
use crate::spectra::piecewise::PiecewiseLinearSpectrumBuffer;
|
use crate::spectra::piecewise::PiecewiseLinearSpectrumBuffer;
|
||||||
|
|
@ -683,7 +683,7 @@ impl ParameterDictionary {
|
||||||
fn read_spectrum_from_file(filename: &str) -> Result<Spectrum, String> {
|
fn read_spectrum_from_file(filename: &str) -> Result<Spectrum, String> {
|
||||||
let fn_key = filename.to_string();
|
let fn_key = filename.to_string();
|
||||||
{
|
{
|
||||||
let cache = SPECTRUM_CACHE.lock();
|
let cache = SPECTRUM_FILE_CACHE.lock();
|
||||||
if let Some(s) = cache.get(&fn_key) {
|
if let Some(s) = cache.get(&fn_key) {
|
||||||
return Ok(s.clone());
|
return Ok(s.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -695,7 +695,7 @@ fn read_spectrum_from_file(filename: &str) -> Result<Spectrum, String> {
|
||||||
let spectrum = Spectrum::Piecewise(*pls);
|
let spectrum = Spectrum::Piecewise(*pls);
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut cache = SPECTRUM_CACHE.lock();
|
let mut cache = SPECTRUM_FILE_CACHE.lock();
|
||||||
cache.insert(fn_key, spectrum.clone());
|
cache.insert(fn_key, spectrum.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue