use crate::{
optics::{
absorption::{AbsorptionBand, AbsorptionTensor, BandShape},
dispersion::DispersionModel,
materials::GemMaterial,
},
renderer::buffers::{
GpuGemMaterial, MAX_ABSORPTION_BANDS, band_shape, crystal_system, dispersion_model_type,
optical_character,
},
};
use glam::Vec3;
fn probe_material() -> GemMaterial {
let mut material = GemMaterial::by_name("Zircon").expect("Zircon must be a built-in");
material.dispersion = DispersionModel::Cauchy {
a: 1.5,
b: 0.01,
c: 0.0,
};
material.birefringence_delta = 0.05;
material.c_axis = Vec3::X;
material.absorption = AbsorptionTensor::uniaxial(
vec![
AbsorptionBand::new(500.0, 10.0, 1.0),
AbsorptionBand::new(600.0, 20.0, 2.0),
],
vec![
AbsorptionBand::new(510.0, 11.0, 1.5),
AbsorptionBand::new(610.0, 21.0, 2.5),
AbsorptionBand {
center_nm: 700.0,
width_nm: 300.0,
peak: 3.5,
shape: BandShape::GaussianEnergy,
},
],
);
material
}
#[test]
fn encode_places_the_o_and_e_band_sets_in_their_own_slots() {
let gpu = GpuGemMaterial::encode(&probe_material());
assert_eq!(gpu.o_ray_band_count, 2);
assert_eq!(gpu.e_ray_band_count, 3);
assert_eq!(gpu.is_pleochroic, 1);
assert_eq!(gpu.has_beta_ray, 0);
assert_eq!(gpu.beta_ray_band_count, 0);
let o = &gpu.o_ray_bands;
assert_eq!(
(o[0].center_nm, o[0].width_nm, o[0].peak),
(500.0, 10.0, 1.0)
);
assert_eq!(
(o[1].center_nm, o[1].width_nm, o[1].peak),
(600.0, 20.0, 2.0)
);
assert_eq!(o[0].shape, band_shape::GAUSSIAN_WAVELENGTH);
assert_eq!(o[2].peak, 0.0, "slot past the count is an empty band");
let e = &gpu.e_ray_bands;
assert_eq!(
(e[0].center_nm, e[0].width_nm, e[0].peak),
(510.0, 11.0, 1.5)
);
assert_eq!(
(e[1].center_nm, e[1].width_nm, e[1].peak),
(610.0, 21.0, 2.5)
);
assert_eq!(
(e[2].center_nm, e[2].width_nm, e[2].peak),
(700.0, 300.0, 3.5)
);
assert_eq!(e[2].shape, band_shape::GAUSSIAN_ENERGY);
assert_eq!(e[3].peak, 0.0, "slot past the count is an empty band");
}
#[test]
fn encode_places_dispersion_axis_and_class_in_their_slots() {
let gpu = GpuGemMaterial::encode(&probe_material());
assert_eq!(gpu.dispersion.model_type, dispersion_model_type::CAUCHY);
assert_eq!(gpu.dispersion.param_a, [1.5, 0.01, 0.0, 0.0]);
assert_eq!(
gpu.dispersion.c_axis_and_birefringence,
[1.0, 0.0, 0.0, 0.05]
);
assert_eq!(gpu.dispersion.is_anisotropic, 1);
assert_eq!(gpu.dispersion.has_biaxial_delta, 0);
assert_eq!(gpu.crystal_system, crystal_system::TETRAGONAL);
assert_eq!(gpu.optical_character, optical_character::UNIAXIAL_POSITIVE);
assert_eq!(gpu.has_extraordinary_dispersion, 0);
}
#[test]
fn a_custom_material_with_a_dispersion_model_encodes_that_model() {
let three_term = DispersionModel::Sellmeier3 {
b: [1.039_612_2, 0.231_792_35, 1.010_469_4],
c: [0.006_000_699, 0.020_017_914, 103.560_65],
};
let gpu = GpuGemMaterial::encode(&GemMaterial::new_custom_with_dispersion(
"Probe 3", three_term, 0.0, [0.0; 3],
));
assert_eq!(gpu.dispersion.model_type, dispersion_model_type::SELLMEIER3);
assert_eq!(
gpu.dispersion.param_a,
[1.039_612_2, 0.231_792_35, 1.010_469_4, 0.0]
);
assert_eq!(
gpu.dispersion.param_b,
[0.006_000_699, 0.020_017_914, 103.560_65, 0.0]
);
let one_term = DispersionModel::Sellmeier1 { b1: 1.2, c1: 0.009 };
let gpu = GpuGemMaterial::encode(&GemMaterial::new_custom_with_dispersion(
"Probe 1", one_term, 0.0, [0.0; 3],
));
assert_eq!(gpu.dispersion.model_type, dispersion_model_type::SELLMEIER1);
assert_eq!(gpu.dispersion.param_a[0], 1.2);
assert_eq!(gpu.dispersion.param_b[0], 0.009);
let cauchy = DispersionModel::Cauchy {
a: 1.7,
b: 0.006,
c: 0.0001,
};
let gpu = GpuGemMaterial::encode(&GemMaterial::new_custom_with_dispersion(
"Probe C", cauchy, 0.0, [0.0; 3],
));
assert_eq!(gpu.dispersion.model_type, dispersion_model_type::CAUCHY);
assert_eq!(gpu.dispersion.param_a, [1.7, 0.006, 0.0001, 0.0]);
}
#[test]
fn encode_truncates_an_over_long_band_set_to_the_gpu_capacity() {
let mut material = probe_material();
let too_many: Vec<AbsorptionBand> = (0..MAX_ABSORPTION_BANDS + 2)
.map(|i| AbsorptionBand::new((450 + 10 * i) as f32, 5.0, 1.0))
.collect();
material.absorption = AbsorptionTensor::isotropic(too_many);
let gpu = GpuGemMaterial::encode(&material);
assert_eq!(gpu.o_ray_band_count as usize, MAX_ABSORPTION_BANDS);
assert_eq!(gpu.e_ray_band_count as usize, MAX_ABSORPTION_BANDS);
let last = &gpu.o_ray_bands[MAX_ABSORPTION_BANDS - 1];
assert_eq!(
last.center_nm,
(450 + 10 * (MAX_ABSORPTION_BANDS - 1)) as f32
);
}