height map generator

This commit is contained in:
2024-03-24 21:36:26 -04:00
commit e9757a5371
13 changed files with 4650 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

19
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,19 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "cppvsdbg",
"stopAtEntry": false,
// "console": "externalTerminal",
"request": "launch",
"name": "Debug",
"program": "${workspaceRoot}/target/debug/phos.exe",
"args": [],
"cwd": "${workspaceRoot}",
"preLaunchTask": "build",
}
]
}

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"cmake.configureOnOpen": false
}

15
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,15 @@
{
"version": "2.0.0",
"tasks":[
{
"type":"cargo",
"command":"build",
"args":[],
"group": {
"kind": "build",
"isDefault": true
},
"label":"build"
}
]
}

4361
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

15
Cargo.toml Normal file
View File

@@ -0,0 +1,15 @@
[workspace]
members = [
"game/main",
"engine/world_generation"
]
resolver = "2"
# Enable a small amount of optimization in debug mode
[profile.dev]
opt-level = 1
# Enable high optimizations for dependencies (incl. Bevy), but not for our code:
[profile.dev.package."*"]
opt-level = 3

View File

@@ -0,0 +1,9 @@
[package]
name = "world_generation"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
noise = "0.9.0"

View File

@@ -0,0 +1,149 @@
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 struct Map {
pub chunks: Vec<Chunk>,
pub height: usize,
pub width: usize,
}
pub fn generate_heightmap(
height: usize,
width: usize,
cfg: &GenerationConfig,
seed: u32,
) -> Map {
let mut chunks: Vec<Chunk> = Vec::with_capacity(height * width);
for z in 0..height {
for x in 0..width {
chunks.push(generate_chunk(x as f64, z as f64, 32, cfg, seed));
}
}
return Map {
chunks: chunks,
height: height,
width: width,
};
}
pub fn generate_chunk(
chunk_x: f64,
chunk_z: f64,
size: usize,
cfg: &GenerationConfig,
seed: u32,
) -> Chunk {
let mut result: Vec<f32> = Vec::with_capacity(size * size);
let noise = SuperSimplex::new(seed);
for z in 0..size {
for x in 0..size {
result.push(sample_point(
x as f64 + chunk_x * size as f64,
z as f64 + chunk_z * size as f64,
&cfg,
&noise,
));
}
}
return Chunk {
points: result,
size: size,
};
}
fn sample_point(x: f64, z: f64, cfg: &GenerationConfig, noise: &SuperSimplex) -> f32 {
let x_s = x / cfg.noise_scale;
let z_s = z / cfg.noise_scale;
let mut elevation: f64 = 0.;
let mut first_layer: f64 = 0.;
for i in 0..cfg.layers.len() {
let value: f64;
let layer = &cfg.layers[i];
if layer.is_rigid {
value = sample_rigid(x_s, z_s, layer, noise);
} else {
value = sample_simple(x_s, z_s, layer, noise);
}
if i == 0 {
first_layer = value;
}
if layer.first_layer_mask {
elevation += mask(first_layer, value, cfg.sea_level);
} else {
elevation += value;
}
}
return elevation as f32;
}
fn mask(mask: f64, value: f64, sea_level: f64) -> f64 {
let m = (mask - sea_level).max(0.);
return value * m;
}
fn sample_simple(x: f64, z: f64, cfg: &GeneratorLayer, noise: &SuperSimplex) -> f64 {
let mut freq: f64 = cfg.base_roughness;
let mut amp: f64 = 1.;
let mut value = 0.;
for _ in 0..cfg.layers {
let v = noise.get([x * freq, z * freq]);
value += (v + 1.) * 0.5 * amp;
freq *= cfg.roughness;
amp *= cfg.persistence;
}
value -= cfg.min_value;
return value * cfg.strength;
}
fn sample_rigid(x: f64, z: f64, cfg: &GeneratorLayer, noise: &SuperSimplex) -> f64 {
let mut freq: f64 = cfg.base_roughness;
let mut amp: f64 = 1.;
let mut value = 0.;
let mut weight = 1.;
for _ in 0..cfg.layers {
let mut v = 1. - noise.get([x * freq, z * freq]).abs();
v *= v;
v *= weight;
weight = v * cfg.weight_multi;
weight = weight.clamp(0., 1.);
value += v * amp;
freq *= cfg.roughness;
amp *= cfg.persistence;
}
value -= cfg.min_value;
return value * cfg.strength;
}
#[cfg(test)]
mod tests {
use super::*;
// #[test]
// fn it_works() {
// let result = add(2, 2);
// assert_eq!(result, 4);
// }
}

View File

@@ -0,0 +1,6 @@
mod lib;
use lib::Chunk;
pub fn generate_chunk_mesh(chunk: &Chunk){
}

11
game/main/Cargo.toml Normal file
View File

@@ -0,0 +1,11 @@
[package]
name = "phos"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bevy = "0.13.0"
bevy-inspector-egui = "0.23.4"
noise = "0.8.2"

28
game/main/src/main.rs Normal file
View File

@@ -0,0 +1,28 @@
use bevy::{pbr::wireframe::WireframePlugin, prelude::*};
use bevy_inspector_egui::quick::WorldInspectorPlugin;
mod phos;
use phos::PhosGamePlugin;
fn main() {
App::new()
.add_plugins((
DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
title: "Phos".into(),
name: Some("phos".into()),
resolution: (1920.0, 1080.0).into(),
resizable: false,
enabled_buttons: bevy::window::EnabledButtons {
maximize: false,
..Default::default()
},
..default()
}),
..default()
}),
WireframePlugin,
WorldInspectorPlugin::new(),
PhosGamePlugin,
))
.run();
}

32
game/main/src/phos.rs Normal file
View File

@@ -0,0 +1,32 @@
use bevy::{pbr::CascadeShadowConfig, prelude::*};
pub struct PhosGamePlugin;
impl Plugin for PhosGamePlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, init_game);
}
}
fn init_game(mut commands: Commands) {
commands.spawn((
Camera3dBundle {
transform: Transform::from_xyz(0., 50., 0.)
.looking_at(Vec3::new(50., 0., 50.), Vec3::Y),
..default()
},
));
commands.spawn(DirectionalLightBundle {
directional_light: DirectionalLight {
shadows_enabled: false,
..default()
},
cascade_shadow_config: CascadeShadowConfig {
bounds: vec![20., 40., 80., 1000., 5000., 19000., 20000.],
..default()
},
transform: Transform::from_xyz(0.0, 16.0, 5.).looking_at(Vec3::ZERO, Vec3::Y),
..default()
});
}

1
rustfmt.toml Normal file
View File

@@ -0,0 +1 @@
hard_tabs=true