SdfState

Trait SdfState 

Source
pub trait SdfState<Scalar: Float, const DIM: usize>:
    'static
    + Clone
    + Default {
    type Sample;

    // Required methods
    fn mix(&self, other: &Self, factor: Scalar) -> Self;
    fn sample(&self, position: &[Scalar; DIM]) -> Self::Sample;
}
Expand description

Trait corresponding to types that can be bound to an SDF.

Examples of things that could be a state would be colors or materials (when doing 3D rendering)

§Example

// A simple Phong material model
use lightwalk::prelude::*;
use glam::{Vec3, vec3, FloatExt};

// We need to derive Clone and Default
// (default will be done manually)
#[derive(Clone)]
struct PhongMaterial {
    diffuse_color: Vec3,
    diffuse_factor: f32,

    specular_color: Vec3,
    specular_factor: f32,
    specular_exponent: f32,
}

// Provide a default material
impl Default for PhongMaterial {
    fn default() -> Self {
        Self {
            diffuse_color: Vec3::ONE,
            diffuse_factor: 1.0,
            specular_color: Vec3::ONE,
            specular_factor: 1.0,
            specular_exponent: 32.0,
        }
    }
}

impl SdfState<f32, 3> for PhongMaterial {
    type Sample = Self;

    fn mix(&self, other: &Self, factor: f32) -> Self {
        // self.clone()
        Self {
            diffuse_color: self.diffuse_color.lerp(other.diffuse_color, factor),
            diffuse_factor: self.diffuse_factor.lerp(other.diffuse_factor, factor),
            specular_color: self.specular_color.lerp(other.specular_color, factor),
            specular_factor: self.specular_factor.lerp(other.specular_factor, factor),
            specular_exponent: self.specular_exponent.lerp(other.specular_exponent, factor),
        }
    }

    #[inline]
    fn sample(&self, _: &[f32; 3]) -> Self::Sample {
        self.clone()
    }
}

// We can now bind this material to a SDF:
let cube = Cube.bind(PhongMaterial {
    diffuse_color: vec3(1.0, 0.0, 0.0),
    ..Default::default()
});

let sphere = Sphere.bind(PhongMaterial {
    diffuse_color: vec3(0.0, 1.0, 0.0),
    ..Default::default()
});

// We can combine a sphere and a cube because their states match
let sdf = sphere.add(cube);

// And we can now fetch the state at a point:
// NOTE: This will grab the state of the closest shape (and if the union is
// smoothed, so will the states).
let state = sdf.state([2.0, 5.0, 1.0]);

Required Associated Types§

Source

type Sample

In the off chance the state needs to be more complex than the data we wish to query (for example if the state holds texture information), a sample can be constructed at some point in space. See SdfState::sample. If this is not required, just use type Sample = Self, it’s not required anyways.

Required Methods§

Source

fn mix(&self, other: &Self, factor: Scalar) -> Self

Linear interpolation between self and other depending on factor (which ranges between 0 and 1)

Source

fn sample(&self, position: &[Scalar; DIM]) -> Self::Sample

Samples the state at some point in space. Sometimes needed for when the data contained in the state type does not directly map the state of the SDF at some coordinate, for example when using textures, or when generating the state on-the-fly (and thus not storing the data in the actual state)

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementations on Foreign Types§

Source§

impl<Scalar: Float, const DIM: usize> SdfState<Scalar, DIM> for ()

Source§

type Sample = ()

Source§

fn mix(&self, _: &Self, _: Scalar)

Source§

fn sample(&self, _: &[Scalar; DIM])

Implementors§