diff --git a/Cargo.toml b/Cargo.toml index 15c8868..21d471f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" bytemuck = { version = "^1.0", features = ["derive"] } glam = "0.20" multimap = "0.8" +noise = "^0.7" notify = "^4" parking_lot = "^0.11" pollster = "0.2" diff --git a/src/main.rs b/src/main.rs index da0bc65..8d31802 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,8 +37,8 @@ impl Default for SpawnDistributions { fn default() -> Self { Self { theta: rand::distributions::Uniform::new(0.0, std::f32::consts::TAU), - radius: rand::distributions::Uniform::new(4.0, 5.0), - up: rand::distributions::Uniform::new(10.0, 15.0), + radius: rand::distributions::Uniform::new(3.0, 4.0), + up: rand::distributions::Uniform::new(8.0, 12.0), } } } @@ -94,10 +94,7 @@ fn update_transforms(transform: &mut cyborg::scene::Transform, particle: &Partic } #[system(for_each)] -fn update_debug( - draw_list: &mut cyborg::scene::DebugDrawList, - velocity: &Velocity, -) { +fn update_debug(draw_list: &mut cyborg::scene::DebugDrawList, velocity: &Velocity) { draw_list.clear(); draw_list.indices.extend_from_slice(&[0, 1]); @@ -125,6 +122,83 @@ fn build_update_schedule() -> Schedule { builder.build() } +fn make_terrain(attributes: &mesh::Attributes) -> MeshBuffer { + const MOUNTAINS_RADIUS: f32 = 25.0; + const MOUNTAINS_WIDTH: f32 = 10.0; + const MOUNTAINS_HEIGHT: f32 = 5.0; + const MOUNTAINS_FREQUENCY: f32 = 1.0; + + use noise::NoiseFn; + let noise = noise::OpenSimplex::new(); + + let sample = |xy: glam::Vec2| -> f32 { + let mountains_dist = (xy.length() - MOUNTAINS_RADIUS).abs() / MOUNTAINS_WIDTH; + let mountains_scale = 1.0 - mountains_dist; + if mountains_scale > 0.0 { + let noise_input = (xy * MOUNTAINS_FREQUENCY).as_dvec2(); + let sampled = noise.get(noise_input.to_array()) as f32; + ((sampled + 0.5) / 0.5) * MOUNTAINS_HEIGHT * mountains_scale + } else { + 0.0 + } + }; + + const GRID_FREQUENCY: f32 = 0.2; + const GRID_RADIUS: isize = ((MOUNTAINS_RADIUS + MOUNTAINS_WIDTH) / GRID_FREQUENCY) as isize; + const GRID_WIDTH: isize = GRID_RADIUS * 2 + 1; + + let tile_num = (GRID_RADIUS * GRID_RADIUS) as usize; + let mut vertices = Vec::with_capacity(tile_num); + let mut indices = Vec::with_capacity(tile_num * 6); + + for x in -GRID_RADIUS..=GRID_RADIUS { + for z in -GRID_RADIUS..=GRID_RADIUS { + let x = x as f32 * GRID_FREQUENCY; + let z = z as f32 * GRID_FREQUENCY; + let y = sample(glam::Vec2::new(x, z)); + + vertices.push(mesh::Vertex { + position: [x, y, z], + tan_frame: 0, + }); + } + } + + let mut cursor: mesh::Index = 0; + for _x in -GRID_RADIUS..GRID_RADIUS { + for _z in -GRID_RADIUS..GRID_RADIUS { + let next_line = cursor + GRID_WIDTH as mesh::Index; + indices.extend_from_slice(&[ + cursor, + next_line, + cursor + 1, + next_line, + cursor + 1, + next_line + 1, + ]); + cursor += 1; + } + cursor += 1; + } + + let vertices = AttrBuffer { + id: attributes.vertex, + count: vertices.len(), + data: bytemuck::cast_slice(&vertices).to_vec(), + }; + + let indices = AttrBuffer { + id: attributes.index, + count: indices.len(), + data: bytemuck::cast_slice(&indices).to_vec(), + }; + + let mut mesh = MeshBuffer::default(); + mesh.attributes.push(vertices); + mesh.attributes.push(indices); + mesh +} + fn main() { let event_loop = EventLoop::new(); let window = WindowBuilder::new().build(&event_loop).unwrap(); @@ -205,6 +279,18 @@ fn main() { example_mesh.attributes.push(example_indices); let example_mesh = mesh_pass.get_mesh_pool().load(example_mesh).unwrap(); + world.push(( + cyborg::scene::Mesh { + mesh: mesh_pass + .get_mesh_pool() + .load(make_terrain(attributes)) + .unwrap(), + }, + cyborg::scene::Transform { + transform: glam::Mat4::from_translation(glam::Vec3::new(0.0, -10.0, 0.0)), + }, + )); + drop(mesh_pass); let r = 6;