pub struct OceanParams {
pub wind_speed_ms: f64,
pub wind_direction: [f64; 2],
pub fetch_km: f64,
pub depth_m: f64,
pub grid_size: u32,
pub patch_size_m: f64,
pub gravity: f64,
}
impl Default for OceanParams {
fn default() -> Self {
Self {
wind_speed_ms: 10.0,
wind_direction: [1.0, 0.0],
fetch_km: 500.0,
depth_m: 4000.0,
grid_size: 256,
patch_size_m: 1000.0,
gravity: *crate::SURFACE_GRAVITY,
}
}
}
pub struct OceanSpectrum {
pub heights: Vec<f64>,
pub normals: Vec<[f64; 3]>,
pub grid_size: u32,
}
impl OceanParams {
pub fn phillips_spectrum(&self, kx: f64, ky: f64) -> f64 {
let k_sq = kx * kx + ky * ky;
if k_sq < 1e-12 {
return 0.0;
}
let k = k_sq.sqrt();
let l = self.wind_speed_ms * self.wind_speed_ms / self.gravity;
let k_dot_w = (kx * self.wind_direction[0] + ky * self.wind_direction[1]) / k;
let damping = 0.001;
let phillips = ((-1.0 / (k * l).powi(2)).exp() / k_sq.powi(2))
* k_dot_w.powi(2)
* (-k_sq * damping * damping).exp();
phillips.max(0.0)
}
pub fn generate_spectrum(&self) -> OceanSpectrum {
let n = self.grid_size as usize;
let mut heights = vec![0.0; n * n];
let normals = vec![[0.0, 1.0, 0.0]; n * n];
for j in 0..n {
for i in 0..n {
let kx =
(2.0 * std::f64::consts::PI * (i as f64 - n as f64 / 2.0)) / self.patch_size_m;
let ky =
(2.0 * std::f64::consts::PI * (j as f64 - n as f64 / 2.0)) / self.patch_size_m;
heights[j * n + i] = self.phillips_spectrum(kx, ky).sqrt();
}
}
OceanSpectrum {
heights,
normals,
grid_size: self.grid_size,
}
}
pub fn dispersion(&self, k: f64) -> f64 {
(self.gravity * k * (k * self.depth_m).tanh()).sqrt()
}
}