mesh generation

This commit is contained in:
2024-03-26 19:30:28 -04:00
parent aada52a45b
commit ad1c3e5370
11 changed files with 218 additions and 64 deletions

2
.vscode/launch.json vendored
View File

@@ -13,7 +13,7 @@
"program": "${workspaceRoot}/target/debug/phos.exe", "program": "${workspaceRoot}/target/debug/phos.exe",
"args": [], "args": [],
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"preLaunchTask": "build", "preLaunchTask": "Build",
} }
] ]
} }

16
.vscode/tasks.json vendored
View File

@@ -3,13 +3,15 @@
"tasks": [ "tasks": [
{ {
"type": "cargo", "type": "cargo",
"command":"build", "command": "",
"args":[], "args": [
"group": { "build"
"kind": "build", ],
"isDefault": true "problemMatcher": [
}, "$rustc"
"label":"build" ],
"group": "build",
"label": "Build"
} }
] ]
} }

12
Cargo.lock generated
View File

@@ -2271,6 +2271,15 @@ version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
name = "iyes_perf_ui"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a49f5aa5866dadfdd274c45eddc0a94c84ad1ce0c02c27bcb33c34a20b961f9e"
dependencies = [
"bevy",
]
[[package]] [[package]]
name = "jni" name = "jni"
version = "0.21.1" version = "0.21.1"
@@ -2892,7 +2901,9 @@ version = "0.1.0"
dependencies = [ dependencies = [
"bevy", "bevy",
"bevy-inspector-egui", "bevy-inspector-egui",
"iyes_perf_ui",
"noise 0.8.2", "noise 0.8.2",
"world_generation",
] ]
[[package]] [[package]]
@@ -4274,6 +4285,7 @@ dependencies = [
name = "world_generation" name = "world_generation"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bevy",
"noise 0.9.0", "noise 0.9.0",
] ]

View File

@@ -6,4 +6,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
bevy = "0.13.1"
noise = "0.9.0" noise = "0.9.0"

View File

@@ -1,26 +0,0 @@
pub struct GenerationConfig {
pub noise_scale: f64,
pub sea_level: f64,
pub layers: Vec<GeneratorLayer>,
}
pub struct GeneratorLayer {
pub strength: f64,
pub min_value: f64,
pub base_roughness: f64,
pub roughness: f64,
pub persistence: f64,
pub is_rigid: bool,
pub weight: f64,
pub weight_multi: f64,
pub layers: usize,
pub first_layer_mask: bool,
}
pub struct Chunk {
pub points: Vec<f32>,
pub size: usize,
}
pub struct Map {
pub chunks: Vec<Chunk>,
pub height: usize,
pub width: usize,
}

View File

@@ -1,12 +1,8 @@
mod data; use crate::prelude::*;
use data::*; use bevy::math::IVec2;
use noise::{NoiseFn, SuperSimplex};
pub fn generate_heightmap( pub fn generate_heightmap(height: usize, width: usize, cfg: &GenerationConfig, seed: u32) -> Map {
height: usize,
width: usize,
cfg: &GenerationConfig,
seed: u32,
) -> Map {
let mut chunks: Vec<Chunk> = Vec::with_capacity(height * width); let mut chunks: Vec<Chunk> = Vec::with_capacity(height * width);
for z in 0..height { for z in 0..height {
for x in 0..width { for x in 0..width {
@@ -42,6 +38,7 @@ pub fn generate_chunk(
return Chunk { return Chunk {
points: result, points: result,
size: size, size: size,
chunk_offset: IVec2::new(chunk_x as i32, chunk_z as i32),
}; };
} }

View File

@@ -0,0 +1,10 @@
use bevy::prelude::*;
pub const OUTER_RADIUS: f32 = 1.;
pub const INNER_RADIUS: f32 = OUTER_RADIUS * 0.866025404;
pub fn to_hex_pos(pos: Vec3) -> Vec3 {
let x = (pos.x + pos.z * 0.5 - (pos.z / 2.).floor()) * (INNER_RADIUS * 2.);
return Vec3::new(x, pos.y, pos.z * OUTER_RADIUS * 1.5);
}

View File

@@ -1,9 +1,38 @@
pub mod prelude {
use bevy::math::IVec2;
use noise::{NoiseFn, SuperSimplex}; pub struct GenerationConfig {
pub noise_scale: f64,
pub sea_level: f64,
pub layers: Vec<GeneratorLayer>,
}
pub struct GeneratorLayer {
pub strength: f64,
pub min_value: f64,
pub base_roughness: f64,
pub roughness: f64,
pub persistence: f64,
pub is_rigid: bool,
pub weight: f64,
pub weight_multi: f64,
pub layers: usize,
pub first_layer_mask: bool,
}
pub struct Chunk {
pub points: Vec<f32>,
pub size: usize,
pub chunk_offset: IVec2,
}
pub struct Map {
pub chunks: Vec<Chunk>,
pub height: usize,
pub width: usize,
}
}
pub mod heightmap;
pub mod hex_utils;
pub mod mesh_generator;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@@ -1,6 +1,73 @@
mod data; use crate::{
use data::Chunk; hex_utils::{to_hex_pos, INNER_RADIUS, OUTER_RADIUS},
prelude::*,
};
use bevy::{
prelude::*,
render::{
mesh::{Indices, PrimitiveTopology},
render_asset::RenderAssetUsages,
},
};
pub fn generate_chunk_mesh(chunk: &Chunk){ const HEX_CORNERS: [Vec3; 6] = [
Vec3::new(0., 0., OUTER_RADIUS),
Vec3::new(INNER_RADIUS, 0., 0.5 * OUTER_RADIUS),
Vec3::new(INNER_RADIUS, 0., -0.5 * OUTER_RADIUS),
Vec3::new(0., 0., -OUTER_RADIUS),
Vec3::new(-INNER_RADIUS, 0., -0.5 * OUTER_RADIUS),
Vec3::new(-INNER_RADIUS, 0., 0.5 * OUTER_RADIUS),
];
pub fn generate_chunk_mesh(chunk: &Chunk) -> Mesh {
let vertex_count: usize = chunk.size * chunk.size;
let mut verts = Vec::with_capacity(vertex_count);
let mut uvs = Vec::with_capacity(vertex_count);
let mut normals = Vec::with_capacity(vertex_count);
let mut indices = Vec::with_capacity(vertex_count);
for z in 0..chunk.size {
for x in 0..chunk.size {
let height = chunk.points[x + z * chunk.size];
let off_pos = Vec3::new(x as f32, height, z as f32);
let grid_pos = to_hex_pos(off_pos);
create_tile(grid_pos, &mut verts, &mut uvs, &mut normals, &mut indices);
}
}
let mesh = Mesh::new(
PrimitiveTopology::TriangleList,
RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD,
)
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, verts)
.with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs)
// .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
.with_inserted_indices(Indices::U32(indices))
.with_duplicated_vertices()
.with_computed_flat_normals();
return mesh;
}
//TODO: figure out texture index
fn create_tile(
pos: Vec3,
verts: &mut Vec<Vec3>,
uvs: &mut Vec<Vec2>,
normals: &mut Vec<Vec3>,
indices: &mut Vec<u32>,
) {
let idx = verts.len() as u32;
let center = Vec3::new(pos.x, 0., pos.z);
normals.push(Vec3::Y);
uvs.push(pos.xz());
verts.push(pos);
for i in 0..6 {
let p = pos + HEX_CORNERS[i];
verts.push(p);
uvs.push(p.xz());
normals.push((p - center).normalize());
indices.push(idx);
indices.push(idx + 1 + i as u32);
indices.push(idx + 1 + ((i as u32 + 1) % 6));
}
} }

View File

@@ -6,6 +6,8 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
bevy = "0.13.0" bevy = "0.13.1"
bevy-inspector-egui = "0.23.4" bevy-inspector-egui = "0.23.4"
iyes_perf_ui = "0.2.3"
noise = "0.8.2" noise = "0.8.2"
world_generation ={path="../../engine/world_generation"}

View File

@@ -1,20 +1,33 @@
use bevy::{pbr::CascadeShadowConfig, prelude::*}; use bevy::{pbr::CascadeShadowConfig, prelude::*};
use iyes_perf_ui::prelude::*;
use world_generation::{
heightmap::generate_heightmap, hex_utils::to_hex_pos, mesh_generator::generate_chunk_mesh,
prelude::*,
};
pub struct PhosGamePlugin; pub struct PhosGamePlugin;
impl Plugin for PhosGamePlugin { impl Plugin for PhosGamePlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems(Startup, init_game); app.add_systems(Startup, init_game)
.add_systems(Startup, create_map);
app.add_plugins(bevy::diagnostic::FrameTimeDiagnosticsPlugin)
.add_plugins(bevy::diagnostic::EntityCountDiagnosticsPlugin)
.add_plugins(bevy::diagnostic::SystemInformationDiagnosticsPlugin)
.add_plugins(PerfUiPlugin);
} }
} }
fn init_game(mut commands: Commands) { fn init_game(mut commands: Commands) {
commands.spawn(( commands.spawn((Camera3dBundle {
Camera3dBundle { transform: Transform::from_xyz(-200., 300., -200.)
transform: Transform::from_xyz(0., 50., 0.) .looking_at(Vec3::new(1000., 0., 1000.), Vec3::Y),
.looking_at(Vec3::new(50., 0., 50.), Vec3::Y),
..default() ..default()
}, },));
commands.spawn((
PerfUiRoot::default(),
PerfUiEntryFPS::default(),
PerfUiEntryClock::default(),
)); ));
commands.spawn(DirectionalLightBundle { commands.spawn(DirectionalLightBundle {
@@ -30,3 +43,50 @@ fn init_game(mut commands: Commands) {
..default() ..default()
}); });
} }
fn create_map(
mut commands: Commands,
mut materials: ResMut<Assets<StandardMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
) {
let heightmap = generate_heightmap(
32,
32,
&GenerationConfig {
layers: vec![GeneratorLayer {
base_roughness: 2.14,
roughness: 0.87,
strength: 2.93,
min_value: -0.2,
persistence: 0.77,
is_rigid: false,
weight: 0.,
weight_multi: 0.,
layers: 4,
first_layer_mask: false,
}],
noise_scale: 250.,
sea_level: 4.,
},
1,
);
let debug_material = materials.add(StandardMaterial {
// base_color_texture: Some(images.add(uv_debug_texture())),
..default()
});
for chunk in heightmap.chunks {
let mesh = generate_chunk_mesh(&chunk);
let pos = to_hex_pos(
Vec3::new(chunk.chunk_offset.x as f32, 0., chunk.chunk_offset.y as f32)
* chunk.size as f32,
);
commands.spawn(PbrBundle {
mesh: meshes.add(mesh),
material: debug_material.clone(),
transform: Transform::from_translation(pos),
..default()
});
}
}