131 lines
4.6 KiB
Rust
131 lines
4.6 KiB
Rust
use crate::core::color::{RGB, XYZ};
|
|
use crate::core::image::{Image, WrapMode, WrapMode2D};
|
|
use crate::core::spectrum::SpectrumTrait;
|
|
use crate::core::texture::{SpectrumType, TextureEvalContext, TextureMapping2D};
|
|
use crate::spectra::{
|
|
RGBAlbedoSpectrum, RGBColorSpace, RGBIlluminantSpectrum, RGBUnboundedSpectrum, SampledSpectrum,
|
|
SampledWavelengths,
|
|
};
|
|
use crate::utils::Ptr;
|
|
use crate::Float;
|
|
|
|
/* GPU heavy code, dont know if this will ever work the way Im doing things.
|
|
* Leaving it here isolated, for careful handling */
|
|
#[repr(C)]
|
|
#[derive(Clone, Debug, Copy)]
|
|
pub struct SpectrumImageTexture {
|
|
pub wrap_mode: WrapMode,
|
|
pub tex_obj: u64,
|
|
pub scale: Float,
|
|
pub spectrum_type: SpectrumType,
|
|
pub image: Ptr<Image>,
|
|
pub color_space: Ptr<RGBColorSpace>,
|
|
pub mapping: TextureMapping2D,
|
|
pub is_single_channel: bool,
|
|
pub invert: bool,
|
|
}
|
|
|
|
impl SpectrumImageTexture {
|
|
pub fn evaluate(
|
|
&self,
|
|
ctx: &TextureEvalContext,
|
|
lambda: &SampledWavelengths,
|
|
) -> SampledSpectrum {
|
|
#[cfg(feature = "cuda")]
|
|
if self.tex_obj != 0 {
|
|
// FUTURE: hardware sampling path.
|
|
// let c = self.mapping.map(ctx);
|
|
// let rgb = tex2d_grad(self.tex_obj, c.st, [c.dsdx,c.dtdx], [c.dsdy,c.dtdy]);
|
|
// return spectrum_from_rgb(rgb * self.scale, self.invert, self.spectrum_type, ...);
|
|
// Until then, fall through to software path below.
|
|
}
|
|
|
|
let Some(image) = self.image.get() else {
|
|
return SampledSpectrum::zero();
|
|
};
|
|
let mut c = self.mapping.map(ctx);
|
|
c.st[1] = 1.0 - c.st[1]; // flip V to match pbrt convention
|
|
|
|
let wrap = WrapMode2D {
|
|
uv: [self.wrap_mode; 2],
|
|
};
|
|
let rgb = if image.n_channels == 1 {
|
|
let v = image.bilerp_channel_with_wrap(c.st, 0, wrap);
|
|
RGB::new(v, v, v)
|
|
} else {
|
|
RGB::new(
|
|
image.bilerp_channel_with_wrap(c.st, 0, wrap),
|
|
image.bilerp_channel_with_wrap(c.st, 1, wrap),
|
|
image.bilerp_channel_with_wrap(c.st, 2, wrap),
|
|
)
|
|
};
|
|
let mut rgb = rgb * self.scale;
|
|
if self.invert {
|
|
rgb = (RGB::new(1.0, 1.0, 1.0) - rgb);
|
|
}
|
|
rgb = rgb.clamp_zero();
|
|
let cs = self
|
|
.color_space
|
|
.get()
|
|
.expect("color_space must not be null");
|
|
match self.spectrum_type {
|
|
SpectrumType::Unbounded => RGBUnboundedSpectrum::new(cs, rgb).sample(lambda),
|
|
SpectrumType::Albedo => RGBAlbedoSpectrum::new(cs, rgb.clamp(0.0, 1.0)).sample(lambda),
|
|
_ => RGBIlluminantSpectrum::new(cs, rgb).sample(lambda),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, Copy, Clone)]
|
|
pub struct FloatImageTexture {
|
|
pub image: Ptr<Image>,
|
|
pub mapping: TextureMapping2D,
|
|
pub wrap_mode: WrapMode,
|
|
pub tex_obj: u64,
|
|
pub scale: Float,
|
|
pub invert: bool,
|
|
}
|
|
|
|
impl FloatImageTexture {
|
|
#[allow(unused_variables)]
|
|
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
|
|
#[cfg(not(feature = "cuda"))]
|
|
{
|
|
let wrap = WrapMode2D {
|
|
uv: [self.wrap_mode; 2],
|
|
};
|
|
let mut c = self.mapping.map(ctx);
|
|
c.st[1] = 1.0 - c.st[1];
|
|
let Some(image) = self.image.get() else { return 0. };
|
|
|
|
let v = image.bilerp_channel_with_wrap(c.st, 0, wrap);
|
|
let v = if self.invert { (1.0 - v).max(0.0) } else { v };
|
|
return v * self.scale;
|
|
}
|
|
#[cfg(feature = "cuda")]
|
|
{
|
|
if self.tex_obj != 0 {
|
|
use cuda_std::intrinsics;
|
|
let c = self.mapping.map(ctx);
|
|
let u = c.st.x();
|
|
let v = 1.0 - c.st.y();
|
|
let d_p_dx = [c.dsdx, c.dtdx];
|
|
let d_p_dy = [c.dsdy, c.dtdy];
|
|
// let val: Float = unsafe { intrinsics::tex2d_grad(self.tex_obj, u, v, d_p_dx, d_p_dy) };
|
|
let _ = (u, v, d_p_dx, d_p_dy);
|
|
let val: Float = 0.;
|
|
let result = if self.invert { (1.0 - val).max(0.0) } else { val };
|
|
return result * self.scale;
|
|
}
|
|
// software path (no hardware texture object)
|
|
let wrap = WrapMode2D { uv: [self.wrap_mode; 2] };
|
|
let mut c = self.mapping.map(ctx);
|
|
c.st[1] = 1.0 - c.st[1];
|
|
let Some(image) = self.image.get() else { return 0. };
|
|
let v = image.bilerp_channel_with_wrap(c.st, 0, wrap);
|
|
let v = if self.invert { (1.0 - v).max(0.0) } else { v };
|
|
return v * self.scale;
|
|
}
|
|
}
|
|
}
|