Continuing the slog

This commit is contained in:
Wito Wiala 2026-09-01 22:25:52 +01:00
parent 2e9526ce18
commit 7c35f9b180
8 changed files with 201 additions and 98 deletions

View file

@ -96,13 +96,13 @@ impl MaterialTrait for ThinDielectricMaterial {
ctx: &MaterialEvalContext,
lambda: &mut SampledWavelengths,
) -> BSDF {
let sampled_eta = self.eta.evaluate(lambda[0]);
let mut sampled_eta = self.eta.evaluate(lambda[0]);
if !self.eta.is_constant() {
lambda.terminate_secondary_inplace();
}
if sampled_eta == 0. {
sampled_eta == 1.;
sampled_eta = 1.;
}
let bxdf = BxDF::ThinDielectric(ThinDielectricBxDF::new(sampled_eta));

View file

@ -7,14 +7,17 @@ use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::{Ptr, math::square};
use num_traits::Float as NumFloat;
fn checkerboard(
ctx: &TextureEvalContext,
map2d: Ptr<TextureMapping2D>,
map3d: Ptr<TextureMapping3D>,
) -> Float {
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub enum CheckerMap {
D2(TextureMapping2D),
D3(TextureMapping3D),
}
fn checkerboard(ctx: &TextureEvalContext, checker_map: CheckerMap) -> Float {
let d = |x: Float| -> Float {
let y = x / 2. - (x / 2.).floor() - 0.5;
return x / 2. + y * (1. - 2. * y.abs());
x / 2. + y * (1. - 2. * y.abs())
};
let bf = |x: Float, r: Float| -> Float {
@ -24,48 +27,52 @@ fn checkerboard(
(d(x + r) - 2. * d(x) + d(x - r)) / square(r)
};
if !map2d.is_null() {
assert!(map3d.is_null());
let c = map2d.map(&ctx);
let ds = 1.5 * c.dsdx.abs().max(c.dsdy.abs());
let dt = 1.5 * c.dtdx.abs().max(c.dtdy.abs());
// Integrate product of 2D checkerboard function and triangle filter
0.5 - bf(c.st[0], ds) * bf(c.st[1], dt) / 2.
} else {
assert!(!map3d.is_null());
let c = map3d.map(&ctx);
let dx = 1.5 * c.dpdx.x().abs().max(c.dpdy.x().abs());
let dy = 1.5 * c.dpdx.y().abs().max(c.dpdy.y().abs());
let dz = 1.5 * c.dpdx.z().abs().max(c.dpdy.z().abs());
0.5 - bf(c.p.x(), dx) * bf(c.p.y(), dy) * bf(c.p.z(), dz)
match checker_map {
CheckerMap::D2(map) => {
let c = map.map(ctx);
let ds = 1.5 * c.dsdx.abs().max(c.dsdy.abs());
let dt = 1.5 * c.dtdx.abs().max(c.dtdy.abs());
// Integrate product of 2D checkerboard function and triangle filter
0.5 - bf(c.st[0], ds) * bf(c.st[1], dt) / 2.
}
CheckerMap::D3(map) => {
let c = map.map(ctx);
let dx = 1.5 * c.dpdx.x().abs().max(c.dpdy.x().abs());
let dy = 1.5 * c.dpdx.y().abs().max(c.dpdy.y().abs());
let dz = 1.5 * c.dpdx.z().abs().max(c.dpdy.z().abs());
0.5 - bf(c.p.x(), dx) * bf(c.p.y(), dy) * bf(c.p.z(), dz)
}
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct FloatCheckerboardTexture {
pub map2d: Ptr<TextureMapping2D>,
pub map3d: Ptr<TextureMapping3D>,
pub map: CheckerMap,
pub tex: [Ptr<FloatTexture>; 2],
}
impl FloatCheckerboardTexture {
pub fn new(map: CheckerMap, tex: [Ptr<FloatTexture>; 2]) -> Self {
Self { map, tex }
}
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
let w = checkerboard(&ctx, self.map2d, self.map3d);
let w = checkerboard(ctx, self.map);
let mut t0 = 0.0;
let mut t1 = 0.0;
if w != 1.0 {
if let Some(tex) = self.tex[0].get() {
t0 = tex.evaluate(ctx);
}
if w != 1.0
&& let Some(tex) = self.tex[0].get()
{
t0 = tex.evaluate(ctx);
}
if w != 0.0 {
if let Some(tex) = self.tex[1].get() {
t1 = tex.evaluate(ctx);
}
if w != 0.0
&& let Some(tex) = self.tex[1].get()
{
t1 = tex.evaluate(ctx);
}
(1.0 - w) * t0 + w * t1
@ -75,30 +82,33 @@ impl FloatCheckerboardTexture {
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct SpectrumCheckerboardTexture {
pub map2d: Ptr<TextureMapping2D>,
pub map3d: Ptr<TextureMapping3D>,
pub map: CheckerMap,
pub tex: [Ptr<SpectrumTexture>; 2],
}
impl SpectrumCheckerboardTexture {
pub fn new(map: CheckerMap, tex: [Ptr<SpectrumTexture>; 2]) -> Self {
Self { map, tex }
}
pub fn evaluate(
&self,
ctx: &TextureEvalContext,
lambda: &SampledWavelengths,
) -> SampledSpectrum {
let w = checkerboard(ctx, self.map2d, self.map3d);
let w = checkerboard(ctx, self.map);
let mut t0 = SampledSpectrum::new(0.);
let mut t1 = SampledSpectrum::new(0.);
if w != 1.0 {
if let Some(tex) = self.tex[0].get() {
t0 = tex.evaluate(ctx, lambda);
}
if w != 1.0
&& let Some(tex) = self.tex[0].get()
{
t0 = tex.evaluate(ctx, lambda);
}
if w != 0.0 {
if let Some(tex) = self.tex[1].get() {
t1 = tex.evaluate(ctx, lambda);
}
if w != 0.0
&& let Some(tex) = self.tex[1].get()
{
t1 = tex.evaluate(ctx, lambda);
}
t0 * (1.0 - w) + t1 * w

View file

@ -1,8 +1,6 @@
use crate::Float;
use crate::core::geometry::{Point2f, VectorLike};
use crate::core::texture::{
FloatTexture, SpectrumTexture, TextureEvalContext, TextureMapping2D,
};
use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvalContext, TextureMapping2D};
use crate::spectra::sampled::{SampledSpectrum, SampledWavelengths};
use crate::utils::Ptr;
use crate::utils::math::square;
@ -22,18 +20,30 @@ fn inside_polka_dot(st: Point2f) -> bool {
return true;
}
}
return false;
false
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct FloatDotsTexture {
pub mapping: TextureMapping2D,
pub outside_dot: Ptr<FloatTexture>,
pub inside_dot: Ptr<FloatTexture>,
pub outside_dot: Ptr<FloatTexture>,
}
impl FloatDotsTexture {
pub fn new(
mapping: TextureMapping2D,
inside_dot: Ptr<FloatTexture>,
outside_dot: Ptr<FloatTexture>,
) -> Self {
Self {
mapping,
inside_dot,
outside_dot,
}
}
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
let c = self.mapping.map(ctx);
let target_texture = if inside_polka_dot(c.st) {
@ -54,11 +64,22 @@ impl FloatDotsTexture {
#[derive(Clone, Copy, Debug)]
pub struct SpectrumDotsTexture {
pub mapping: TextureMapping2D,
pub outside_dot: Ptr<SpectrumTexture>,
pub inside_dot: Ptr<SpectrumTexture>,
pub outside_dot: Ptr<SpectrumTexture>,
}
impl SpectrumDotsTexture {
pub fn new(
mapping: TextureMapping2D,
inside_dot: Ptr<SpectrumTexture>,
outside_dot: Ptr<SpectrumTexture>,
) -> Self {
Self {
mapping,
inside_dot,
outside_dot,
}
}
pub fn evaluate(
&self,
ctx: &TextureEvalContext,

View file

@ -5,11 +5,18 @@ use crate::utils::noise::fbm;
#[derive(Debug, Clone, Copy)]
pub struct FBmTexture {
pub mapping: TextureMapping3D,
pub omega: Float,
pub octaves: u32,
pub omega: Float,
}
impl FBmTexture {
pub fn new(mapping: TextureMapping3D, octaves: u32, omega: Float) -> Self {
Self {
mapping,
omega,
octaves,
}
}
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
let c = self.mapping.map(ctx);
fbm(c.p, c.dpdx, c.dpdy, self.omega, self.octaves)

View file

@ -30,7 +30,6 @@ impl CreateFloatTexture for FloatBilerpTexture {
}
}
impl CreateSpectrumTexture for SpectrumBilerpTexture {
fn create(
render_from_texture: Transform,
@ -43,9 +42,7 @@ impl CreateSpectrumTexture for SpectrumBilerpTexture {
let zero = Spectrum::Constant(ConstantSpectrum::new(0.));
let one = Spectrum::Constant(ConstantSpectrum::new(1.));
// `Spectrum` is already a device type, so it is allocated into the arena
// rather than uploaded -- upload is for host trees (Arc) -> device (Ptr).
let mut get = |name: &str, def: Spectrum| {
let get = |name: &str, def: Spectrum| {
let s = parameters
.get_one_spectrum(name, Some(def), spectrum_type)
.unwrap_or(def);

View file

@ -1,37 +1,79 @@
use crate::Arena;
use anyhow::Result;
use anyhow::{Result, bail};
use shared::{
core::texture::SpectrumType,
textures::{FloatCheckerboardTexture, SpectrumCheckerboardTexture},
utils::Transform
core::spectrum::Spectrum,
core::texture::{SpectrumType, TextureMapping2D, TextureMapping3D},
spectra::ConstantSpectrum,
textures::{CheckerMap, FloatCheckerboardTexture, SpectrumCheckerboardTexture},
utils::Transform,
};
use crate::{
core::texture::{
CreateFloatTexture, CreateSpectrumTexture, FloatTexture, SpectrumTexture },
utils::{FileLoc, TextureParameterDictionary}
CreateFloatTexture, CreateSpectrumTexture, CreateTextureMapping, FloatTexture,
SpectrumTexture,
},
utils::{ArenaUpload, FileLoc, TextureParameterDictionary},
};
fn checker_map(
render_from_texture: Transform,
parameters: TextureParameterDictionary,
loc: FileLoc,
) -> Result<CheckerMap> {
match parameters.get_one_int("dimension", 2)? {
2 => Ok(CheckerMap::D2(TextureMapping2D::create(
&parameters,
&render_from_texture,
&loc,
)?)),
3 => Ok(CheckerMap::D3(TextureMapping3D::create(
&parameters,
&render_from_texture,
&loc,
)?)),
dim => bail!("{loc}: {dim} dimensional checkerboard texture not supported"),
}
}
impl CreateFloatTexture for FloatCheckerboardTexture {
fn create(
_render_from_texture: Transform,
_parameters: TextureParameterDictionary,
_loc: FileLoc,
_arena: &Arena,
render_from_texture: Transform,
parameters: TextureParameterDictionary,
loc: FileLoc,
arena: &Arena,
) -> Result<FloatTexture> {
todo!()
let tex1 = arena.upload(parameters.get_float_texture("tex1", 1.)?);
let tex2 = arena.upload(parameters.get_float_texture("tex2", 0.)?);
let map = checker_map(render_from_texture, parameters, loc)?;
let tex = FloatCheckerboardTexture::new(map, [tex1, tex2]);
Ok(FloatTexture::Checkerboard(tex))
}
}
impl CreateSpectrumTexture for SpectrumCheckerboardTexture {
fn create(
_render_from_texture: Transform,
_parameters: TextureParameterDictionary,
_spectrum_type: SpectrumType,
_loc: FileLoc,
_arena: &Arena,
render_from_texture: Transform,
parameters: TextureParameterDictionary,
spectrum_type: SpectrumType,
loc: FileLoc,
arena: &Arena,
) -> Result<SpectrumTexture> {
todo!()
let zero = Spectrum::Constant(ConstantSpectrum::new(0.));
let one = Spectrum::Constant(ConstantSpectrum::new(1.));
let tex = |name: &str, def: Spectrum| {
arena.upload(
parameters
.get_spectrum_texture(name, Some(def), spectrum_type)
.expect("default supplied"),
)
};
let tex1 = tex("tex1", one);
let tex2 = tex("tex2", zero);
let map = checker_map(render_from_texture, parameters, loc)?;
let tex = SpectrumCheckerboardTexture::new(map, [tex1, tex2]);
Ok(SpectrumTexture::Checkerboard(tex))
}
}

View file

@ -1,36 +1,57 @@
use crate::Arena;
use crate::{Arena, ArenaUpload};
use anyhow::Result;
use shared::{
core::texture::SpectrumType,
core::spectrum::Spectrum,
core::texture::{SpectrumType, TextureMapping2D},
spectra::ConstantSpectrum,
textures::{FloatDotsTexture, SpectrumDotsTexture},
utils::Transform
utils::Transform,
};
use crate::{
core::texture::{
CreateFloatTexture, CreateSpectrumTexture, FloatTexture, SpectrumTexture },
utils::{FileLoc, TextureParameterDictionary}
CreateFloatTexture, CreateSpectrumTexture, CreateTextureMapping, FloatTexture,
SpectrumTexture,
},
utils::{FileLoc, TextureParameterDictionary},
};
impl CreateFloatTexture for FloatDotsTexture {
fn create(
_render_from_texture: Transform,
_parameters: TextureParameterDictionary,
_loc: FileLoc,
_arena: &Arena,
render_from_texture: Transform,
parameters: TextureParameterDictionary,
loc: FileLoc,
arena: &Arena,
) -> Result<FloatTexture> {
todo!()
let map = TextureMapping2D::create(&parameters, &render_from_texture, &loc)?;
let inside = parameters.get_float_texture("inside", 1.)?;
let outside = parameters.get_float_texture("outside", 1.)?;
let tex = FloatDotsTexture::new(map, arena.upload(inside), arena.upload(outside));
Ok(FloatTexture::Dots(tex))
}
}
impl CreateSpectrumTexture for SpectrumDotsTexture {
fn create(
_render_from_texture: Transform,
_parameters: TextureParameterDictionary,
_spectrum_type: SpectrumType,
_loc: FileLoc,
_arena: &Arena,
render_from_texture: Transform,
parameters: TextureParameterDictionary,
spectrum_type: SpectrumType,
loc: FileLoc,
arena: &Arena,
) -> Result<SpectrumTexture> {
todo!()
let map = TextureMapping2D::create(&parameters, &render_from_texture, &loc)?;
let zero = Spectrum::Constant(ConstantSpectrum::new(0.));
let one = Spectrum::Constant(ConstantSpectrum::new(1.));
let get = |name: &str, def: Spectrum| {
let t = parameters
.get_spectrum_texture(name, Some(def), spectrum_type)
.expect("default supplied");
arena.upload(t)
};
let tex = SpectrumDotsTexture::new(map, get("inside", one), get("outside", zero));
Ok(SpectrumTexture::Dots(tex))
}
}

View file

@ -1,21 +1,26 @@
use crate::Arena;
use anyhow::Result;
use shared::core::texture::TextureEvalContext;
use shared::core::texture::{TextureEvalContext, TextureMapping3D};
use shared::{textures::FBmTexture, utils::Transform};
use crate::{
core::texture::{CreateFloatTexture, FloatTexture },
utils::{FileLoc, TextureParameterDictionary}
core::texture::{CreateFloatTexture, CreateTextureMapping, FloatTexture},
utils::{FileLoc, TextureParameterDictionary},
};
impl CreateFloatTexture for FBmTexture {
fn create(
_render_from_texture: Transform,
_parameters: TextureParameterDictionary,
_loc: FileLoc,
_arena: &Arena,
render_from_texture: Transform,
parameters: TextureParameterDictionary,
loc: FileLoc,
arena: &Arena,
) -> Result<FloatTexture> {
todo!()
let map = TextureMapping3D::create(&parameters, &render_from_texture, &loc)?;
let tex = FBmTexture::new(
map,
parameters.get_one_int("octaves", 5)?.try_into().unwrap(),
parameters.get_one_float("roughness", 0.5)?,
);
Ok(FloatTexture::FBm(tex))
}
}