use crate::gfx::camera::{camera_to_world, view_ray_scale};
use crate::gfx::render_types::RtParams;
const MAX_INTENSITY: f32 = 1.0;
const MIN_DISTANCE: f32 = 1.0;
const MAX_DISTANCE: f32 = 1000.0;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct RtReflectionSettings {
pub intensity: f32,
pub max_distance: f32,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct RtParamsInputs {
pub fov_y_radians: f32,
pub aspect: f32,
pub inv_view_rot: [[f32; 4]; 4],
pub cam_pos: [f32; 3],
pub sun_dir: [f32; 3],
pub sun_color: [f32; 3],
pub prefilter_mip_count: f32,
pub sky_rot: [[f32; 4]; 3],
}
impl RtReflectionSettings {
pub fn resolve(intensity: f32, max_distance: f32) -> Self {
Self {
intensity: intensity.clamp(0.0, MAX_INTENSITY),
max_distance: max_distance.clamp(MIN_DISTANCE, MAX_DISTANCE),
}
}
pub fn params(&self, inputs: RtParamsInputs) -> RtParams {
let RtParamsInputs {
fov_y_radians,
aspect,
inv_view_rot,
cam_pos,
sun_dir,
sun_color,
prefilter_mip_count,
sky_rot,
} = inputs;
let inv_view = camera_to_world(inv_view_rot, cam_pos);
let (tan_half_fov_y, aspect) = view_ray_scale(fov_y_radians, aspect);
RtParams {
intensity: self.intensity,
max_distance: self.max_distance,
tan_half_fov_y,
aspect,
prefilter_mip_count,
_pad0: 0.0,
_pad1: 0.0,
_pad2: 0.0,
cam_pos: [cam_pos[0], cam_pos[1], cam_pos[2], 0.0],
sun_dir: [sun_dir[0], sun_dir[1], sun_dir[2], 0.0],
sun_color: [sun_color[0], sun_color[1], sun_color[2], 0.0],
inv_view,
sky_rot,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::gfx::camera::MIN_ASPECT;
use crate::gfx::transform::IDENTITY;
use crate::sky::SkyOrientation;
#[test]
fn resolve_clamps_intensity_and_distance() {
let s = RtReflectionSettings::resolve(5.0, 1.0e6);
assert_eq!(s.intensity, MAX_INTENSITY);
assert_eq!(s.max_distance, MAX_DISTANCE);
let s = RtReflectionSettings::resolve(-2.0, -10.0);
assert_eq!(s.intensity, 0.0);
assert_eq!(s.max_distance, MIN_DISTANCE);
}
#[test]
fn resolve_passes_through_in_range_values() {
let s = RtReflectionSettings::resolve(0.7, 60.0);
assert_eq!(s.intensity, 0.7);
assert_eq!(s.max_distance, 60.0);
}
#[test]
fn params_carry_camera_and_sun_inputs() {
let s = RtReflectionSettings::resolve(0.8, 40.0);
let p = s.params(RtParamsInputs {
fov_y_radians: core::f32::consts::FRAC_PI_2,
aspect: 1.6,
inv_view_rot: IDENTITY,
cam_pos: [3.0, 4.0, 5.0],
sun_dir: [0.0, 1.0, 0.0],
sun_color: [1.0, 0.9, 0.8],
prefilter_mip_count: 6.0,
sky_rot: SkyOrientation::IDENTITY_ROWS,
});
assert_eq!(p.intensity, 0.8);
assert_eq!(p.max_distance, 40.0);
assert!((p.tan_half_fov_y - 1.0).abs() < 1.0e-5);
assert_eq!(p.aspect, 1.6);
assert_eq!(p.prefilter_mip_count, 6.0);
assert_eq!(p.cam_pos, [3.0, 4.0, 5.0, 0.0]);
assert_eq!(p.sun_dir, [0.0, 1.0, 0.0, 0.0]);
assert_eq!(p.sun_color, [1.0, 0.9, 0.8, 0.0]);
}
#[test]
fn params_assemble_camera_to_world_translation_column() {
let s = RtReflectionSettings::resolve(0.8, 40.0);
let p = s.params(RtParamsInputs {
fov_y_radians: core::f32::consts::FRAC_PI_2,
aspect: 1.6,
inv_view_rot: IDENTITY,
cam_pos: [3.0, 4.0, 5.0],
sun_dir: [0.0, 1.0, 0.0],
sun_color: [1.0, 1.0, 1.0],
prefilter_mip_count: 6.0,
sky_rot: SkyOrientation::IDENTITY_ROWS,
});
assert_eq!(p.inv_view[3], [3.0, 4.0, 5.0, 1.0]);
assert_eq!(p.inv_view[0], [1.0, 0.0, 0.0, 0.0]);
}
#[test]
fn params_floor_a_degenerate_aspect() {
let s = RtReflectionSettings::resolve(0.7, 40.0);
let p = s.params(RtParamsInputs {
fov_y_radians: core::f32::consts::FRAC_PI_2,
aspect: 0.0,
inv_view_rot: IDENTITY,
cam_pos: [0.0, 0.0, 0.0],
sun_dir: [0.0, 1.0, 0.0],
sun_color: [1.0, 1.0, 1.0],
prefilter_mip_count: 0.0,
sky_rot: SkyOrientation::IDENTITY_ROWS,
});
assert!(p.aspect >= MIN_ASPECT);
}
}