refactor(): restructured code to turn the process_gltf (core) part into a crate (#1)
* refactor(): restructured code to turn the process_gltf (core) part into a crate * changed process_gltf into a lib/crate basics * changed current demo setup into an example that is importing the new crate * updated imports in the crate side * updated dependencies * cleanups * added more clear information about preUpdate vs setup * improved README/ added use as crate examples
This commit is contained in:
parent
2eb6daece8
commit
1417d5f389
|
@ -675,6 +675,17 @@ dependencies = [
|
|||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bevy_gltf_components"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"bevy",
|
||||
"bevy_editor_pls",
|
||||
"bevy_rapier3d",
|
||||
"ron",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bevy_hierarchy"
|
||||
version = "0.11.0"
|
||||
|
@ -1208,17 +1219,6 @@ version = "2.3.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
|
||||
|
||||
[[package]]
|
||||
name = "blender-worklfow"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bevy",
|
||||
"bevy_editor_pls",
|
||||
"bevy_rapier3d",
|
||||
"ron",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
|
|
22
Cargo.toml
22
Cargo.toml
|
@ -1,17 +1,23 @@
|
|||
[package]
|
||||
name = "blender-worklfow"
|
||||
version = "0.1.0"
|
||||
name = "bevy_gltf_components"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bevy="0.11.0"
|
||||
serde = "*"
|
||||
ron="*"
|
||||
[dev-dependencies]
|
||||
bevy="0.11"
|
||||
bevy_rapier3d = { version = "0.22.0", features = [ "serde-serialize", "debug-render-3d", "enhanced-determinism"] }
|
||||
bevy_editor_pls = { git="https://github.com/jakobhellermann/bevy_editor_pls.git" }
|
||||
|
||||
[dependencies]
|
||||
bevy = { version = "0.11", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf"] }
|
||||
serde = "*"
|
||||
ron="*"
|
||||
|
||||
[[example]]
|
||||
name = "general"
|
||||
path = "examples/general/main.rs"
|
||||
|
||||
#### --------------------Dev/ debug-------------------------------
|
||||
# Enable high optimizations for dependencies (incl. Bevy), but not for our code:
|
||||
[profile.dev.package."*"]
|
||||
|
|
190
README.md
190
README.md
|
@ -1,8 +1,190 @@
|
|||
|
||||
# Blender_bevy_components_worklflow
|
||||
# bevy_gltf_components
|
||||
|
||||
![demo](./docs/blender_gltf_components.png)
|
||||
|
||||
A plugin & tools for adding components from gltf files in the [bevy](https://bevyengine.org/) game engine.
|
||||
|
||||
It enables minimalistic [Blender](https://www.blender.org/) (gltf) centric workflow for Bevy, ie defining entites & their components
|
||||
inside Blender using Blender's objects **custom properties**.
|
||||
Aka "Blender as editor for Bevy"
|
||||
|
||||
It also allows you to setup 'blueprints' in Blender by using collections (the recomended way to go most of the time), or directly on single use objects .
|
||||
|
||||
## Features
|
||||
|
||||
* Useful if you want to use Blender (or any editor allowing to export gltf with configurable gltf_extras) as your Editor
|
||||
* define Bevy components as custom properties in Blender (RON, though an older JSON version is also available)
|
||||
* no plugin or extra tools needed in Blender (but I provide a little Blender plugin to auto-export to gltf on save if you want !)
|
||||
* define components in Blender Collections & override any of them in your collection instances if you want
|
||||
* minimal setup & code, you can have something basic running fast
|
||||
|
||||
## Usage
|
||||
|
||||
1. Add the crate to your dependencies
|
||||
```toml
|
||||
[dependencies]
|
||||
bevy_gltf_components = { git="https://github.com/kaosat-dev/Blender_bevy_components_worklflow.git" }
|
||||
|
||||
```
|
||||
(not on crates.io yet !)
|
||||
|
||||
2. Import
|
||||
|
||||
```rust
|
||||
use bevy_gltf_components::ComponentsFromGltfPlugin;
|
||||
```
|
||||
|
||||
3. Add the plugin
|
||||
```rust
|
||||
.add_plugin(ComponentsFromGltfPlugin)
|
||||
```
|
||||
|
||||
### Example (without bevy_asset_loader)
|
||||
|
||||
See [here](./examples/general/main.rs) for more details
|
||||
|
||||
```rust
|
||||
use bevy::prelude::*;
|
||||
use bevy_gltf_components::ComponentsFromGltfPlugin;
|
||||
|
||||
|
||||
#[derive(Component, Reflect, Default, Debug, Deref, DerefMut)]
|
||||
#[reflect(Component)]
|
||||
struct TuppleTestF32(f32);
|
||||
|
||||
#[derive(Component, Reflect, Default, Debug, )]
|
||||
#[reflect(Component)]
|
||||
/// helper marker component, for demo only
|
||||
pub struct LoadedMarker;
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)]
|
||||
enum AppState {
|
||||
#[default]
|
||||
Loading,
|
||||
Running,
|
||||
}
|
||||
|
||||
fn main(){
|
||||
App::new()
|
||||
.add_plugins((
|
||||
DefaultPlugins,
|
||||
ComponentsFromGltfPlugin,
|
||||
))
|
||||
|
||||
.add_state::<AppState>()
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(Update, (
|
||||
spawn_level.run_if(in_state(AppState::Loading)),
|
||||
))
|
||||
.run();
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
struct AssetLoadHelper(Handle<Scene>);
|
||||
// we preload the data here, but this is for DEMO PURPOSES ONLY !! Please use https://github.com/NiklasEi/bevy_asset_loader or a similar logic to seperate loading / pre processing
|
||||
// of assets from the spawning
|
||||
// AssetLoadHelper is also just for the same purpose, you do not need it in a real scenario
|
||||
// the states here are also for demo purposes only,
|
||||
fn setup(
|
||||
mut commands: Commands,
|
||||
asset_server: Res<AssetServer>,
|
||||
) {
|
||||
|
||||
let tmp: Handle<Scene> = asset_server.load("models/level1.glb#Scene0");
|
||||
commands.insert_resource(AssetLoadHelper(tmp));
|
||||
}
|
||||
|
||||
fn spawn_level(
|
||||
mut commands: Commands,
|
||||
scene_markers: Query<&LoadedMarker>,
|
||||
preloaded_scene: Res<AssetLoadHelper>,
|
||||
|
||||
mut asset_event_reader: EventReader<AssetEvent<Gltf>>,
|
||||
mut next_state: ResMut<NextState<AppState>>,
|
||||
){
|
||||
|
||||
if let Some(asset_event) = asset_event_reader.iter().next() {
|
||||
match asset_event {
|
||||
AssetEvent::Created { handle: _ } => {
|
||||
info!("GLTF loaded");
|
||||
if scene_markers.is_empty() {
|
||||
info!("spawning scene");
|
||||
commands.spawn(
|
||||
(
|
||||
SceneBundle {
|
||||
scene: preloaded_scene.0.clone(),
|
||||
..default()
|
||||
},
|
||||
LoadedMarker,
|
||||
Name::new("Level1")
|
||||
)
|
||||
);
|
||||
next_state.set(AppState::Running);
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Example (with bevy_asset_loader, recommended for ease of use)
|
||||
|
||||
- follow [bevy_asset_loader's](https://github.com/NiklasEi/bevy_asset_loader) docs to setup your gltf asset loading
|
||||
- also add this plugin
|
||||
|
||||
```rust
|
||||
use bevy::prelude::*;
|
||||
use bevy_gltf_components::ComponentsFromGltfPlugin;
|
||||
|
||||
// replace this with your actual states !
|
||||
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)]
|
||||
enum AppState {
|
||||
#[default]
|
||||
Loading,
|
||||
Running,
|
||||
}
|
||||
|
||||
|
||||
fn main(){
|
||||
App::new()
|
||||
.add_plugins((
|
||||
DefaultPlugins,
|
||||
ComponentsFromGltfPlugin,
|
||||
))
|
||||
// do the setup for bevy_asset_loader
|
||||
.add_system(setup_game.in_schedule(OnEnter(AppState::Running)))
|
||||
|
||||
.run();
|
||||
}
|
||||
|
||||
|
||||
pub fn setup_game(
|
||||
mut commands: Commands,
|
||||
game_assets: Res<GameAssets>, // assets with your "world" or "level" gltf for example
|
||||
) {
|
||||
|
||||
|
||||
// more fast approach, load the game seperatly
|
||||
commands.spawn((
|
||||
SceneBundle {
|
||||
scene: game_assets.world.clone(),
|
||||
..default()
|
||||
},
|
||||
bevy::prelude::Name::from("world"),
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
# Workflow with blender
|
||||
|
||||
This example, is actually closer to a boilerplate + tooling showcases how to use a minimalistic [Blender](https://www.blender.org/) (gltf) centric workflow for [Bevy](https://bevyengine.org/), ie defining entites & their components
|
||||
inside Blender using Blender's objects **custom properties**.
|
||||
|
@ -12,7 +194,7 @@ It also allows you to setup 'blueprints' in Blender by using collections (the re
|
|||
|
||||
## Features
|
||||
|
||||
* Useful if you want to use Blender as your Editor
|
||||
* Useful if you want to use Blender (or any editor allowing to export gltf with configurable gltf_extras) as your Editor
|
||||
* define Bevy components as custom properties in Blender (RON, though an older JSON version is also available)
|
||||
* no plugin or extra tools needed in Blender (but I provide a little Blender plugin to auto-export to gltf on save if you want !)
|
||||
* define components in Blender Collections & override any of them in your collection instances if you want
|
||||
|
@ -22,6 +204,10 @@ It also allows you to setup 'blueprints' in Blender by using collections (the re
|
|||
|
||||
There is a [video tutorial/explanation](https://youtu.be/-lcScjQCA3c) if you want, or you can skip to the text version ahead
|
||||
|
||||
|
||||
important : the plugin for processing gltf files runs in *preUpdate* , so you cannot use the components directly if you spawn your scene from gltf in *setup* (the additional components will not show up)
|
||||
Please see the included example or use bevy_asset_loader for a reliable workflow
|
||||
|
||||
## Workflow
|
||||
|
||||
The workflow goes as follows (once you got your Bevy code setup)
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
pub mod process_gltf;
|
||||
pub use process_gltf::*;
|
||||
|
||||
pub mod camera;
|
||||
pub use camera::*;
|
||||
|
||||
|
@ -19,7 +16,6 @@ impl Plugin for CorePlugin {
|
|||
fn build(&self, app: &mut App) {
|
||||
app
|
||||
.add_plugins((
|
||||
ProcessGltfPlugin,
|
||||
LightingPlugin,
|
||||
CameraPlugin,
|
||||
PhysicsPlugin
|
|
@ -2,6 +2,7 @@ use std::time::Duration;
|
|||
use bevy::{prelude::*, asset::ChangeWatcher, gltf::Gltf};
|
||||
use bevy_editor_pls::prelude::*;
|
||||
use bevy_rapier3d::prelude::*;
|
||||
use bevy_gltf_components::ComponentsFromGltfPlugin;
|
||||
|
||||
mod core;
|
||||
use crate::core::*;
|
||||
|
@ -45,6 +46,7 @@ fn main(){
|
|||
RapierPhysicsPlugin::<NoUserData>::default(),
|
||||
RapierDebugRenderPlugin::default(),
|
||||
// our custom plugins
|
||||
ComponentsFromGltfPlugin,
|
||||
CorePlugin, // reusable plugins
|
||||
DemoPlugin, // specific to our game
|
||||
ComponentsTestPlugin // Showcases different type of components /structs
|
||||
|
@ -61,10 +63,10 @@ fn main(){
|
|||
|
||||
|
||||
#[derive(Resource)]
|
||||
struct AssetLoadHack(Handle<Scene>);
|
||||
struct AssetLoadHelper(Handle<Scene>);
|
||||
// we preload the data here, but this is for DEMO PURPOSES ONLY !! Please use https://github.com/NiklasEi/bevy_asset_loader or a similar logic to seperate loading / pre processing
|
||||
// of assets from the spawning
|
||||
// AssetLoadHack is also just for the same purpose, you do not need it in a real scenario
|
||||
// AssetLoadHelper is also just for the same purpose, you do not need it in a real scenario
|
||||
// the states here are also for demo purposes only,
|
||||
fn setup(
|
||||
mut commands: Commands,
|
||||
|
@ -72,13 +74,13 @@ fn setup(
|
|||
) {
|
||||
|
||||
let tmp: Handle<Scene> = asset_server.load("models/level1.glb#Scene0");
|
||||
commands.insert_resource(AssetLoadHack(tmp));
|
||||
commands.insert_resource(AssetLoadHelper(tmp));
|
||||
}
|
||||
|
||||
fn spawn_level(
|
||||
mut commands: Commands,
|
||||
scene_markers: Query<&LoadedMarker>,
|
||||
preloaded_scene: Res<AssetLoadHack>,
|
||||
preloaded_scene: Res<AssetLoadHelper>,
|
||||
|
||||
mut asset_event_reader: EventReader<AssetEvent<Gltf>>,
|
||||
mut next_state: ResMut<NextState<AppState>>,
|
||||
|
@ -106,7 +108,4 @@ fn spawn_level(
|
|||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
pub mod utils;
|
||||
pub use utils::*;
|
||||
|
||||
pub mod gltf_to_components;
|
||||
pub use gltf_to_components::*;
|
||||
|
||||
pub mod process_gltfs;
|
||||
pub use process_gltfs::*;
|
||||
|
||||
// pub mod models_replace_proxies;
|
||||
// pub use models_replace_proxies::*;
|
||||
|
||||
use bevy::prelude::*;
|
||||
|
||||
// use crate::state::{AppState};
|
||||
|
||||
pub struct ProcessGltfPlugin;
|
||||
impl Plugin for ProcessGltfPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app
|
||||
.insert_resource(GltfLoadingTracker::new())
|
||||
|
||||
.add_systems(PreUpdate, (
|
||||
track_new_gltf,
|
||||
process_loaded_scenes,
|
||||
))
|
||||
|
||||
// .add_systems((models_replace_proxies,).in_set(OnUpdate(AppState::GameRunning)))
|
||||
|
||||
// compute the aabbs of a whole hierarchy
|
||||
//.add_systems((compute_compound_aabb,).in_set(OnUpdate(AppState::GameRunning)))
|
||||
;
|
||||
}
|
||||
}
|
|
@ -1,12 +1,15 @@
|
|||
use std::collections::HashMap;
|
||||
use core::ops::Deref;
|
||||
|
||||
|
||||
use ron::Value;
|
||||
use serde::de::DeserializeSeed;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy::reflect::serde::{UntypedReflectDeserializer, ReflectSerializer};
|
||||
use bevy::reflect::{TypeRegistryInternal, TypeInfo};
|
||||
use bevy::prelude::{ResMut, Assets, info, debug, Name, Parent, warn};
|
||||
use bevy::ecs::{entity::Entity, reflect::ReflectComponent};
|
||||
use bevy::scene::Scene;
|
||||
use bevy::utils::HashMap;
|
||||
use bevy::reflect::serde::UntypedReflectDeserializer;
|
||||
use bevy::reflect::{TypeRegistryInternal, TypeInfo, Reflect};
|
||||
use bevy::gltf::{Gltf, GltfExtras};
|
||||
|
||||
use super::capitalize_first_letter;
|
|
@ -0,0 +1,57 @@
|
|||
pub mod utils;
|
||||
pub use utils::*;
|
||||
|
||||
pub mod gltf_to_components;
|
||||
pub use gltf_to_components::*;
|
||||
|
||||
pub mod process_gltfs;
|
||||
pub use process_gltfs::*;
|
||||
|
||||
use bevy::prelude::{
|
||||
App,Plugin, PreUpdate
|
||||
};
|
||||
|
||||
|
||||
/// A Bevy plugin for extracting components from gltf files and automatically adding them to the relevant entities
|
||||
/// It will automatically run every time you load a gltf file
|
||||
/// Add this plugin to your Bevy app to get access to this feature
|
||||
/// ```
|
||||
/// # use bevy::prelude::*;
|
||||
/// # use bevy_gltf_components::ComponentsFromGltfPlugin::*;
|
||||
///
|
||||
///
|
||||
/// fn main() {
|
||||
/// App::new()
|
||||
/// .add_plugins(DefaultPlugins)
|
||||
/// .add_plugin(GltfComponentsPlugin)
|
||||
/// .add_startup_system(setup)
|
||||
/// .add_system(spawn_level)
|
||||
/// .run();
|
||||
/// }
|
||||
///
|
||||
/// fn setup(
|
||||
/// mut state: ResMut<State>,
|
||||
/// asset_server: Res<AssetServer>,
|
||||
/// mut commands: bevy::prelude::Commands
|
||||
/// ){
|
||||
/// asset_server.load("models/level1.glb#Scene0")
|
||||
/// }
|
||||
///
|
||||
/// fn spawn_level(){
|
||||
///
|
||||
///}
|
||||
/// ```
|
||||
#[derive(Default)]
|
||||
pub struct ComponentsFromGltfPlugin;
|
||||
impl Plugin for ComponentsFromGltfPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app
|
||||
.insert_resource(GltfLoadingTracker::new())
|
||||
|
||||
.add_systems(PreUpdate, (
|
||||
track_new_gltf,
|
||||
process_loaded_scenes,
|
||||
))
|
||||
;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use std::collections::HashSet;
|
||||
use bevy::utils::HashSet;
|
||||
use bevy::{prelude::*, asset::LoadState};
|
||||
use bevy::gltf::Gltf;
|
||||
|
Loading…
Reference in New Issue