mirror of
https://github.com/eliasstepanik/voxel-simulation.git
synced 2026-01-11 13:58:30 +00:00
remove network stack + refactor + readded old voxel system + added skybox
This commit is contained in:
parent
e3e3d4d7a2
commit
0329a9015d
@ -10,11 +10,8 @@ build = "build.rs"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy = { version = "0.15.1", features = ["jpeg", "trace_tracy", "trace_tracy_memory"] }
|
bevy = { version = "0.15.1", features = ["jpeg", "trace_tracy", "trace_tracy_memory"] }
|
||||||
bevy_egui = "0.33.0"
|
|
||||||
random_word = { version = "0.5.0", features = ["en"] }
|
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
toml = "0.8"
|
toml = "0.8"
|
||||||
big_space = "0.9.1"
|
big_space = "0.9.1"
|
||||||
|
noise = "0.9.0"
|
||||||
|
|
||||||
BIN
client/assets/textures/skybox_space_1024/back.png
Normal file
BIN
client/assets/textures/skybox_space_1024/back.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 659 KiB |
BIN
client/assets/textures/skybox_space_1024/bottom.png
Normal file
BIN
client/assets/textures/skybox_space_1024/bottom.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 740 KiB |
BIN
client/assets/textures/skybox_space_1024/front.png
Normal file
BIN
client/assets/textures/skybox_space_1024/front.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 683 KiB |
BIN
client/assets/textures/skybox_space_1024/left.png
Normal file
BIN
client/assets/textures/skybox_space_1024/left.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 672 KiB |
BIN
client/assets/textures/skybox_space_1024/right.png
Normal file
BIN
client/assets/textures/skybox_space_1024/right.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 711 KiB |
BIN
client/assets/textures/skybox_space_1024/top.png
Normal file
BIN
client/assets/textures/skybox_space_1024/top.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 568 KiB |
@ -1,3 +1,4 @@
|
|||||||
|
use bevy::pbr::wireframe::WireframePlugin;
|
||||||
use crate::helper::debug_gizmos::debug_gizmos;
|
use crate::helper::debug_gizmos::debug_gizmos;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
pub struct AppPlugin;
|
pub struct AppPlugin;
|
||||||
@ -9,6 +10,7 @@ impl Plugin for AppPlugin {
|
|||||||
app.add_plugins(crate::plugins::environment::environment_plugin::EnvironmentPlugin);
|
app.add_plugins(crate::plugins::environment::environment_plugin::EnvironmentPlugin);
|
||||||
//app.add_plugins(crate::plugins::network::network_plugin::NetworkPlugin);
|
//app.add_plugins(crate::plugins::network::network_plugin::NetworkPlugin);
|
||||||
app.add_plugins(crate::plugins::input::input_plugin::InputPlugin);
|
app.add_plugins(crate::plugins::input::input_plugin::InputPlugin);
|
||||||
|
app.add_plugins(WireframePlugin);
|
||||||
|
|
||||||
app.add_systems(Update, (debug_gizmos));
|
app.add_systems(Update, (debug_gizmos));
|
||||||
app.register_type::<Option<Handle<Image>>>();
|
app.register_type::<Option<Handle<Image>>>();
|
||||||
|
|||||||
@ -13,7 +13,6 @@ use bevy::render::RenderPlugin;
|
|||||||
use bevy::DefaultPlugins;
|
use bevy::DefaultPlugins;
|
||||||
use bevy::input::gamepad::AxisSettingsError::DeadZoneUpperBoundGreaterThanLiveZoneUpperBound;
|
use bevy::input::gamepad::AxisSettingsError::DeadZoneUpperBoundGreaterThanLiveZoneUpperBound;
|
||||||
use bevy::window::PresentMode;
|
use bevy::window::PresentMode;
|
||||||
use bevy_egui::EguiPlugin;
|
|
||||||
use big_space::plugin::BigSpacePlugin;
|
use big_space::plugin::BigSpacePlugin;
|
||||||
use toml;
|
use toml;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
@ -42,7 +41,7 @@ fn main() {
|
|||||||
register_platform_plugins(&mut app);
|
register_platform_plugins(&mut app);
|
||||||
|
|
||||||
app.add_plugins(AppPlugin);
|
app.add_plugins(AppPlugin);
|
||||||
app.add_plugins(EguiPlugin);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use bevy::app::{App, Plugin, PreStartup, PreUpdate, Startup};
|
use bevy::app::{App, Plugin, PreStartup, PreUpdate, Startup};
|
||||||
use bevy::prelude::IntoSystemConfigs;
|
use bevy::prelude::*;
|
||||||
|
use crate::plugins::environment::systems::voxels::structure::SparseVoxelOctree;
|
||||||
|
|
||||||
pub struct EnvironmentPlugin;
|
pub struct EnvironmentPlugin;
|
||||||
impl Plugin for EnvironmentPlugin {
|
impl Plugin for EnvironmentPlugin {
|
||||||
@ -7,9 +8,31 @@ impl Plugin for EnvironmentPlugin {
|
|||||||
|
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
Startup,
|
Startup,
|
||||||
(crate::plugins::environment::systems::camera_system::setup,crate::plugins::environment::systems::environment_system::setup.after(crate::plugins::environment::systems::camera_system::setup) ),
|
(
|
||||||
|
crate::plugins::environment::systems::camera_system::setup,
|
||||||
|
crate::plugins::environment::systems::environment_system::setup.after(crate::plugins::environment::systems::camera_system::setup),
|
||||||
|
crate::plugins::environment::systems::voxel_system::setup
|
||||||
|
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
app.add_systems(Update, (crate::plugins::environment::systems::voxels::rendering::render,crate::plugins::environment::systems::voxels::debug::visualize_octree_system.run_if(should_visualize_octree), crate::plugins::environment::systems::voxels::debug::draw_grid.run_if(should_draw_grid)).chain());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn should_visualize_octree(octree_query: Query<&SparseVoxelOctree>,) -> bool {
|
||||||
|
octree_query.single().show_wireframe
|
||||||
|
}
|
||||||
|
|
||||||
|
fn should_draw_grid(octree_query: Query<&SparseVoxelOctree>,) -> bool {
|
||||||
|
octree_query.single().show_world_grid
|
||||||
|
}
|
||||||
|
|
||||||
|
fn should_visualize_chunks(octree_query: Query<&SparseVoxelOctree>,) -> bool {
|
||||||
|
octree_query.single().show_chunks
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
|
use bevy::core_pipeline::Skybox;
|
||||||
use bevy::input::mouse::{MouseMotion, MouseWheel};
|
use bevy::input::mouse::{MouseMotion, MouseWheel};
|
||||||
use bevy::math::Vec3;
|
use bevy::math::Vec3;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
@ -26,11 +26,13 @@ impl Default for CameraController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn setup(mut commands: Commands,
|
pub fn setup(mut commands: Commands,
|
||||||
root: Res<RootGrid>,) {
|
root: Res<RootGrid>,
|
||||||
|
asset_server: Res<AssetServer>) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let cubemap_handle = asset_server.load("textures/skybox_space_1024/sky.ktx2");
|
||||||
|
commands.insert_resource(PendingSkybox { handle: cubemap_handle.clone() });
|
||||||
|
|
||||||
commands.entity(root.0).with_children(|parent| {
|
commands.entity(root.0).with_children(|parent| {
|
||||||
parent.spawn((
|
parent.spawn((
|
||||||
@ -51,7 +53,20 @@ pub fn setup(mut commands: Commands,
|
|||||||
sensor_height: 0.01866,
|
sensor_height: 0.01866,
|
||||||
}),
|
}),
|
||||||
FloatingOrigin,
|
FloatingOrigin,
|
||||||
|
Skybox {
|
||||||
|
image: cubemap_handle.clone(),
|
||||||
|
brightness: 1000.0,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
struct PendingSkybox {
|
||||||
|
handle: Handle<Image>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
pub mod environment_system;
|
pub mod environment_system;
|
||||||
pub mod camera_system;
|
pub mod camera_system;
|
||||||
mod planet;
|
pub mod planet_system;
|
||||||
|
pub mod voxels;
|
||||||
|
pub mod voxel_system;
|
||||||
@ -1,71 +0,0 @@
|
|||||||
use bevy::asset::RenderAssetUsages;
|
|
||||||
use bevy::prelude::*;
|
|
||||||
use bevy::render::mesh::*;
|
|
||||||
use big_space::floating_origins::FloatingOrigin;
|
|
||||||
use big_space::prelude::GridCell;
|
|
||||||
use crate::plugins::big_space::big_space_plugin::RootGrid;
|
|
||||||
use crate::plugins::environment::systems::camera_system::CameraController;
|
|
||||||
|
|
||||||
pub struct PlanetMaker {}
|
|
||||||
|
|
||||||
|
|
||||||
fn setup(
|
|
||||||
mut commands: Commands,
|
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
|
||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
|
||||||
root: Res<RootGrid>
|
|
||||||
) {
|
|
||||||
// Four corner vertices – y is up in Bevy’s 3-D coordinate system
|
|
||||||
let positions = vec![
|
|
||||||
[-0.5, 0.0, -0.5],
|
|
||||||
[ 0.5, 0.0, -0.5],
|
|
||||||
[ 0.5, 0.0, 0.5],
|
|
||||||
[-0.5, 0.0, 0.5],
|
|
||||||
];
|
|
||||||
|
|
||||||
// Single normal for all vertices (pointing up)
|
|
||||||
let normals = vec![[0.0, 1.0, 0.0]; 4];
|
|
||||||
|
|
||||||
// UVs for a full-size texture
|
|
||||||
let uvs = vec![
|
|
||||||
[0.0, 0.0],
|
|
||||||
[1.0, 0.0],
|
|
||||||
[1.0, 1.0],
|
|
||||||
[0.0, 1.0],
|
|
||||||
];
|
|
||||||
|
|
||||||
// Two triangles: (0,1,2) and (0,2,3)
|
|
||||||
let indices = Indices::U32(vec![0, 1, 2, 0, 2, 3]);
|
|
||||||
|
|
||||||
let plane = Mesh::new(
|
|
||||||
PrimitiveTopology::TriangleList,
|
|
||||||
RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD,
|
|
||||||
)
|
|
||||||
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions)
|
|
||||||
.with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
|
|
||||||
.with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs)
|
|
||||||
.with_inserted_indices(indices);
|
|
||||||
|
|
||||||
let mesh_handle = meshes.add(plane);
|
|
||||||
let material_handle = materials.add(StandardMaterial::from_color(Color::srgb(0.3, 0.6, 1.0)));
|
|
||||||
|
|
||||||
|
|
||||||
let sphere = meshes.add(
|
|
||||||
SphereMeshBuilder::new(1.0, SphereKind::Ico { subdivisions: 5 })
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
commands.entity(root.0).with_children(|parent| {
|
|
||||||
|
|
||||||
parent.spawn((
|
|
||||||
Name::new("Planet"),
|
|
||||||
Mesh3d(sphere),
|
|
||||||
MeshMaterial3d(material_handle),
|
|
||||||
GridCell::<i64>::ZERO,
|
|
||||||
Transform::from_translation(Vec3::new(0.0, 0.0, 0.0)),
|
|
||||||
));
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
116
client/src/plugins/environment/systems/planet_system.rs
Normal file
116
client/src/plugins/environment/systems/planet_system.rs
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
use bevy::asset::RenderAssetUsages;
|
||||||
|
use bevy::pbr::wireframe::{Wireframe, WireframeColor};
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy::render::mesh::*;
|
||||||
|
use big_space::floating_origins::FloatingOrigin;
|
||||||
|
use big_space::prelude::GridCell;
|
||||||
|
use noise::{Fbm, NoiseFn, Perlin};
|
||||||
|
use crate::plugins::big_space::big_space_plugin::RootGrid;
|
||||||
|
use crate::plugins::environment::systems::camera_system::CameraController;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct PlanetMaker;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
pub struct PlanetNoise(pub Fbm<Perlin>);
|
||||||
|
|
||||||
|
pub fn setup(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
|
root: Res<RootGrid>,
|
||||||
|
) {
|
||||||
|
// Diameter ~ Earth (~12,742 km) × 2 to exaggerate terrain if desired
|
||||||
|
let radius = 12_742_000.0;
|
||||||
|
let sphere_mesh = meshes.add(
|
||||||
|
SphereMeshBuilder::new(radius, SphereKind::Ico { subdivisions: 100 })
|
||||||
|
.build(),
|
||||||
|
);
|
||||||
|
let material_handle = materials.add(StandardMaterial::from(Color::rgb(0.3, 0.6, 1.0)));
|
||||||
|
|
||||||
|
commands.entity(root.0).with_children(|parent| {
|
||||||
|
parent.spawn((
|
||||||
|
Name::new("Planet"),
|
||||||
|
Mesh3d(sphere_mesh.clone()),
|
||||||
|
MeshMaterial3d(material_handle),
|
||||||
|
GridCell::<i64>::ZERO,
|
||||||
|
Transform::default(),
|
||||||
|
PlanetMaker,
|
||||||
|
Wireframe,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub(crate) fn setup_noise(mut commands: Commands) {
|
||||||
|
let fbm_noise = Fbm::<Perlin>::new(0);
|
||||||
|
commands.insert_resource(PlanetNoise(fbm_noise));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deform_planet(
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
noise: Res<PlanetNoise>,
|
||||||
|
query: Query<&Mesh3d, With<PlanetMaker>>,
|
||||||
|
) {
|
||||||
|
let frequency = 4.0 / 12_742_000.0;
|
||||||
|
let amplitude = 100_000.0;
|
||||||
|
|
||||||
|
for mesh3d in query.iter() {
|
||||||
|
let handle: &Handle<Mesh> = &mesh3d.0;
|
||||||
|
|
||||||
|
if let Some(mesh) = meshes.get_mut(handle) {
|
||||||
|
// 1. Immutable borrow to extract normals (or default)
|
||||||
|
let normals: Vec<[f32; 3]> = if let Some(VertexAttributeValues::Float32x3(vals)) =
|
||||||
|
mesh.attribute(Mesh::ATTRIBUTE_NORMAL)
|
||||||
|
{
|
||||||
|
vals.clone()
|
||||||
|
} else {
|
||||||
|
// default normals if none exist
|
||||||
|
let count = mesh
|
||||||
|
.attribute(Mesh::ATTRIBUTE_POSITION)
|
||||||
|
.and_then(|attr| match attr {
|
||||||
|
VertexAttributeValues::Float32x3(v) => Some(v.len()),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.unwrap_or(0);
|
||||||
|
vec![[0.0, 1.0, 0.0]; count]
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. Drop the immutable borrow, then mutable-borrow positions
|
||||||
|
if let Some(VertexAttributeValues::Float32x3(positions)) =
|
||||||
|
mesh.attribute_mut(Mesh::ATTRIBUTE_POSITION)
|
||||||
|
{
|
||||||
|
// Now mutate positions using the pre-fetched normals
|
||||||
|
for (i, pos) in positions.iter_mut().enumerate() {
|
||||||
|
let mut vertex = Vec3::new(pos[0], pos[1], pos[2]);
|
||||||
|
let normal = Vec3::new(
|
||||||
|
normals[i][0],
|
||||||
|
normals[i][1],
|
||||||
|
normals[i][2],
|
||||||
|
);
|
||||||
|
|
||||||
|
let unit_dir = vertex.normalize();
|
||||||
|
let sample = [
|
||||||
|
unit_dir.x as f64 * frequency as f64,
|
||||||
|
unit_dir.y as f64 * frequency as f64,
|
||||||
|
unit_dir.z as f64 * frequency as f64,
|
||||||
|
];
|
||||||
|
let noise_value = noise.0.get(sample) as f32;
|
||||||
|
let offset = normal * (noise_value * amplitude);
|
||||||
|
|
||||||
|
let new_pos = unit_dir * (vertex.length() + offset.length());
|
||||||
|
*pos = [new_pos.x, new_pos.y, new_pos.z];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mesh.compute_smooth_normals();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force AABB recalc
|
||||||
|
mesh.remove_attribute(Mesh::ATTRIBUTE_COLOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
152
client/src/plugins/environment/systems/voxel_system.rs
Normal file
152
client/src/plugins/environment/systems/voxel_system.rs
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
use bevy::asset::RenderAssetUsages;
|
||||||
|
use bevy::pbr::wireframe::{Wireframe, WireframeColor};
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy::render::mesh::*;
|
||||||
|
use big_space::floating_origins::FloatingOrigin;
|
||||||
|
use big_space::prelude::GridCell;
|
||||||
|
use noise::{Fbm, NoiseFn, Perlin};
|
||||||
|
use crate::plugins::big_space::big_space_plugin::RootGrid;
|
||||||
|
use crate::plugins::environment::systems::camera_system::CameraController;
|
||||||
|
use crate::plugins::environment::systems::voxels::structure::*;
|
||||||
|
|
||||||
|
pub fn setup(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
|
root: Res<RootGrid>,
|
||||||
|
) {
|
||||||
|
let unit_size = 1.0;
|
||||||
|
|
||||||
|
let octree_base_size = 64.0 * unit_size; // Octree's total size in your world space
|
||||||
|
let octree_depth = 10;
|
||||||
|
|
||||||
|
|
||||||
|
let mut octree = SparseVoxelOctree::new(octree_depth, octree_base_size as f32, false, false, false);
|
||||||
|
|
||||||
|
|
||||||
|
let color = Color::rgb(0.2, 0.8, 0.2);
|
||||||
|
/*generate_voxel_rect(&mut octree,color);*/
|
||||||
|
generate_voxel_sphere(&mut octree, 10, color);
|
||||||
|
|
||||||
|
commands.spawn(
|
||||||
|
(
|
||||||
|
Transform::default(),
|
||||||
|
octree
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_voxel_sphere(
|
||||||
|
octree: &mut SparseVoxelOctree,
|
||||||
|
planet_radius: i32,
|
||||||
|
voxel_color: Color,
|
||||||
|
) {
|
||||||
|
// For simplicity, we center the sphere around (0,0,0).
|
||||||
|
// We'll loop over a cubic region [-planet_radius, +planet_radius] in x, y, z
|
||||||
|
let min = -planet_radius;
|
||||||
|
let max = planet_radius;
|
||||||
|
|
||||||
|
let step = octree.get_spacing_at_depth(octree.max_depth);
|
||||||
|
|
||||||
|
for ix in min..=max {
|
||||||
|
let x = ix;
|
||||||
|
for iy in min..=max {
|
||||||
|
let y = iy;
|
||||||
|
for iz in min..=max {
|
||||||
|
let z = iz;
|
||||||
|
|
||||||
|
// Check if within sphere of radius `planet_radius`
|
||||||
|
let dist2 = x * x + y * y + z * z;
|
||||||
|
if dist2 <= planet_radius * planet_radius {
|
||||||
|
// Convert (x,y,z) to world space, stepping by `voxel_step`.
|
||||||
|
let wx = x as f32 * step;
|
||||||
|
let wy = y as f32 * step;
|
||||||
|
let wz = z as f32 * step;
|
||||||
|
let position = Vec3::new(wx, wy, wz);
|
||||||
|
|
||||||
|
// Insert the voxel
|
||||||
|
let voxel = Voxel {
|
||||||
|
color: voxel_color,
|
||||||
|
};
|
||||||
|
octree.insert(position, voxel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Inserts a 16x256x16 "column" of voxels into the octree at (0,0,0) corner.
|
||||||
|
/// If you want it offset or centered differently, just adjust the for-loop ranges or offsets.
|
||||||
|
fn generate_voxel_rect(
|
||||||
|
octree: &mut SparseVoxelOctree,
|
||||||
|
voxel_color: Color,
|
||||||
|
) {
|
||||||
|
// The dimensions of our rectangle: 16 x 256 x 16
|
||||||
|
let size_x = 16;
|
||||||
|
let size_y = 256;
|
||||||
|
let size_z = 16;
|
||||||
|
|
||||||
|
// We'll get the voxel spacing (size at the deepest level), same as in your sphere code.
|
||||||
|
let step = octree.get_spacing_at_depth(octree.max_depth);
|
||||||
|
|
||||||
|
// Triple-nested loop for each voxel in [0..16, 0..256, 0..16]
|
||||||
|
for ix in 0..size_x {
|
||||||
|
let x = ix as f32;
|
||||||
|
for iy in 0..size_y {
|
||||||
|
let y = iy as f32;
|
||||||
|
for iz in 0..size_z {
|
||||||
|
let z = iz as f32;
|
||||||
|
|
||||||
|
// Convert (x,y,z) to world coordinates
|
||||||
|
let wx = x * step;
|
||||||
|
let wy = y * step;
|
||||||
|
let wz = z * step;
|
||||||
|
|
||||||
|
let position = Vec3::new(wx, wy, wz);
|
||||||
|
|
||||||
|
// Insert the voxel
|
||||||
|
let voxel = Voxel {
|
||||||
|
color: voxel_color,
|
||||||
|
};
|
||||||
|
octree.insert(position, voxel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_large_plane(
|
||||||
|
octree: &mut SparseVoxelOctree,
|
||||||
|
width: usize,
|
||||||
|
depth: usize,
|
||||||
|
color: Color,
|
||||||
|
) {
|
||||||
|
// We'll get the voxel spacing (size at the deepest level).
|
||||||
|
let step = octree.get_spacing_at_depth(octree.max_depth);
|
||||||
|
|
||||||
|
// Double-nested loop for each voxel in [0..width, 0..depth],
|
||||||
|
// with y=0.
|
||||||
|
for ix in 0..width {
|
||||||
|
let x = ix as f32;
|
||||||
|
for iz in 0..depth {
|
||||||
|
let z = iz as f32;
|
||||||
|
// y is always 0.
|
||||||
|
let y = 0.0;
|
||||||
|
|
||||||
|
// Convert (x,0,z) to world coordinates
|
||||||
|
let wx = x * step;
|
||||||
|
let wy = y * step;
|
||||||
|
let wz = z * step;
|
||||||
|
|
||||||
|
let position = Vec3::new(wx, wy, wz);
|
||||||
|
|
||||||
|
// Insert the voxel
|
||||||
|
let voxel = Voxel {
|
||||||
|
color,
|
||||||
|
};
|
||||||
|
octree.insert(position, voxel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,7 +1,6 @@
|
|||||||
|
|
||||||
use bevy::app::{App, Plugin, PreUpdate, Startup};
|
use bevy::app::{App, Plugin, PreUpdate, Startup};
|
||||||
use bevy::prelude::{IntoSystemConfigs, Update};
|
use bevy::prelude::{IntoSystemConfigs, Update};
|
||||||
use crate::plugins::input::systems::console::{console_system, toggle_console, ConsoleState};
|
|
||||||
|
|
||||||
pub struct InputPlugin;
|
pub struct InputPlugin;
|
||||||
impl Plugin for InputPlugin {
|
impl Plugin for InputPlugin {
|
||||||
@ -9,17 +8,14 @@ impl Plugin for InputPlugin {
|
|||||||
_app.add_systems(
|
_app.add_systems(
|
||||||
Update,
|
Update,
|
||||||
(
|
(
|
||||||
crate::plugins::input::systems::console::console_system,
|
|
||||||
crate::plugins::input::systems::flight::flight_systems,
|
crate::plugins::input::systems::flight::flight_systems,
|
||||||
crate::plugins::input::systems::ui::ui_system,
|
crate::plugins::input::systems::ui::ui_system,
|
||||||
//crate::plugins::input::systems::network::network_system,
|
//crate::plugins::input::systems::network::network_system,
|
||||||
crate::plugins::input::systems::movement::movement_system,
|
crate::plugins::input::systems::movement::movement_system,
|
||||||
|
crate::plugins::input::systems::voxels::voxel_system
|
||||||
|
|
||||||
),
|
),
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
_app.insert_resource(ConsoleState::default());
|
|
||||||
_app.add_systems(Update, (toggle_console, console_system));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,60 +0,0 @@
|
|||||||
use bevy::app::AppExit;
|
|
||||||
use bevy::input::ButtonInput;
|
|
||||||
use bevy::input::mouse::{MouseMotion, MouseWheel};
|
|
||||||
use bevy::prelude::*;
|
|
||||||
use bevy_egui::{egui, EguiContexts};
|
|
||||||
use crate::plugins::environment::systems::camera_system::CameraController;
|
|
||||||
pub fn console_system(
|
|
||||||
mut ctxs: EguiContexts,
|
|
||||||
mut state: ResMut<ConsoleState>,
|
|
||||||
) {
|
|
||||||
if !state.open { return; }
|
|
||||||
|
|
||||||
egui::Window::new("Console")
|
|
||||||
.resizable(true)
|
|
||||||
.vscroll(true)
|
|
||||||
.show(ctxs.ctx_mut(), |ui| {
|
|
||||||
// Output
|
|
||||||
for line in &state.output {
|
|
||||||
ui.label(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Input line
|
|
||||||
let resp = ui.text_edit_singleline(&mut state.input);
|
|
||||||
if resp.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
|
|
||||||
let cmd = state.input.trim().to_string();
|
|
||||||
if !cmd.is_empty() {
|
|
||||||
state.history.push(cmd.clone());
|
|
||||||
handle_command(&cmd, &mut state.output);
|
|
||||||
state.input.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/// Press ` to open / close
|
|
||||||
pub fn toggle_console(
|
|
||||||
mut state: ResMut<ConsoleState>,
|
|
||||||
keys: Res<ButtonInput<KeyCode>>,
|
|
||||||
) {
|
|
||||||
if keys.just_pressed(KeyCode::KeyC) {
|
|
||||||
state.open = !state.open;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add your own commands here.
|
|
||||||
/// For demo purposes we just echo the input.
|
|
||||||
fn handle_command(cmd: &str, out: &mut Vec<String>) {
|
|
||||||
match cmd.trim() {
|
|
||||||
"help" => out.push("Available: help, clear, echo …".into()),
|
|
||||||
"clear" => out.clear(),
|
|
||||||
_ => out.push(format!("> {cmd}")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Resource, Default)]
|
|
||||||
pub struct ConsoleState {
|
|
||||||
pub open: bool,
|
|
||||||
pub input: String,
|
|
||||||
pub history: Vec<String>,
|
|
||||||
pub output: Vec<String>,
|
|
||||||
}
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
pub mod movement;
|
pub mod movement;
|
||||||
pub mod flight;
|
pub mod flight;
|
||||||
pub mod console;
|
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
|
pub mod voxels;
|
||||||
99
client/src/plugins/input/systems/voxels.rs
Normal file
99
client/src/plugins/input/systems/voxels.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use crate::plugins::environment::systems::camera_system::CameraController;
|
||||||
|
use crate::plugins::environment::systems::voxels::structure::*;
|
||||||
|
|
||||||
|
///TODO
|
||||||
|
pub fn voxel_system(
|
||||||
|
|
||||||
|
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||||
|
mouse_button_input: Res<ButtonInput<MouseButton>>,
|
||||||
|
mut octree_query: Query<&mut SparseVoxelOctree>,
|
||||||
|
|
||||||
|
mut query: Query<(&mut Transform, &mut CameraController)>,
|
||||||
|
mut windows: Query<&mut Window>,
|
||||||
|
) {
|
||||||
|
let mut window = windows.single_mut();
|
||||||
|
let (mut transform, _) = query.single_mut();
|
||||||
|
|
||||||
|
// =======================
|
||||||
|
// 5) Octree Keys
|
||||||
|
// =======================
|
||||||
|
if keyboard_input.just_pressed(KeyCode::F2){
|
||||||
|
for mut octree in octree_query.iter_mut() {
|
||||||
|
octree.show_wireframe = !octree.show_wireframe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if keyboard_input.just_pressed(KeyCode::F3){
|
||||||
|
for mut octree in octree_query.iter_mut() {
|
||||||
|
octree.show_world_grid = !octree.show_world_grid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if keyboard_input.just_pressed(KeyCode::F4){
|
||||||
|
for mut octree in octree_query.iter_mut() {
|
||||||
|
octree.show_chunks = !octree.show_chunks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if keyboard_input.just_pressed(KeyCode::KeyQ) && window.cursor_options.visible == false{
|
||||||
|
for mut octree in octree_query.iter_mut() {
|
||||||
|
octree.insert(transform.translation, Voxel::new(Color::srgb(1.0, 0.0, 0.0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =======================
|
||||||
|
// 6) Building
|
||||||
|
// =======================
|
||||||
|
|
||||||
|
if (mouse_button_input.just_pressed(MouseButton::Left) || mouse_button_input.just_pressed(MouseButton::Right)) && !window.cursor_options.visible {
|
||||||
|
|
||||||
|
// Get the mouse position in normalized device coordinates (-1 to 1)
|
||||||
|
if let Some(_) = window.cursor_position() {
|
||||||
|
// Set the ray direction to the camera's forward vector
|
||||||
|
let ray_origin = transform.translation;
|
||||||
|
let ray_direction = transform.forward().normalize();
|
||||||
|
|
||||||
|
let ray = Ray {
|
||||||
|
origin: ray_origin,
|
||||||
|
direction: ray_direction,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for mut octree in octree_query.iter_mut() {
|
||||||
|
if let Some((hit_x, hit_y, hit_z, depth,normal)) = octree.raycast(&ray) {
|
||||||
|
|
||||||
|
|
||||||
|
if mouse_button_input.just_pressed(MouseButton::Right) {
|
||||||
|
|
||||||
|
let voxel_size = octree.get_spacing_at_depth(depth);
|
||||||
|
let hit_position = Vec3::new(hit_x as f32, hit_y as f32, hit_z as f32);
|
||||||
|
let epsilon = voxel_size * 0.1; // Adjust this value as needed (e.g., 0.1 times the voxel size)
|
||||||
|
|
||||||
|
// Offset position by epsilon in the direction of the normal
|
||||||
|
let offset_position = hit_position - (normal * Vec3::new(epsilon as f32, epsilon as f32, epsilon as f32));
|
||||||
|
|
||||||
|
// Remove the voxel
|
||||||
|
octree.remove(offset_position);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else if mouse_button_input.just_pressed(MouseButton::Left) {
|
||||||
|
|
||||||
|
let voxel_size = octree.get_spacing_at_depth(depth);
|
||||||
|
let hit_position = Vec3::new(hit_x as f32, hit_y as f32, hit_z as f32);
|
||||||
|
let epsilon = voxel_size * 0.1; // Adjust this value as needed (e.g., 0.1 times the voxel size)
|
||||||
|
|
||||||
|
// Offset position by epsilon in the direction of the normal
|
||||||
|
let offset_position = hit_position + (normal * Vec3::new(epsilon as f32, epsilon as f32, epsilon as f32));
|
||||||
|
|
||||||
|
// Insert the new voxel
|
||||||
|
octree.insert(
|
||||||
|
offset_position,
|
||||||
|
Voxel::new(Color::srgb(1.0, 0.0, 0.0)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user