#[derive(Clone)] pub struct LodLevel { pub distance: f32, pub resolution: u32, } pub trait PlanetNoise: Send + Sync { fn get_noise_3d(&self, p: Vec3) -> f32; fn is_base_layer(&self) -> bool; fn amplitude(&self) -> f32; fn min_height(&self) -> f32; } use bevy::prelude::*; #[derive(Resource)] pub struct PlanetData { pub radius: f32, pub lod_focus: Vec3, pub max_lod: usize, pub lod_levels: Vec, /// Noise layers pub planet_noise: Vec>, pub min_height: f32, pub max_height: f32, /// Gradient texture (optional) pub planet_color: Option>, } impl Default for PlanetData { fn default() -> Self { let lod_levels = vec![ LodLevel { distance: 500.0, resolution: 2 }, LodLevel { distance: 50.0, resolution: 2 }, LodLevel { distance: 25.0, resolution: 3 }, LodLevel { distance: 10.0, resolution: 4 }, LodLevel { distance: 1.0, resolution: 10 }, ]; Self { radius: 1.0, lod_focus: Vec3::ZERO, max_lod: lod_levels.len() - 1, lod_levels, planet_noise: Vec::new(), min_height: 9999.0, max_height: 0.0, planet_color: None, } } } impl PlanetData { pub fn point_on_planet(&self, point_on_sphere: Vec3) -> Vec3 { let mut elevation = 0.0; let mut base_layer_mask = 0.0; if !self.planet_noise.is_empty() { // Base layers for n in &self.planet_noise { if n.is_base_layer() { let mut level_base_elevation = n.get_noise_3d(point_on_sphere * 100.0); level_base_elevation = (level_base_elevation + 1.0) / 2.0 * n.amplitude(); level_base_elevation = (level_base_elevation - n.min_height()).max(0.0); base_layer_mask += level_base_elevation; } } // All layers for n in &self.planet_noise { let mut level_elevation = n.get_noise_3d(point_on_sphere * 100.0); level_elevation = (level_elevation + 1.0) / 2.0 * n.amplitude(); level_elevation = (level_elevation - n.min_height()).max(0.0) * base_layer_mask; elevation += level_elevation; } } point_on_sphere * self.radius * (elevation + 1.0) } } pub fn planet_data_changed( planet_data: Res, ) { if planet_data.is_changed() { // Regenerate meshes / LODs } }