From c80e3eef8f5f8ca6ad542dcd67f89390872e7abb Mon Sep 17 00:00:00 2001 From: Oliver Dew Date: Fri, 19 Jan 2024 00:13:39 +0000 Subject: [PATCH] add modify voxels example --- assets/study.vox | Bin 1071035 -> 1071034 bytes examples/modify-voxels.rs | 156 ++++++++++++++--------------------- examples/voxel-collisions.rs | 146 ++++++++++++++++++++++++++++++++ 3 files changed, 210 insertions(+), 92 deletions(-) create mode 100644 examples/voxel-collisions.rs diff --git a/assets/study.vox b/assets/study.vox index 904a00e08ed972fe2b6aab8dd72ea8a1f5d1f116..d66faffbdbbfa00425cd1a58f93380d294c23659 100644 GIT binary patch delta 66187 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 delta 66189 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, -} +#[derive(Component)] +struct Floor; fn setup(mut commands: Commands, assets: Res) { commands.spawn(( @@ -40,7 +32,7 @@ fn setup(mut commands: Commands, assets: Res) { hdr: true, ..Default::default() }, - transform: Transform::from_xyz(15.0, 40.0, 90.0).looking_at(Vec3::ZERO, Vec3::Y), + transform: Transform::from_xyz(8.0, 1.5, 8.0).looking_at(Vec3::ZERO, Vec3::Y), tonemapping: Tonemapping::SomewhatBoringDisplayTransform, ..Default::default() }, @@ -54,93 +46,73 @@ fn setup(mut commands: Commands, assets: Res) { specular_map: assets.load("pisa_specular.ktx2"), }, )); - commands.insert_resource(Scenes { - snowflake: assets.load("study.vox#snowflake"), + + commands.spawn(DirectionalLightBundle { + directional_light: DirectionalLight { + illuminance: 10000.0, + shadows_enabled: true, + ..Default::default() + }, + transform: Transform::IDENTITY.looking_to(Vec3::new(1.0, -2.5, 0.85), Vec3::Y), + ..default() }); commands.spawn(VoxelSceneHookBundle { - // Load a slice of the scene - scene: assets.load("study.vox#workstation"), - hook: VoxelSceneHook::new(|entity, commands| { - if entity.get::().is_some() { - commands.insert(Scenery); + scene: assets.load("study.vox"), + hook: VoxelSceneHook::new(move |entity, commands| { + let Some(name) = entity.get::() else { return }; + if name.as_str() == "floor" { + commands.insert(Floor); } }), + transform: Transform::from_scale(Vec3::splat(0.05)), ..default() }); } -#[derive(Component)] -struct Snowflake(Quat); - -#[derive(Component)] -struct Scenery; - -fn spawn_snow(mut commands: Commands, scenes: Res) { - let mut rng = rand::thread_rng(); - let position = Vec3::new(rng.gen_range(-30.0..30.0), 80.0, rng.gen_range(-20.0..20.0)).round() - + Vec3::splat(0.5); - let rotation_axis = - Vec3::new(rng.gen_range(-0.5..0.5), 1.0, rng.gen_range(-0.5..0.5)).normalize(); - let angular_velocity = Quat::from_axis_angle(rotation_axis, 0.01); - commands.spawn(( - Snowflake(angular_velocity), - VoxelSceneBundle { - scene: scenes.snowflake.clone(), - transform: Transform::from_translation(position), - ..default() - }, - )); -} - -fn update_snow( - mut commands: Commands, - mut snowflakes: Query<(Entity, &Snowflake, &mut Transform), Without>, - scenery: Query<(&GlobalTransform, &VoxelModelInstance), (With, Without)>, - models: Res>, -) { - for (snowflake, snowflake_angular_vel, mut snowflake_xform) in snowflakes.iter_mut() { - let old_ypos = snowflake_xform.translation.y; - snowflake_xform.translation.y -= 0.1; - snowflake_xform.rotation *= snowflake_angular_vel.0; - // don't check collisions unless crossing boundary to next voxel - if old_ypos.trunc() == snowflake_xform.translation.y.trunc() { - continue; - } - for (item_xform, item_instance) in scenery.iter() { - let Some(model) = models.get(item_instance.0.id()) else { continue }; - let vox_pos = - model.global_point_to_voxel_space(snowflake_xform.translation, item_xform); - // check whether snowflake has landed on something solid - let pos_below_snowflake = vox_pos - IVec3::Y; - let Some(voxel) = model.get_voxel_at_point(pos_below_snowflake) else { continue }; - if voxel == Voxel::EMPTY { - continue; +fn grow_grass(mut commands: Commands, query: Query<&VoxelModelInstance, With>) { + // All the floor tiles are instances of the same model, so we only need one instance + let Some(instance) = query.iter().next() else { return }; + let region = BoxRegion { + origin: IVec3::new(0, 4, 0), + size: IVec3::new(64, 8, 64), + }; + commands.add(ModifyVoxelModel::new( + instance.0.id(), + VoxelRegion::Box(region), + |pos, voxel, model| { + if *voxel != Voxel::EMPTY { + return voxel.clone(); }; - let flake_radius = 2; - let radius_squared = flake_radius * flake_radius; - let flake_region = BoxRegion { - origin: vox_pos - IVec3::splat(flake_radius), - size: IVec3::splat(1 + (flake_radius * 2)), + let mut rng = rand::thread_rng(); + let value: u16 = rng.gen_range(0..5000); + if value > 20 { + return Voxel::EMPTY; }; - commands.add(ModifyVoxelModel::new( - item_instance.0.id(), - VoxelRegion::Box(flake_region), - move |pos, voxel, model| { - // a signed distance field for a sphere, but _only_ drawing it on empty cells directly above solid voxels - if *voxel == Voxel::EMPTY && pos.distance_squared(vox_pos) <= radius_squared { - if let Some(voxel_below) = model.get_voxel_at_point(pos - IVec3::Y) { - if voxel_below != Voxel::EMPTY { - // draw our snow material - return Voxel(234); - } - } + let vox_below = model + .get_voxel_at_point(pos - IVec3::Y) + .unwrap_or(Voxel::EMPTY); + let grass_voxels: RangeInclusive = 161..=165; + let grow_grass = grass_voxels.contains(&vox_below.0); + let mut plant_grass = !grow_grass && value < 5 && vox_below != Voxel::EMPTY; + if plant_grass { + // poisson disk effect: don't plant grass if too near other blades + 'check_neighbors: for direction in [IVec3::NEG_X, IVec3::X, IVec3::NEG_Z, IVec3::Z] + { + let neighbor = model + .get_voxel_at_point(pos + direction) + .unwrap_or(Voxel::EMPTY); + if grass_voxels.contains(&neighbor.0) { + plant_grass = false; + break 'check_neighbors; } - // else we return the underlying voxel, unmodified - voxel.clone() - }, - )); - commands.entity(snowflake).despawn(); - } - } + } + } + if plant_grass || grow_grass { + Voxel((161 + value % 5) as u8) + } else { + Voxel::EMPTY + } + }, + )); } diff --git a/examples/voxel-collisions.rs b/examples/voxel-collisions.rs new file mode 100644 index 0000000..47e40c7 --- /dev/null +++ b/examples/voxel-collisions.rs @@ -0,0 +1,146 @@ +use std::time::Duration; + +use bevy::{ + core_pipeline::{bloom::BloomSettings, tonemapping::Tonemapping}, + prelude::*, + time::common_conditions::on_timer, +}; +use bevy_panorbit_camera::{PanOrbitCamera, PanOrbitCameraPlugin}; +use bevy_vox_scene::{ + BoxRegion, ModifyVoxelModel, VoxScenePlugin, Voxel, VoxelModel, VoxelModelInstance, + VoxelQueryable, VoxelRegion, VoxelScene, VoxelSceneBundle, VoxelSceneHook, + VoxelSceneHookBundle, +}; +use rand::Rng; + +// When a snowflake lands on the scenery, it is added to scenery's voxel data, so that snow gradually builds up +fn main() { + // Making this frequency not cleanly divisible by the snowflake speed ensures that expensive collisions + // don't all happen on the same frame + let snow_spawn_freq = Duration::from_secs_f32(0.213); + App::new() + .add_plugins((DefaultPlugins, PanOrbitCameraPlugin, VoxScenePlugin)) + .add_systems(Startup, setup) + .add_systems( + Update, + (spawn_snow.run_if(on_timer(snow_spawn_freq)), update_snow), + ) + .run(); +} + +#[derive(Resource)] +struct Scenes { + snowflake: Handle, +} + +fn setup(mut commands: Commands, assets: Res) { + commands.spawn(( + Camera3dBundle { + camera: Camera { + hdr: true, + ..Default::default() + }, + transform: Transform::from_xyz(15.0, 40.0, 90.0).looking_at(Vec3::ZERO, Vec3::Y), + tonemapping: Tonemapping::SomewhatBoringDisplayTransform, + ..Default::default() + }, + PanOrbitCamera::default(), + BloomSettings { + intensity: 0.3, + ..default() + }, + EnvironmentMapLight { + diffuse_map: assets.load("pisa_diffuse.ktx2"), + specular_map: assets.load("pisa_specular.ktx2"), + }, + )); + commands.insert_resource(Scenes { + snowflake: assets.load("study.vox#snowflake"), + }); + + commands.spawn(VoxelSceneHookBundle { + // Load a slice of the scene + scene: assets.load("study.vox#workstation"), + hook: VoxelSceneHook::new(|entity, commands| { + if entity.get::().is_some() { + commands.insert(Scenery); + } + }), + ..default() + }); +} + +#[derive(Component)] +struct Snowflake(Quat); + +#[derive(Component)] +struct Scenery; + +fn spawn_snow(mut commands: Commands, scenes: Res) { + let mut rng = rand::thread_rng(); + let position = Vec3::new(rng.gen_range(-30.0..30.0), 80.0, rng.gen_range(-20.0..20.0)).round() + + Vec3::splat(0.5); + let rotation_axis = + Vec3::new(rng.gen_range(-0.5..0.5), 1.0, rng.gen_range(-0.5..0.5)).normalize(); + let angular_velocity = Quat::from_axis_angle(rotation_axis, 0.01); + commands.spawn(( + Snowflake(angular_velocity), + VoxelSceneBundle { + scene: scenes.snowflake.clone(), + transform: Transform::from_translation(position), + ..default() + }, + )); +} + +fn update_snow( + mut commands: Commands, + mut snowflakes: Query<(Entity, &Snowflake, &mut Transform), Without>, + scenery: Query<(&GlobalTransform, &VoxelModelInstance), (With, Without)>, + models: Res>, +) { + for (snowflake, snowflake_angular_vel, mut snowflake_xform) in snowflakes.iter_mut() { + let old_ypos = snowflake_xform.translation.y; + snowflake_xform.translation.y -= 0.1; + snowflake_xform.rotation *= snowflake_angular_vel.0; + // don't check collisions unless crossing boundary to next voxel + if old_ypos.trunc() == snowflake_xform.translation.y.trunc() { + continue; + } + for (item_xform, item_instance) in scenery.iter() { + let Some(model) = models.get(item_instance.0.id()) else { continue }; + let vox_pos = + model.global_point_to_voxel_space(snowflake_xform.translation, item_xform); + // check whether snowflake has landed on something solid + let pos_below_snowflake = vox_pos - IVec3::Y; + let Some(voxel) = model.get_voxel_at_point(pos_below_snowflake) else { continue }; + if voxel == Voxel::EMPTY { + continue; + }; + let flake_radius = 2; + let radius_squared = flake_radius * flake_radius; + let flake_region = BoxRegion { + origin: vox_pos - IVec3::splat(flake_radius), + size: IVec3::splat(1 + (flake_radius * 2)), + }; + commands.add(ModifyVoxelModel::new( + item_instance.0.id(), + VoxelRegion::Box(flake_region), + move |pos, voxel, model| { + // a signed distance field for a sphere, but _only_ drawing it on empty cells directly above solid voxels + if *voxel == Voxel::EMPTY && pos.distance_squared(vox_pos) <= radius_squared { + if let Some(voxel_below) = model.get_voxel_at_point(pos - IVec3::Y) { + if voxel_below != Voxel::EMPTY { + // draw our snow material + return Voxel(234); + } + } + } + // else we return the underlying voxel, unmodified + voxel.clone() + }, + )); + commands.entity(snowflake).despawn(); + } + } +}