Continuing cleanup. Added constructors for FloatImageTexture

This commit is contained in:
Wito Wiala 2026-06-05 17:39:22 +01:00
parent aefd204577
commit 79c87a6c15
7 changed files with 96 additions and 66 deletions

View file

@ -8,6 +8,7 @@ use core::fmt;
use core::ops::{
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
};
use anyhow::{Result, bail};
use enum_dispatch::enum_dispatch;
use num_traits::Float as NumFloat;
@ -680,6 +681,16 @@ pub enum ColorEncoding {
SRGB(SRGBEncoding),
}
impl ColorEncoding {
pub fn from_name(name: &str) -> Result<Self> {
match name {
"sRGB" | "srgb" => Ok(ColorEncoding::SRGB(SRGBEncoding)),
"linear" => Ok(ColorEncoding::Linear(LinearEncoding)),
_ => bail!("Unknown color encoding: {}", name),
}
}
}
impl fmt::Display for ColorEncoding {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Encoding")

View file

@ -2,6 +2,7 @@ use crate::core::color::{ColorEncoding, ColorEncodingTrait, LINEAR};
use crate::core::geometry::{Bounds2f, Point2f, Point2fi, Point2i};
use crate::utils::math::{f16_to_f32_software, lerp, square};
use crate::{gvec_with_capacity, Float, GVec};
use anyhow::{Result, bail};
use core::hash;
use core::ops::{Deref, DerefMut};
use num_traits::Float as NumFloat;
@ -14,6 +15,18 @@ pub enum WrapMode {
OctahedralSphere,
}
impl WrapMode {
pub fn parse(name: &str) -> Result<WrapMode> {
match name {
"clamp" => Ok(WrapMode::Clamp),
"black" => Ok(WrapMode::Black),
"repeat" => Ok(WrapMode::Repeat),
"octahedralsphere" => Ok(WrapMode::OctahedralSphere),
_ => bail!("{:?}: wrap mode unknown", name)
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct WrapMode2D {
pub uv: [WrapMode; 2],

View file

@ -6,7 +6,6 @@ pub mod fbm;
pub mod image;
pub mod marble;
pub mod mix;
pub mod ptex;
pub mod scaled;
pub mod windy;
pub mod wrinkled;
@ -19,7 +18,6 @@ pub use fbm::*;
pub use image::*;
pub use marble::*;
pub use mix::*;
pub use ptex::*;
pub use scaled::*;
pub use windy::*;
pub use wrinkled::*;

View file

@ -1,51 +0,0 @@
use crate::Float;
use crate::core::color::{ColorEncoding, RGB};
use crate::core::spectrum::{SpectrumTrait, StandardSpectra};
use crate::core::texture::{SpectrumType, TextureEvalContext};
use crate::spectra::{
DeviceStandardColorSpaces, RGBAlbedoSpectrum, RGBColorSpace, RGBIlluminantSpectrum,
RGBUnboundedSpectrum, SampledSpectrum, SampledWavelengths,
};
use crate::utils::Ptr;
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct GPUFloatPtexTexture {
pub face_values: *const Float,
}
impl GPUFloatPtexTexture {
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
unsafe { *self.face_values.add(ctx.face_index as usize) }
}
}
#[repr(C)]
#[derive(Clone, Debug, Copy)]
pub struct GPUSpectrumPtexTexture {
pub face_values: Ptr<RGB>,
pub n_faces: u32,
pub spectrum_type: SpectrumType,
pub colorspaces: DeviceStandardColorSpaces,
}
impl GPUSpectrumPtexTexture {
pub fn evaluate(
&self,
ctx: &TextureEvalContext,
lambda: &SampledWavelengths,
) -> SampledSpectrum {
let index = (ctx.face_index as u32).clamp(0, self.n_faces.saturating_sub(1));
let rgb = unsafe { &*self.face_values.add(index as usize) };
let s_rgb = self.colorspaces.srgb;
match self.spectrum_type {
SpectrumType::Unbounded => RGBUnboundedSpectrum::new(&s_rgb, *rgb).sample(lambda),
SpectrumType::Albedo => {
let clamped_rgb = rgb.clamp(0.0, 1.0);
RGBAlbedoSpectrum::new(&s_rgb, clamped_rgb).sample(lambda)
}
SpectrumType::Illuminant => RGBIlluminantSpectrum::new(&s_rgb, *rgb).sample(lambda),
}
}
}

View file

@ -335,9 +335,6 @@ pub trait FilmTrait: Sync {
for x in pixel_bounds.p_min.x()..pixel_bounds.p_max.x() {
let p = Point2i::new(x, y);
let mut rgb = self.get_pixel_rgb(p, Some(splat_scale));
if rgb.r > 1.0 || rgb.g > 1.0 || rgb.b > 1.0 {
eprintln!("p={:?} get_pixel_rgb=({}, {}, {})", p, rgb.r, rgb.g, rgb.b);
}
let mut was_clamped = false;
if write_fp16 {
if rgb.r > 65504.0 {

View file

@ -3,16 +3,16 @@ use crate::core::texture::{
CreateFloatTexture, CreateSpectrumTexture, FloatTexture, FloatTextureTrait, SpectrumTexture,
SpectrumTextureTrait,
};
use crate::utils::mipmap::{MIPMap, MIPMapFilterOptions};
use crate::utils::{FileLoc, TextureParameterDictionary};
use crate::Arena;
use crate::utils::mipmap::{FilterFunction, MIPMap, MIPMapFilterOptions};
use crate::utils::{FileLoc, TextureParameterDictionary, resolve_filename};
use crate::{Arena};
use anyhow::Result;
use shared::core::color::RGB;
use shared::core::color::{ColorEncoding, SRGBEncoding};
use shared::core::geometry::Vector2f;
use shared::core::image::WrapMode;
use shared::core::spectrum::SpectrumTrait;
use shared::core::texture::{SpectrumType, TextureEvalContext, TextureMapping2D};
use shared::core::texture::{SpectrumType, TexCoord2D, TextureEvalContext, TextureMapping2D};
use shared::spectra::{
RGBAlbedoSpectrum, RGBIlluminantSpectrum, RGBUnboundedSpectrum, SampledSpectrum,
SampledWavelengths,
@ -168,6 +168,7 @@ impl CreateSpectrumTexture for SpectrumImageTexture {
let filter_options = MIPMapFilterOptions::default();
let wrap_str = parameters.get_one_string("wrap", "repeat")?;
// let wrap_mode = WrapMode::parse(wrap_str)?;
let wrap_mode = match wrap_str.as_str() {
"repeat" => WrapMode::Repeat,
"clamp" => WrapMode::Clamp,
@ -222,18 +223,65 @@ impl FloatImageTexture {
}
impl FloatTextureTrait for FloatImageTexture {
fn evaluate(&self, _ctx: &TextureEvalContext) -> Float {
todo!()
fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
let mut c: TexCoord2D = self.base.mapping.map(ctx);
c.st[1] = 1. - c.st[1];
let v: Float = self.base.scale
* self.base.mipmap.filter::<Float>(
c.st,
Vector2f::new(c.dsdx, c.dtdx),
Vector2f::new(c.dsdy, c.dtdy),
);
if self.base.invert {
(1. - v).max(0.)
} else {
v
}
}
}
impl CreateFloatTexture for FloatImageTexture {
fn create(
_render_from_texture: Transform,
_parameters: TextureParameterDictionary,
_loc: FileLoc,
render_from_texture: Transform,
parameters: TextureParameterDictionary,
loc: FileLoc,
_arena: &Arena,
) -> Result<FloatTexture> {
todo!()
let mapping = TextureMapping2D::create(&parameters, &render_from_texture, &loc)?;
let max_aniso = parameters.get_one_float("maxanisotropy", 8.)?;
let filter = parameters.get_one_string("filter", "bilinear")?;
let mut filter_options = MIPMapFilterOptions::default();
filter_options.max_anisotropy = max_aniso;
let ff = FilterFunction::parse(&filter)?;
filter_options.filter = ff;
let wrap_string = parameters.get_one_string("wrap", "repeat")?;
let wrap_mode = WrapMode::parse(&wrap_string)?;
let scale = parameters.get_one_float("scale", 1.)?;
let invert = parameters.get_one_bool("invert", false)?;
let filename = resolve_filename(&parameters.get_one_string("filename", "")?);
let default_encoding = if Path::new(&filename)
.extension()
.map_or(false, |ext| ext == "png")
{
"sRGB"
} else {
"linear"
};
let encoding_str = parameters.get_one_string("encoding", default_encoding)?;
let encoding = ColorEncoding::from_name(&encoding_str)?;
let tex = FloatImageTexture::new(
mapping,
filename,
filter_options,
wrap_mode,
scale,
invert,
encoding,
);
Ok(FloatTexture::Image(tex))
}
}

View file

@ -3,6 +3,7 @@ use shared::core::color::{ColorEncoding, RGB};
use shared::core::geometry::{Point2f, Point2i, Vector2f, VectorLike};
use shared::core::image::{WrapMode, WrapMode2D};
use shared::spectra::RGBColorSpace;
use anyhow::{bail, Result};
use shared::utils::math::{lerp, safe_sqrt, square};
use shared::Float;
use std::hash::{Hash, Hasher};
@ -21,6 +22,19 @@ pub enum FilterFunction {
Ewa,
}
impl FilterFunction {
pub fn parse(name: &str) -> Result<FilterFunction> {
match name {
"ewa" | "EWA" => Ok(FilterFunction::Ewa),
"trilinear" => Ok(FilterFunction::Trilinear),
"bilinear" => Ok(FilterFunction::Bilinear),
"point" => Ok(FilterFunction::Point),
_ => bail!("Filter function unknown")
}
}
}
impl std::fmt::Display for FilterFunction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {