106 lines
3 KiB
Rust
106 lines
3 KiB
Rust
use crate::Float;
|
|
use crate::core::texture::{
|
|
GPUFloatTexture, GPUSpectrumTexture, TextureEvalContext, TextureMapping2D, TextureMapping3D,
|
|
TextureMapping3DTrait,
|
|
};
|
|
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 {
|
|
let d = |x: Float| -> Float {
|
|
let y = x / 2. - (x / 2.).floor() - 0.5;
|
|
return x / 2. + y * (1. - 2. * y.abs());
|
|
};
|
|
|
|
let bf = |x: Float, r: Float| -> Float {
|
|
if (x.floor() - r) == (x + r).floor() {
|
|
return 1. - 2. * (x.floor() as i32 & 1) as Float;
|
|
}
|
|
(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)
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, Copy, Clone)]
|
|
pub struct FloatCheckerboardTexture {
|
|
pub map2d: Ptr<TextureMapping2D>,
|
|
pub map3d: Ptr<TextureMapping3D>,
|
|
pub tex: [Ptr<GPUFloatTexture>; 2],
|
|
}
|
|
|
|
impl FloatCheckerboardTexture {
|
|
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
|
|
let w = checkerboard(&ctx, self.map2d, self.map3d);
|
|
|
|
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 != 0.0 {
|
|
if let Some(tex) = self.tex[1].get() {
|
|
t1 = tex.evaluate(ctx);
|
|
}
|
|
}
|
|
|
|
(1.0 - w) * t0 + w * t1
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct SpectrumCheckerboardTexture {
|
|
pub map2d: Ptr<TextureMapping2D>,
|
|
pub map3d: Ptr<TextureMapping3D>,
|
|
pub tex: [Ptr<GPUSpectrumTexture>; 2],
|
|
}
|
|
|
|
impl SpectrumCheckerboardTexture {
|
|
pub fn evaluate(
|
|
&self,
|
|
ctx: &TextureEvalContext,
|
|
lambda: &SampledWavelengths,
|
|
) -> SampledSpectrum {
|
|
let w = checkerboard(ctx, self.map2d, self.map3d);
|
|
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 != 0.0 {
|
|
if let Some(tex) = self.tex[1].get() {
|
|
t1 = tex.evaluate(ctx, lambda);
|
|
}
|
|
}
|
|
|
|
t0 * (1.0 - w) + t1 * w
|
|
}
|
|
}
|