Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/deprecate voxelscene #10

Merged
merged 12 commits into from
Aug 24, 2024
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ bevy_vox_scene = "0.14.0"

```rust no_run
use bevy::prelude::*;
use bevy_vox_scene::{VoxScenePlugin, VoxelSceneBundle}; // 2.
use bevy_vox_scene::VoxScenePlugin; // 2.

fn main() {
App::new()
Expand All @@ -54,7 +54,7 @@ fn main() {
}

fn setup(mut commands: Commands, assets: Res<AssetServer>) {
commands.spawn(VoxelSceneBundle { // 4.
commands.spawn(SceneBundle { // 4.
scene: assets.load("study.vox#workstation/desk"),
..default()
});
Expand All @@ -63,7 +63,7 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>) {

2. Import the library.
3. Add the plugin to the app.
4. Spawn a scene graph using `VoxelSceneBundle`. Alternatively, spawn any node of the scene graph, down to individual models, using the name you assigned to the node in MagicaVoxel.
4. Spawn a scene graph using `SceneBundle`. Alternatively, spawn any node of the scene graph, down to individual models, using the name you assigned to the node in MagicaVoxel.

Take a look in the `examples/` directory for complete working examples. To run an example, type the following into the terminal:
```ignore
Expand Down
4 changes: 2 additions & 2 deletions examples/basic-model.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use bevy::prelude::*;
use bevy_vox_scene::{VoxScenePlugin, VoxelSceneBundle};
use bevy_vox_scene::VoxScenePlugin;

fn main() {
App::new()
Expand All @@ -21,7 +21,7 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>) {
},
));

commands.spawn(VoxelSceneBundle {
commands.spawn(SceneBundle {
// Load a single model using the name assigned to it in MagicaVoxel
// If a model is nested in a named group, than the group will form part of the path
// Path components are separated with a slash
Expand Down
4 changes: 2 additions & 2 deletions examples/emissive-model.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use bevy::{core_pipeline::bloom::BloomSettings, prelude::*};
use bevy_vox_scene::{VoxScenePlugin, VoxelSceneBundle};
use bevy_vox_scene::VoxScenePlugin;
use utilities::{PanOrbitCamera, PanOrbitCameraPlugin};

fn main() {
Expand Down Expand Up @@ -36,7 +36,7 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>) {
},
));

commands.spawn(VoxelSceneBundle {
commands.spawn(SceneBundle {
// Load a single model using the name assigned to it in MagicaVoxel
scene: assets.load("study.vox#workstation/computer"),
..default()
Expand Down
18 changes: 7 additions & 11 deletions examples/modify-scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ use bevy::{
input::keyboard::KeyboardInput,
prelude::*,
};
use bevy_vox_scene::{VoxScenePlugin, VoxelModelInstance, VoxelSceneBundle};
use bevy_vox_scene::VoxScenePlugin;
use rand::Rng;
use std::f32::consts::PI;
use utilities::{PanOrbitCamera, PanOrbitCameraPlugin};

/// Uses the [`bevy_vox_scene::VoxelSceneHook`] component to add extra components into the scene graph.
/// Uses an observer triggered by `VoxelModelInstance` being added to add extra components into the scene graph.
/// Press any key to toggle the fish tank black-light on and off
fn main() {
let mut app = App::new();
Expand Down Expand Up @@ -73,7 +73,7 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>) {
intensity: 500.0,
},
));
commands.spawn(VoxelSceneBundle {
commands.spawn(SceneBundle {
// "tank" is the name of the group containing the glass walls, the body of water, the scenery in the tank and the fish
scene: assets.load("study.vox#tank"),
transform: Transform::from_scale(Vec3::splat(0.05)),
Expand All @@ -82,19 +82,15 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>) {
commands.observe(on_spawn_voxel_instance);
}

// Will run against every child entity that gets spawned in the scene
// Will run against every named child entity that gets spawned in the scene
fn on_spawn_voxel_instance(
trigger: Trigger<OnAdd, VoxelModelInstance>,
model_query: Query<&VoxelModelInstance>,
trigger: Trigger<OnAdd, Name>,
model_query: Query<&Name>,
mut commands: Commands,
assets: Res<AssetServer>,
) {
let mut entity_commands = commands.entity(trigger.entity());
let name = model_query
.get(trigger.entity())
.unwrap()
.model_name
.as_str();
let name = model_query.get(trigger.entity()).unwrap().as_str();
match name {
"tank/black-light" => {
entity_commands.insert(EmissiveToggle {
Expand Down
39 changes: 20 additions & 19 deletions examples/modify-voxels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ use bevy::{
time::common_conditions::on_timer,
};
use bevy_vox_scene::{
ModifyVoxelCommandsExt, VoxScenePlugin, Voxel, VoxelModelInstance, VoxelRegion,
VoxelRegionMode, VoxelSceneBundle,
ModifyVoxelCommandsExt, VoxScenePlugin, Voxel, VoxelModelInstance, VoxelRegion, VoxelRegionMode,
};
use rand::Rng;
use std::{ops::RangeInclusive, time::Duration};
Expand All @@ -30,6 +29,7 @@ fn main() {
struct Floor;

fn setup(mut commands: Commands, assets: Res<AssetServer>) {
commands.observe(on_spawn_voxel_instance);
commands.spawn((
Camera3dBundle {
camera: Camera {
Expand All @@ -50,36 +50,37 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>) {
specular_map: assets.load("pisa_specular.ktx2"),
intensity: 500.0,
},
Name::new("camera"),
));

commands.spawn(DirectionalLightBundle {
directional_light: DirectionalLight {
illuminance: 5000.0,
shadows_enabled: true,
..Default::default()
commands.spawn((
DirectionalLightBundle {
directional_light: DirectionalLight {
illuminance: 5000.0,
shadows_enabled: true,
..Default::default()
},
transform: Transform::IDENTITY.looking_to(Vec3::new(1.0, -2.5, 0.85), Vec3::Y),
..default()
},
transform: Transform::IDENTITY.looking_to(Vec3::new(1.0, -2.5, 0.85), Vec3::Y),
..default()
});
Name::new("light"),
));

commands.spawn(VoxelSceneBundle {
commands.spawn(SceneBundle {
scene: assets.load("study.vox"),
transform: Transform::from_scale(Vec3::splat(0.05)),
..default()
});
commands.observe(on_spawn_voxel_instance);
}

fn on_spawn_voxel_instance(
trigger: Trigger<OnAdd, VoxelModelInstance>,
model_query: Query<&VoxelModelInstance>,
trigger: Trigger<OnAdd, Name>,
model_query: Query<&Name>,
mut commands: Commands,
) {
let name = model_query
.get(trigger.entity())
.unwrap()
.model_name
.as_str();
let Ok(name) = model_query.get(trigger.entity()).map(|n| n.as_str()) else {
return;
};
if name == "floor" {
commands.entity(trigger.entity()).insert(Floor);
}
Expand Down
4 changes: 2 additions & 2 deletions examples/scene-slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use bevy::{
},
prelude::*,
};
use bevy_vox_scene::{VoxScenePlugin, VoxelSceneBundle};
use bevy_vox_scene::VoxScenePlugin;
use utilities::{PanOrbitCamera, PanOrbitCameraPlugin};

/// Asset labels aren't just for loading individual models within a scene, they can load any named group within a scene, a "slice" of the scene
Expand Down Expand Up @@ -62,7 +62,7 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>) {
},
));

commands.spawn(VoxelSceneBundle {
commands.spawn(SceneBundle {
// "workstation" is the name of the group containing the desk, computer, & keyboard
scene: assets.load("study.vox#workstation"),
transform: Transform::from_scale(Vec3::splat(0.05)),
Expand Down
4 changes: 2 additions & 2 deletions examples/ssao-model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use bevy::{
pbr::ScreenSpaceAmbientOcclusionBundle,
prelude::*,
};
use bevy_vox_scene::{VoxScenePlugin, VoxelSceneBundle};
use bevy_vox_scene::VoxScenePlugin;
use utilities::{PanOrbitCamera, PanOrbitCameraPlugin};

/// Press any key to toggle Screen Space Ambient Occlusion
Expand Down Expand Up @@ -66,7 +66,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
))
.insert(ScreenSpaceAmbientOcclusionBundle::default());

commands.spawn(VoxelSceneBundle {
commands.spawn(SceneBundle {
// Load a model nested inside a group by using a `/` to separate the path components
scene: asset_server.load("study.vox#tank/goldfish"),
..default()
Expand Down
7 changes: 3 additions & 4 deletions examples/transmission-scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use bevy::{
pbr::{VolumetricFogSettings, VolumetricLight},
prelude::*,
};
use bevy_vox_scene::{VoxLoaderSettings, VoxScenePlugin, VoxelSceneBundle};
use bevy_vox_scene::{VoxLoaderSettings, VoxScenePlugin};
use utilities::{PanOrbitCamera, PanOrbitCameraPlugin};

fn main() {
Expand All @@ -19,7 +19,7 @@ fn main() {
PanOrbitCameraPlugin,
VoxScenePlugin {
global_settings: Some(VoxLoaderSettings {
voxel_size: 0.5,
voxel_size: 0.05,
..default()
}),
},
Expand Down Expand Up @@ -80,9 +80,8 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>) {
VolumetricLight,
));

commands.spawn(VoxelSceneBundle {
commands.spawn(SceneBundle {
scene: assets.load("study.vox"),
transform: Transform::from_scale(Vec3::splat(0.05)),
..default()
});
}
57 changes: 26 additions & 31 deletions examples/voxel-collisions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use bevy::{
time::common_conditions::on_timer,
};
use bevy_vox_scene::{
DidSpawnVoxelChild, ModifyVoxelCommandsExt, VoxScenePlugin, Voxel, VoxelModelCollection,
VoxelModelInstance, VoxelQueryable, VoxelRegion, VoxelRegionMode, VoxelScene, VoxelSceneBundle,
ModifyVoxelCommandsExt, VoxScenePlugin, Voxel, VoxelModel, VoxelModelInstance, VoxelQueryable,
VoxelRegion, VoxelRegionMode,
};
use rand::Rng;
use utilities::{PanOrbitCamera, PanOrbitCameraPlugin};
Expand Down Expand Up @@ -51,22 +51,19 @@ fn main() {

#[derive(Resource)]
struct Scenes {
snowflake: Handle<VoxelScene>,
snowflake: Handle<Mesh>,
voxel_material: Handle<StandardMaterial>,
}

/// The [`DidSpawnVoxelChild`] event is targeted at the root of a specific [`VoxelScene`], and triggers
/// once for each child [`VoxelModelInstance`] that gets spawned in that node graph.
/// This is useful when we will be spawning other voxel scenes, so that we can scope the observer
/// to one scene and not worry about adding in defensive code.
/// The event also includes the [`model_name`] and [`layer_name`] so you need fewer queries in your observer.
/// Compare with the observer triggered with [`Trigger<OnAdd, VoxelModelInstance>`] in [modify scene](./modify-scene.rs).
fn on_spawn_voxel_instance(trigger: Trigger<DidSpawnVoxelChild>, mut commands: Commands) {
// Note that we're interested in the child entity, which is `trigger.event().child`
// Not the root entity, which is `trigger.entity()`
let mut entity_commands = commands.entity(trigger.event().child);
let name = trigger.event().model_name.as_str();
fn on_spawn_voxel_instance(
trigger: Trigger<OnAdd, Name>,
query: Query<&Name>,
mut commands: Commands,
) {
let mut entity_commands = commands.entity(trigger.entity());
let name = query.get(trigger.entity()).map_or("", |n| n.as_str());
match name {
"snowflake" => panic!("This should never be executed, because this observer is scoped to the 'workstation' scene graph"),
"snowflake" => return,
"workstation/computer" => {
// Focus on the computer screen by suppling the local voxel coordinates of the center of the screen
entity_commands.insert(FocalPoint(Vec3::new(0., 0., 9.)));
Expand Down Expand Up @@ -112,17 +109,16 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>) {
},
));
commands.insert_resource(Scenes {
snowflake: assets.load("study.vox#snowflake"),
snowflake: assets.load("study.vox#snowflake@mesh"),
voxel_material: assets.load("study.vox#snowflake@material"),
});

// NB the `on_spawn_voxel_instance` observer is scoped to just this scene graph: we don't want it firing when snowflakes are spawned later on.
commands
.spawn(VoxelSceneBundle {
// Load a slice of the scene
scene: assets.load("study.vox#workstation"),
..default()
})
.observe(on_spawn_voxel_instance);
commands.spawn(SceneBundle {
// Load a slice of the scene
scene: assets.load("study.vox#workstation"),
..default()
});
commands.observe(on_spawn_voxel_instance);
}

#[derive(Component)]
Expand All @@ -142,9 +138,11 @@ fn spawn_snow(mut commands: Commands, scenes: Res<Scenes>) {
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((
Name::new("snowflake"),
Snowflake(angular_velocity),
VoxelSceneBundle {
scene: scenes.snowflake.clone(),
PbrBundle {
mesh: scenes.snowflake.clone(),
material: scenes.voxel_material.clone(),
transform: Transform::from_translation(position),
..default()
},
Expand All @@ -155,7 +153,7 @@ fn update_snow(
mut commands: Commands,
mut snowflakes: Query<(Entity, &Snowflake, &mut Transform), Without<Scenery>>,
scenery: Query<(&GlobalTransform, &VoxelModelInstance), (With<Scenery>, Without<Snowflake>)>,
model_collections: Res<Assets<VoxelModelCollection>>,
models: Res<Assets<VoxelModel>>,
) {
for (snowflake, snowflake_angular_vel, mut snowflake_xform) in snowflakes.iter_mut() {
let old_ypos = snowflake_xform.translation.y;
Expand All @@ -166,10 +164,7 @@ fn update_snow(
continue;
}
for (item_xform, item_instance) in scenery.iter() {
let Some(collection) = model_collections.get(item_instance.collection.id()) else {
continue;
};
let Some(model) = collection.model(&item_instance.model_name) else {
let Some(model) = models.get(&item_instance.model) else {
continue;
};
let vox_pos =
Expand Down
14 changes: 6 additions & 8 deletions examples/voxel-generation.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use bevy::{core_pipeline::bloom::BloomSettings, prelude::*};
use bevy_vox_scene::{
VoxScenePlugin, Voxel, VoxelModelCollection, VoxelModelInstance, VoxelPalette, SDF,
VoxScenePlugin, Voxel, VoxelContext, VoxelModel, VoxelModelInstance, VoxelPalette, SDF,
};
use utilities::{PanOrbitCamera, PanOrbitCameraPlugin};

Expand Down Expand Up @@ -52,12 +52,10 @@ fn setup(world: &mut World) {
x if x >= 0.0 => Voxel::EMPTY,
_ => Voxel::EMPTY,
});
let Some(collection) = VoxelModelCollection::new(world, palette) else {
return;
};
let context = VoxelContext::new(world, palette);
let model_name = "my sdf model";
let Some(model) =
VoxelModelCollection::add(world, data, model_name.to_string(), collection.clone())
let Some((model_handle, model)) =
VoxelModel::new(world, data, model_name.to_string(), context.clone())
else {
return;
};
Expand All @@ -69,8 +67,8 @@ fn setup(world: &mut World) {
},
// The [`VoxelModelInstance`] component is only needed if you want to be able to modify the model at a later time:
VoxelModelInstance {
collection,
model_name: model_name.to_string(),
model: model_handle,
context,
},
));
}
Loading
Loading