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

Voxel generation #6

Merged
merged 22 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ jobs:
steps:
- name: Checkout sources
uses: actions/checkout@v4

- name: Cache
id: cache
uses: actions/cache@v3
with:
path: |
Expand All @@ -28,10 +30,28 @@ jobs:
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.toml') }}
key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.lock') }}

- name: Install stable toolchain
uses: dtolnay/rust-toolchain@stable

- name: Install Dependencies
run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev
- name: Run cargo test
run: cargo test --lib --verbose

- name: Install cargo-tarpaulin
if: steps.cache.outputs.cache-hit != 'true'
run: cargo install cargo-tarpaulin

- name: Run tests
run: cargo tarpaulin --ignore-tests --out Xml

- name: Upload to codecov.io
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

- name: Archive code coverage results
uses: actions/upload-artifact@v1
with:
name: code-coverage-report
path: cobertura.xml
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description = "A Bevy engine plugin for loading Magica Voxel world files and ren
keywords = ["bevy", "voxel", "Magica-Voxel"]
categories = ["game-development", "graphics", "rendering", "rendering::data-formats"]
license = "MIT"
version = "0.11.5"
version = "0.12.0"
repository = "https://github.com/Utsira/bevy_vox_scene"
authors = ["Oliver Dew <[email protected]>"]
edition = "2021"
Expand All @@ -14,8 +14,9 @@ exclude = ["assets/*"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
default = ["modify_voxels"]
default = ["modify_voxels", "generate_voxels"]
modify_voxels = []
generate_voxels = []

[[example]]
name = "modify-voxels"
Expand All @@ -25,6 +26,10 @@ required-features = ["modify_voxels"]
name = "voxel-collisions"
required-features = ["modify_voxels"]

[[example]]
name = "voxel-generation"
required-features = ["generate_voxels"]

[dependencies]
bevy = { version = "0.12.0", default-features = false, features = [
"bevy_render",
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
[![CI](https://github.com/Utsira/bevy_vox_scene/actions/workflows/ci.yml/badge.svg)](https://github.com/Utsira/bevy_vox_scene/actions/workflows/ci.yml)
[![dependency status](https://deps.rs/crate/bevy_vox_scene/0.11.0/status.svg)](https://deps.rs/crate/bevy_vox_scene/0.11.0)
[![Bevy tracking](https://img.shields.io/badge/Bevy%20tracking-released%20version-lightblue)](https://bevyengine.org/learn/book/plugin-development/#main-branch-tracking)
[![codecov](https://codecov.io/gh/Utsira/bevy_vox_scene/graph/badge.svg?token=29AR6PVOYP)](https://codecov.io/gh/Utsira/bevy_vox_scene)

A plugin for [the Bevy Engine](https://bevyengine.org) which allows loading [Magica Voxel](https://ephtracy.github.io) `.vox` files directly into a Bevy scene graph.
`bevy_vox_scene` is forked from the excellent [`bevy_vox_mesh` crate](https://crates.io/crates/bevy_vox_mesh).
Expand All @@ -33,7 +34,7 @@ All Magica Voxel material types except "cloud" are supported. Bevy's screen spac

```toml
[dependencies]
bevy_vox_scene = "0.11.4"
bevy_vox_scene = "0.12.0"
```

Then in code:
Expand Down Expand Up @@ -75,7 +76,7 @@ cargo run --example <example name>

| Bevy version | Magica Voxel version | `bevy-vox-scene` version |
| ------------ | -------------- | --- |
| 0.12 | 0.99.6 | 0.9, 0.10, 0.11 |
| 0.12 | 0.99.6 | 0.9, 0.10, 0.11, 0.12 |

## Limitations and workarounds

Expand Down
2 changes: 1 addition & 1 deletion examples/modify-voxels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ fn grow_grass(mut commands: Commands, query: Query<&VoxelModelInstance, With<Flo
size: IVec3::new(64, 8, 64),
};
commands.modify_voxel_model(
instance.0.id(),
instance.clone(),
VoxelRegionMode::Box(region),
|pos, voxel, model| {
if *voxel != Voxel::EMPTY {
Expand Down
11 changes: 6 additions & 5 deletions examples/voxel-collisions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use bevy::{
};
use bevy_panorbit_camera::{PanOrbitCamera, PanOrbitCameraPlugin};
use bevy_vox_scene::{
ModifyVoxelCommandsExt, VoxScenePlugin, Voxel, VoxelModel, VoxelModelInstance, VoxelQueryable,
VoxelRegion, VoxelRegionMode, VoxelScene, VoxelSceneBundle, VoxelSceneHook,
ModifyVoxelCommandsExt, VoxScenePlugin, Voxel, VoxelModelCollection, VoxelModelInstance,
VoxelQueryable, VoxelRegion, VoxelRegionMode, VoxelScene, VoxelSceneBundle, VoxelSceneHook,
VoxelSceneHookBundle,
};
use rand::Rng;
Expand Down Expand Up @@ -97,7 +97,7 @@ fn update_snow(
mut commands: Commands,
mut snowflakes: Query<(Entity, &Snowflake, &mut Transform), Without<Scenery>>,
scenery: Query<(&GlobalTransform, &VoxelModelInstance), (With<Scenery>, Without<Snowflake>)>,
models: Res<Assets<VoxelModel>>,
model_collections: Res<Assets<VoxelModelCollection>>,
) {
for (snowflake, snowflake_angular_vel, mut snowflake_xform) in snowflakes.iter_mut() {
let old_ypos = snowflake_xform.translation.y;
Expand All @@ -108,7 +108,8 @@ fn update_snow(
continue;
}
for (item_xform, item_instance) in scenery.iter() {
let Some(model) = models.get(item_instance.0.id()) else { continue };
let Some(collection) = model_collections.get(item_instance.collection.id()) else { continue };
let Some(model) = collection.model(&item_instance.model_name) else { continue };
let vox_pos =
model.global_point_to_voxel_space(snowflake_xform.translation, item_xform);
// check whether snowflake has landed on something solid
Expand All @@ -124,7 +125,7 @@ fn update_snow(
size: IVec3::splat(1 + (flake_radius * 2)),
};
commands.modify_voxel_model(
item_instance.0.id(),
item_instance.clone(),
VoxelRegionMode::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
Expand Down
62 changes: 62 additions & 0 deletions examples/voxel-generation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use bevy::{core_pipeline::bloom::BloomSettings, prelude::*};
use bevy_panorbit_camera::{PanOrbitCamera, PanOrbitCameraPlugin};
use bevy_vox_scene::{
VoxScenePlugin, Voxel, VoxelModelCollection, VoxelModelInstance, VoxelPalette, SDF,
};

fn main() {
App::new()
.add_plugins((DefaultPlugins, PanOrbitCameraPlugin, VoxScenePlugin))
.add_systems(Startup, (setup_camera, setup))
.run();
}

fn setup_camera(mut commands: Commands, assets: Res<AssetServer>) {
commands.spawn((
Camera3dBundle {
camera: Camera {
hdr: true,
..Default::default()
},
transform: Transform::from_xyz(-20.0, 10.0, 60.0).looking_at(Vec3::ZERO, Vec3::Y),
..Default::default()
},
PanOrbitCamera::default(),
BloomSettings {
intensity: 0.3,
..default()
},
EnvironmentMapLight {
diffuse_map: assets.load("pisa_diffuse.ktx2"),
specular_map: assets.load("pisa_specular.ktx2"),
},
));
}

fn setup(world: &mut World) {
let palette =
VoxelPalette::new_from_colors(vec![Color::BLUE, Color::ALICE_BLUE, Color::BISQUE]);

let data = SDF::cuboid(Vec3::splat(13.0))
.subtract(SDF::sphere(16.0))
.map_to_voxels(UVec3::splat(32), |d| match d {
x if x < -1.0 => Voxel(2),
x if x < 0.0 => Voxel(1),
x if x >= 0.0 => Voxel::EMPTY,
_ => Voxel::EMPTY,
});
let Some((mut collection, collection_handle)) = VoxelModelCollection::new(world, palette) else { return };
let model_name = "my sdf model";
let Some(model) = collection.add(data, "my sdf model", world) else { return };
world.spawn((
PbrBundle {
mesh: model.mesh,
material: model.material,
..default()
},
VoxelModelInstance {
collection: collection_handle,
model_name: model_name.to_string(),
},
));
}
8 changes: 6 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ pub use model::{
modify::{ModifyVoxelCommandsExt, VoxelRegion, VoxelRegionMode},
queryable::VoxelQueryable,
};
pub use model::{Voxel, VoxelData, VoxelModel};
#[cfg(feature = "generate_voxels")]
pub use model::sdf::SDF;
pub use model::{
Voxel, VoxelData, VoxelElement, VoxelModel, VoxelModelCollection, VoxelPalette,
};
pub use scene::{
VoxelLayer, VoxelModelInstance, VoxelScene, VoxelSceneBundle, VoxelSceneHook,
VoxelSceneHookBundle,
Expand All @@ -81,7 +85,7 @@ pub struct VoxScenePlugin;
impl Plugin for VoxScenePlugin {
fn build(&self, app: &mut App) {
app.init_asset::<VoxelScene>()
.init_asset::<VoxelModel>()
.init_asset::<VoxelModelCollection>()
.register_asset_loader(VoxSceneLoader)
.add_systems(
SpawnScene,
Expand Down
Loading
Loading