Skip to content

Commit

Permalink
Merge branch 'feature/set-voxel-size'
Browse files Browse the repository at this point in the history
  • Loading branch information
Utsira committed Aug 6, 2024
2 parents 6285421 + 178a3c6 commit 88b09fb
Show file tree
Hide file tree
Showing 19 changed files with 185 additions and 97 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ use bevy_vox_scene::{VoxScenePlugin, VoxelSceneBundle}; // 2.

fn main() {
App::new()
.add_plugins((DefaultPlugins, VoxScenePlugin)) // 3.
.add_plugins((
DefaultPlugins,
VoxScenePlugin::default()
)) // 3.
.add_systems(Startup, setup)
.run();
}
Expand Down
2 changes: 1 addition & 1 deletion examples/basic-model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use bevy_vox_scene::{VoxScenePlugin, VoxelSceneBundle};

fn main() {
App::new()
.add_plugins((DefaultPlugins, VoxScenePlugin))
.add_plugins((DefaultPlugins, VoxScenePlugin::default()))
.add_systems(Startup, setup)
.run();
}
Expand Down
6 changes: 5 additions & 1 deletion examples/emissive-model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ use utilities::{PanOrbitCamera, PanOrbitCameraPlugin};

fn main() {
App::new()
.add_plugins((DefaultPlugins, PanOrbitCameraPlugin, VoxScenePlugin))
.add_plugins((
DefaultPlugins,
PanOrbitCameraPlugin,
VoxScenePlugin::default(),
))
.add_systems(Startup, setup)
.run();
}
Expand Down
22 changes: 13 additions & 9 deletions examples/modify-scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@ use utilities::{PanOrbitCamera, PanOrbitCameraPlugin};
fn main() {
let mut app = App::new();

app.add_plugins((DefaultPlugins, PanOrbitCameraPlugin, VoxScenePlugin))
.add_systems(Startup, setup)
.add_systems(
Update,
(
toggle_black_light.run_if(on_event::<KeyboardInput>()),
swim_fish,
),
);
app.add_plugins((
DefaultPlugins,
PanOrbitCameraPlugin,
VoxScenePlugin::default(),
))
.add_systems(Startup, setup)
.add_systems(
Update,
(
toggle_black_light.run_if(on_event::<KeyboardInput>()),
swim_fish,
),
);

// *Note:* TAA is not _required_ for specular transmission, but
// it _greatly enhances_ the look of the resulting blur effects.
Expand Down
6 changes: 5 additions & 1 deletion examples/modify-voxels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ use utilities::{PanOrbitCamera, PanOrbitCameraPlugin};

fn main() {
App::new()
.add_plugins((DefaultPlugins, PanOrbitCameraPlugin, VoxScenePlugin))
.add_plugins((
DefaultPlugins,
PanOrbitCameraPlugin,
VoxScenePlugin::default(),
))
.add_systems(Startup, setup)
.add_systems(
Update,
Expand Down
8 changes: 6 additions & 2 deletions examples/scene-slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ use utilities::{PanOrbitCamera, PanOrbitCameraPlugin};
fn main() {
let mut app = App::new();

app.add_plugins((DefaultPlugins, PanOrbitCameraPlugin, VoxScenePlugin))
.add_systems(Startup, setup);
app.add_plugins((
DefaultPlugins,
PanOrbitCameraPlugin,
VoxScenePlugin::default(),
))
.add_systems(Startup, setup);

// *Note:* TAA is not _required_ for specular transmission, but
// it _greatly enhances_ the look of the resulting blur effects.
Expand Down
18 changes: 11 additions & 7 deletions examples/ssao-model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,17 @@ use utilities::{PanOrbitCamera, PanOrbitCameraPlugin};
fn main() {
let mut app = App::new();

app.add_plugins((DefaultPlugins, PanOrbitCameraPlugin, VoxScenePlugin))
.insert_resource(AmbientLight {
color: Color::srgb_u8(128, 126, 124),
brightness: 0.5,
})
.add_systems(Startup, setup)
.add_systems(Update, toggle_ssao.run_if(on_event::<KeyboardInput>()));
app.add_plugins((
DefaultPlugins,
PanOrbitCameraPlugin,
VoxScenePlugin::default(),
))
.insert_resource(AmbientLight {
color: Color::srgb_u8(128, 126, 124),
brightness: 0.5,
})
.add_systems(Startup, setup)
.add_systems(Update, toggle_ssao.run_if(on_event::<KeyboardInput>()));

// *Note:* TAA is not _required_ for SSAO, but
// it enhances the look of the resulting blur effects.
Expand Down
15 changes: 12 additions & 3 deletions examples/transmission-scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,23 @@ use bevy::{
pbr::{VolumetricFogSettings, VolumetricLight},
prelude::*,
};
use bevy_vox_scene::{VoxScenePlugin, VoxelSceneBundle};
use bevy_vox_scene::{VoxLoaderSettings, VoxScenePlugin, VoxelSceneBundle};
use utilities::{PanOrbitCamera, PanOrbitCameraPlugin};

fn main() {
let mut app = App::new();

app.add_plugins((DefaultPlugins, PanOrbitCameraPlugin, VoxScenePlugin))
.add_systems(Startup, setup);
app.add_plugins((
DefaultPlugins,
PanOrbitCameraPlugin,
VoxScenePlugin {
global_settings: Some(VoxLoaderSettings {
voxel_size: 0.5,
..default()
}),
},
))
.add_systems(Startup, setup);

// *Note:* TAA is not _required_ for specular transmission, but
// it _greatly enhances_ the look of the resulting blur effects.
Expand Down
6 changes: 5 additions & 1 deletion examples/voxel-collisions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ fn main() {
// 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_plugins((
DefaultPlugins,
PanOrbitCameraPlugin,
VoxScenePlugin::default(),
))
.add_systems(Startup, setup)
.add_systems(
Update,
Expand Down
8 changes: 6 additions & 2 deletions examples/voxel-generation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ use utilities::{PanOrbitCamera, PanOrbitCameraPlugin};

fn main() {
App::new()
.add_plugins((DefaultPlugins, PanOrbitCameraPlugin, VoxScenePlugin))
.add_plugins((
DefaultPlugins,
PanOrbitCameraPlugin,
VoxScenePlugin::default(),
))
.add_systems(Startup, (setup_camera, setup))
.run();
}
Expand Down Expand Up @@ -42,7 +46,7 @@ fn setup(world: &mut World) {
]);
let data = SDF::cuboid(Vec3::splat(13.0))
.subtract(SDF::sphere(16.0))
.map_to_voxels(UVec3::splat(32), |d, _| match d {
.map_to_voxels(UVec3::splat(32), 1.0, |d, _| match d {
x if x < -1.0 => Voxel(2),
x if x < 0.0 => Voxel(1),
x if x >= 0.0 => Voxel::EMPTY,
Expand Down
14 changes: 11 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! App::new()
//! .add_plugins((
//! DefaultPlugins,
//! VoxScenePlugin,
//! VoxScenePlugin::default(),
//! ))
//! .add_systems(Startup, setup)
//! # .add_systems(Update, assert_scene_loaded)
Expand Down Expand Up @@ -74,13 +74,21 @@ pub use scene::{DidSpawnVoxelChild, VoxelLayer, VoxelModelInstance, VoxelScene,
/// Plugin adding functionality for loading `.vox` files.
///
/// Registers an [`bevy::asset::AssetLoader`] capable of loading `.vox` files as spawnable [`VoxelScene`]s.
pub struct VoxScenePlugin;
#[derive(Default)]
pub struct VoxScenePlugin {
/// Inject global settings. This is a workaround for `load_with_settings` currently being broken.
/// See: https://github.com/bevyengine/bevy/issues/12320
/// and: https://github.com/bevyengine/bevy/issues/11111
pub global_settings: Option<VoxLoaderSettings>,
}

impl Plugin for VoxScenePlugin {
fn build(&self, app: &mut App) {
app.init_asset::<VoxelScene>()
.init_asset::<VoxelModelCollection>()
.register_asset_loader(VoxSceneLoader)
.register_asset_loader(VoxSceneLoader {
global_settings: self.global_settings.clone(),
})
.add_systems(SpawnScene, scene::systems::spawn_vox_scenes);
}
}
24 changes: 19 additions & 5 deletions src/load/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,15 @@ use crate::{
/// The meshes generated by this asset loader only use standard [`bevy::render::mesh::Mesh`] attributes for easier compatibility with shaders.
/// You can load multiple models from the same `.vox` file by appending `#{name}` to the asset loading path, where `{name}` corresponds to the object's name in the Magical Voxel world editor.
/// You can load unnamed models by appending `#model{no}` to the asset loading path, where `{no}` corresponds to the model index in the file. Note that this index is subject to change if you delete models in the Magica Voxel file.
pub(super) struct VoxSceneLoader;
pub(super) struct VoxSceneLoader {
pub(super) global_settings: Option<VoxLoaderSettings>,
}

/// Settings for the VoxSceneLoader.
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Clone)]
pub struct VoxLoaderSettings {
/// The length of each side of a single voxel. Defaults to 1.0.
pub voxel_size: f32,
/// Whether the outer-most faces of the model should be meshed. Defaults to true. Set this to false if the outer faces of a
/// model will never be visible, for instance if the model id part of a 3D tileset.
pub mesh_outer_faces: bool,
Expand All @@ -44,6 +48,7 @@ pub struct VoxLoaderSettings {
impl Default for VoxLoaderSettings {
fn default() -> Self {
Self {
voxel_size: 1.0,
mesh_outer_faces: true,
emission_strength: 10.0,
uses_srgb: true,
Expand Down Expand Up @@ -94,7 +99,7 @@ impl VoxSceneLoader {
Err(error) => return Err(VoxLoaderError::InvalidAsset(anyhow!(error))),
};
info!("Loading {}", load_context.asset_path());

let settings = self.global_settings.clone().unwrap_or(settings.clone());
// Palette
let palette = VoxelPalette::from_data(
&file,
Expand All @@ -121,7 +126,12 @@ impl VoxSceneLoader {

// Scene graph

let root = parse_xform_node(&file.scenes, &file.scenes[0], None, load_context);
let root = parse_xform_node(
&file.scenes,
&file.scenes[0],
None,
settings.voxel_size,
);
let layers: Vec<LayerInfo> = file
.layers
.iter()
Expand All @@ -144,7 +154,11 @@ impl VoxSceneLoader {
.map(|(index, (maybe_name, model))| {
let name = maybe_name.clone().unwrap_or(format!("model-{}", index));
index_for_model_name.insert(name.to_string(), index);
let data = VoxelData::from_model(&model, settings.mesh_outer_faces);
let data = VoxelData::from_model(
&model,
settings.mesh_outer_faces,
settings.voxel_size,
);
let (visible_voxels, ior) = data.visible_voxels(&indices_of_refraction);
let mesh = load_context.labeled_asset_scope(format!("{}@mesh", name), |_| {
crate::model::mesh::mesh_model(&visible_voxels, &data)
Expand Down
15 changes: 8 additions & 7 deletions src/load/parse_model.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
use bevy::math::{UVec3, Vec3};
use bevy::math::UVec3;
use dot_vox::Model;

use crate::model::{RawVoxel, VoxelData};

impl VoxelData {
/// Ingest Magica Voxel data and perform coordinate conversion from MV's left-handed Z-up to bevy's right-handed Y-up
pub(super) fn from_model(model: &Model, mesh_outer_faces: bool) -> VoxelData {
pub(super) fn from_model(model: &Model, mesh_outer_faces: bool, voxel_size: f32) -> VoxelData {
let mut data = VoxelData::new(
UVec3::new(model.size.x, model.size.z, model.size.y),
mesh_outer_faces,
voxel_size,
);
model.voxels.iter().for_each(|voxel| {
let raw_voxel = RawVoxel(voxel.i);
let _ = data.set_voxel(
data.set_voxel(
raw_voxel.into(),
Vec3::new(
((model.size.x - 1) - voxel.x as u32) as f32,
voxel.z as f32,
voxel.y as f32,
UVec3::new(
(model.size.x - 1) - voxel.x as u32,
voxel.z as u32,
voxel.y as u32,
),
);
});
Expand Down
22 changes: 11 additions & 11 deletions src/load/parse_scene.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use bevy::{
asset::LoadContext,
log::warn,
math::{Mat3, Mat4, Quat, Vec3},
utils::HashMap,
Expand Down Expand Up @@ -40,7 +39,7 @@ pub(super) fn parse_xform_node(
graph: &Vec<SceneNode>,
scene_node: &SceneNode,
parent_name: Option<&String>,
load_context: &mut LoadContext,
scene_scale: f32,
) -> VoxelNode {
match scene_node {
SceneNode::Transform {
Expand All @@ -53,7 +52,7 @@ pub(super) fn parse_xform_node(
get_accumulated_and_node_name(parent_name, attributes.get("_name"));
let mut vox_node = VoxelNode {
name: node_name,
transform: transform_from_frame(&frames[0]),
transform: transform_from_frame(&frames[0], scene_scale),
is_hidden: parse_bool(attributes.get("_hidden").cloned()),
layer_id: *layer_id,
..Default::default()
Expand All @@ -63,14 +62,14 @@ pub(super) fn parse_xform_node(
&graph[*child as usize],
&mut vox_node,
accumulated.as_ref(),
load_context,
scene_scale,
);
vox_node
}
SceneNode::Group { .. } | SceneNode::Shape { .. } => {
warn!("Found Group or Shape Node without a parent Transform");
let mut vox_node = VoxelNode::default();
parse_xform_child(graph, scene_node, &mut vox_node, parent_name, load_context);
parse_xform_child(graph, scene_node, &mut vox_node, parent_name, scene_scale);
vox_node
}
}
Expand All @@ -81,7 +80,7 @@ fn parse_xform_child(
scene_node: &SceneNode,
partial_node: &mut VoxelNode,
parent_name: Option<&String>,
load_context: &mut LoadContext,
scene_scale: f32,
) {
match scene_node {
SceneNode::Transform { .. } => {
Expand All @@ -90,7 +89,7 @@ fn parse_xform_child(
graph,
scene_node,
parent_name,
load_context,
scene_scale,
)];
}
SceneNode::Group {
Expand All @@ -100,7 +99,7 @@ fn parse_xform_child(
partial_node.children = children
.iter()
.map(|child| {
parse_xform_node(graph, &graph[*child as usize], parent_name, load_context)
parse_xform_node(graph, &graph[*child as usize], parent_name, scene_scale)
})
.collect();
}
Expand Down Expand Up @@ -140,12 +139,13 @@ fn parse_bool(value: Option<String>) -> bool {
}
}

fn transform_from_frame(frame: &Frame) -> Mat4 {
fn transform_from_frame(frame: &Frame, scene_scale: f32) -> Mat4 {
let Some(position) = frame.position() else {
return Mat4::IDENTITY;
};
let position = [-position.x as f32, position.z as f32, position.y as f32];
let translation = Mat4::from_translation(Vec3::from_array(position));
let position =
Vec3::new(-position.x as f32, position.z as f32, position.y as f32) * scene_scale;
let translation = Mat4::from_translation(position);
let rotation = if let Some(orientation) = frame.orientation() {
let (rotation, scale) = &orientation.to_quat_scale();
let scale: Vec3 = (*scale).into();
Expand Down
Loading

0 comments on commit 88b09fb

Please sign in to comment.