1use crate::gfx::camera::{camera_to_world, view_ray_scale};
13
14use crate::gfx::render_types::RtParams;
15
16const MAX_INTENSITY: f32 = 1.0;
20
21const MIN_DISTANCE: f32 = 1.0;
23const MAX_DISTANCE: f32 = 1000.0;
27
28#[derive(Debug, Clone, Copy, PartialEq)]
32pub struct RtReflectionSettings {
33 pub intensity: f32,
35 pub max_distance: f32,
37}
38
39#[derive(Debug, Clone, Copy, PartialEq)]
49pub struct RtParamsInputs {
50 pub fov_y_radians: f32,
52 pub aspect: f32,
54 pub inv_view_rot: [[f32; 4]; 4],
56 pub cam_pos: [f32; 3],
58 pub sun_dir: [f32; 3],
60 pub sun_color: [f32; 3],
62 pub prefilter_mip_count: f32,
64 pub sky_rot: [[f32; 4]; 3],
67}
68
69impl RtReflectionSettings {
70 pub fn resolve(intensity: f32, max_distance: f32) -> Self {
72 Self {
73 intensity: intensity.clamp(0.0, MAX_INTENSITY),
74 max_distance: max_distance.clamp(MIN_DISTANCE, MAX_DISTANCE),
75 }
76 }
77
78 pub fn params(&self, inputs: RtParamsInputs) -> RtParams {
81 let RtParamsInputs {
82 fov_y_radians,
83 aspect,
84 inv_view_rot,
85 cam_pos,
86 sun_dir,
87 sun_color,
88 prefilter_mip_count,
89 sky_rot,
90 } = inputs;
91 let inv_view = camera_to_world(inv_view_rot, cam_pos);
92 let (tan_half_fov_y, aspect) = view_ray_scale(fov_y_radians, aspect);
93 RtParams {
94 intensity: self.intensity,
95 max_distance: self.max_distance,
96 tan_half_fov_y,
97 aspect,
98 prefilter_mip_count,
99 _pad0: 0.0,
100 _pad1: 0.0,
101 _pad2: 0.0,
102 cam_pos: [cam_pos[0], cam_pos[1], cam_pos[2], 0.0],
103 sun_dir: [sun_dir[0], sun_dir[1], sun_dir[2], 0.0],
104 sun_color: [sun_color[0], sun_color[1], sun_color[2], 0.0],
105 inv_view,
106 sky_rot,
107 }
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use crate::gfx::camera::MIN_ASPECT;
115 use crate::gfx::transform::IDENTITY;
116 use crate::sky::SkyOrientation;
117
118 #[test]
119 fn resolve_clamps_intensity_and_distance() {
120 let s = RtReflectionSettings::resolve(5.0, 1.0e6);
121 assert_eq!(s.intensity, MAX_INTENSITY);
122 assert_eq!(s.max_distance, MAX_DISTANCE);
123
124 let s = RtReflectionSettings::resolve(-2.0, -10.0);
125 assert_eq!(s.intensity, 0.0);
126 assert_eq!(s.max_distance, MIN_DISTANCE);
127 }
128
129 #[test]
130 fn resolve_passes_through_in_range_values() {
131 let s = RtReflectionSettings::resolve(0.7, 60.0);
132 assert_eq!(s.intensity, 0.7);
133 assert_eq!(s.max_distance, 60.0);
134 }
135
136 #[test]
137 fn params_carry_camera_and_sun_inputs() {
138 let s = RtReflectionSettings::resolve(0.8, 40.0);
139 let p = s.params(RtParamsInputs {
140 fov_y_radians: core::f32::consts::FRAC_PI_2,
141 aspect: 1.6,
142 inv_view_rot: IDENTITY,
143 cam_pos: [3.0, 4.0, 5.0],
144 sun_dir: [0.0, 1.0, 0.0],
145 sun_color: [1.0, 0.9, 0.8],
146 prefilter_mip_count: 6.0,
147 sky_rot: SkyOrientation::IDENTITY_ROWS,
148 });
149 assert_eq!(p.intensity, 0.8);
150 assert_eq!(p.max_distance, 40.0);
151 assert!((p.tan_half_fov_y - 1.0).abs() < 1.0e-5);
153 assert_eq!(p.aspect, 1.6);
154 assert_eq!(p.prefilter_mip_count, 6.0);
155 assert_eq!(p.cam_pos, [3.0, 4.0, 5.0, 0.0]);
156 assert_eq!(p.sun_dir, [0.0, 1.0, 0.0, 0.0]);
157 assert_eq!(p.sun_color, [1.0, 0.9, 0.8, 0.0]);
158 }
159
160 #[test]
161 fn params_assemble_camera_to_world_translation_column() {
162 let s = RtReflectionSettings::resolve(0.8, 40.0);
165 let p = s.params(RtParamsInputs {
166 fov_y_radians: core::f32::consts::FRAC_PI_2,
167 aspect: 1.6,
168 inv_view_rot: IDENTITY,
169 cam_pos: [3.0, 4.0, 5.0],
170 sun_dir: [0.0, 1.0, 0.0],
171 sun_color: [1.0, 1.0, 1.0],
172 prefilter_mip_count: 6.0,
173 sky_rot: SkyOrientation::IDENTITY_ROWS,
174 });
175 assert_eq!(p.inv_view[3], [3.0, 4.0, 5.0, 1.0]);
176 assert_eq!(p.inv_view[0], [1.0, 0.0, 0.0, 0.0]);
178 }
179
180 #[test]
181 fn params_floor_a_degenerate_aspect() {
182 let s = RtReflectionSettings::resolve(0.7, 40.0);
183 let p = s.params(RtParamsInputs {
184 fov_y_radians: core::f32::consts::FRAC_PI_2,
185 aspect: 0.0,
186 inv_view_rot: IDENTITY,
187 cam_pos: [0.0, 0.0, 0.0],
188 sun_dir: [0.0, 1.0, 0.0],
189 sun_color: [1.0, 1.0, 1.0],
190 prefilter_mip_count: 0.0,
191 sky_rot: SkyOrientation::IDENTITY_ROWS,
192 });
193 assert!(p.aspect >= MIN_ASPECT);
194 }
195}