mirror of
https://github.com/kaosat-dev/Blender_bevy_components_workflow.git
synced 2024-11-22 03:50:52 +00:00
chore(cleanups): overall minor cleanups & tweaks (#3)
* split documentation between main docs & example docs * clearer seperation between example, blender add on etc * some minor code quality improvements based on Clippy linting * minor tweaks & additions to Blender & gltf example files: swapped out one mesh collider for a capsule collider for demo purposes * cleanups, tweaks, badges etc
This commit is contained in:
parent
e24ccc01cc
commit
d9060a4d6b
42
README.md
42
README.md
@ -1,3 +1,5 @@
|
|||||||
|
[![Bevy tracking](https://img.shields.io/badge/Bevy%20tracking-released%20version-lightblue)](https://github.com/bevyengine/bevy/blob/main/docs/plugins_guidelines.md#main-branch-tracking)
|
||||||
|
|
||||||
|
|
||||||
# bevy_gltf_components
|
# bevy_gltf_components
|
||||||
|
|
||||||
@ -21,6 +23,9 @@ It also allows you to setup 'blueprints' in Blender by using collections (the re
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
***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
|
||||||
|
|
||||||
1. Add the crate to your dependencies
|
1. Add the crate to your dependencies
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@ -205,8 +210,7 @@ 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
|
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
|
## Workflow
|
||||||
|
|
||||||
@ -264,8 +268,6 @@ see the [example](./examples/general/) for more information on how to set things
|
|||||||
* In the Level/world itself, just create an instance of the collection (standard Blender, ie Shift+A -> collection instance -> pick the collection)
|
* In the Level/world itself, just create an instance of the collection (standard Blender, ie Shift+A -> collection instance -> pick the collection)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- export your level as a glb/gltf file :
|
- export your level as a glb/gltf file :
|
||||||
!!**IMPORTANT** you need to check the following:
|
!!**IMPORTANT** you need to check the following:
|
||||||
- custom properties
|
- custom properties
|
||||||
@ -301,9 +303,6 @@ Included are the following modules / tools
|
|||||||
* [```lighting```](./examples/general/core/lighting/) an other example post process/replace proxies plugin for lighting, that toggles shadows, lighting config, etc so that things look closer to the original Blender data
|
* [```lighting```](./examples/general/core/lighting/) an other example post process/replace proxies plugin for lighting, that toggles shadows, lighting config, etc so that things look closer to the original Blender data
|
||||||
* [```physics```](./examples/general/core/physics/) an other example post process/replace proxies plugin for physics, that add [Rapier](https://rapier.rs/docs/user_guides/bevy_plugin/getting_started_bevy) Colliders, Rigidbodies etc . Most of these do not need proxies these days, as the most Rapier components are in the Registry & can be used directly
|
* [```physics```](./examples/general/core/physics/) an other example post process/replace proxies plugin for physics, that add [Rapier](https://rapier.rs/docs/user_guides/bevy_plugin/getting_started_bevy) Colliders, Rigidbodies etc . Most of these do not need proxies these days, as the most Rapier components are in the Registry & can be used directly
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Feel free to use as you want, rip it appart, use any/all parts that you need !
|
Feel free to use as you want, rip it appart, use any/all parts that you need !
|
||||||
|
|
||||||
This tooling and workflow has enabled me to go from a blank Bevy + Blender setup to a working barebones level in very little time (30 minutes or so ?) !
|
This tooling and workflow has enabled me to go from a blank Bevy + Blender setup to a working barebones level in very little time (30 minutes or so ?) !
|
||||||
@ -326,34 +325,11 @@ You can then add your own components & systems for your own gameplay very easill
|
|||||||
* gltf spawning tools where you just need to preload gltf files then you can spawn 1...n entities defined in gltf files by name (for example enemies, powerups, etc)
|
* gltf spawning tools where you just need to preload gltf files then you can spawn 1...n entities defined in gltf files by name (for example enemies, powerups, etc)
|
||||||
* simplified animation logic: ie instead of having to manually specify the animations you need from a gltf file, it is integrated with the spawning system above, which creates a ```Animations``` component in all entities that have an ```AnimationPlayer``` and you can simply query for both to easilly control your animations per entity.
|
* simplified animation logic: ie instead of having to manually specify the animations you need from a gltf file, it is integrated with the spawning system above, which creates a ```Animations``` component in all entities that have an ```AnimationPlayer``` and you can simply query for both to easilly control your animations per entity.
|
||||||
|
|
||||||
## Bonus !!
|
## Blender gltf_auto_export
|
||||||
- for convenience I also added a [Blender addon](./tools/blender_auto_export/blender_auto_export_gltf.py) that automatically exports your level/world from Blender to gltf whenever you save your Blend file
|
- for convenience I also added a [Blender addon](./tools/blender_auto_export/README.md) that automatically exports your level/world from Blender to gltf whenever you save your Blend file
|
||||||
(actually when you save inside your level/world scene or in the "library" scene, where I personally usually store all collections to instanciate).
|
(actually when you save inside your level/world scene or in the "library" scene, where I personally usually store all collections to instanciate).
|
||||||
It is **very** barebones and messy, but it does a minimal ok job.
|
It is **very** barebones and messy, but it does a minimal ok job. Please read the README of the add-on for installation instructions
|
||||||
|
|
||||||
### Installation:
|
|
||||||
|
|
||||||
* in Blender go to edit => preferences => install
|
|
||||||
|
|
||||||
![blender addon install](./docs/blender_addon_install.png)
|
|
||||||
|
|
||||||
* choose the path where ```blender_auto_export/blender_auto_export_gltf.py``` is stored
|
|
||||||
|
|
||||||
![blender addon install](./docs/blender_addon_install2.png)
|
|
||||||
|
|
||||||
### Usage:
|
|
||||||
|
|
||||||
* before it can automatically save to gltf, you need to configure it
|
|
||||||
* go to file => export => gltf auto export
|
|
||||||
|
|
||||||
![blender addon use](./docs/blender_addon_use.png)
|
|
||||||
|
|
||||||
* set up your parameters: output path, name of your main scene etc
|
|
||||||
|
|
||||||
![blender addon use2](./docs/blender_addon_use2.png)
|
|
||||||
|
|
||||||
* click on "apply settings"
|
|
||||||
* now next time you save your blend file you will get an automatically exported gltf file
|
|
||||||
|
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
Binary file not shown.
Binary file not shown.
128
examples/general/README.md
Normal file
128
examples/general/README.md
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
|
||||||
|
# Workflow with blender / demo information
|
||||||
|
|
||||||
|
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**.
|
||||||
|
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
|
||||||
|
* code to auto add additional required components in Bevy (if B is needed with A but B is not present, it adds it: optional & configurable)
|
||||||
|
* minimal setup & code, you can have something basic running fast
|
||||||
|
* opensource
|
||||||
|
|
||||||
|
There is a [video tutorial/explanation](https://youtu.be/-lcScjQCA3c) if you want, or you can skip to the text version ahead
|
||||||
|
|
||||||
|
|
||||||
|
## Running this example
|
||||||
|
|
||||||
|
```
|
||||||
|
cargo run --example general --features bevy/dynamic_linking
|
||||||
|
```
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
The workflow goes as follows (once you got your Bevy code setup)
|
||||||
|
|
||||||
|
### All core/helper modules
|
||||||
|
|
||||||
|
see the [example](./examples/general/) for more information on how to set things up
|
||||||
|
|
||||||
|
|
||||||
|
### Then...
|
||||||
|
|
||||||
|
- create & register all your components you want to be able to set from the Blender side (this is basic Bevy, no specific work needed)
|
||||||
|
|
||||||
|
![component registration](./docs/component_registration.png)
|
||||||
|
|
||||||
|
|
||||||
|
- Create a mesh/ collection (for reuse) in Blender
|
||||||
|
- Go to object properties => add a property, and add your component data
|
||||||
|
- unit structs, enums, and more complex strucs / components are all supported, (if the fields are basic data types at least,
|
||||||
|
have not tried more complex ones yet, but should also work)
|
||||||
|
- for structs with no params (unit structs): use a **STRING** property & an empty value
|
||||||
|
- for structs with params: use a RON representation of your fields (see below)
|
||||||
|
- for tupple strucs you can use any of the built in Blender custom property types: Strings, Booleans, floats, Vectors, etc
|
||||||
|
|
||||||
|
![unit struct components in Blender](./docs/components_blender.png)
|
||||||
|
|
||||||
|
In rust:
|
||||||
|
|
||||||
|
![unit struct components in Bevy](./docs/demo_simple_components.png)
|
||||||
|
|
||||||
|
(the Rust struct for these components for reference is [here](./examples/general/game.rs#34) )
|
||||||
|
|
||||||
|
|
||||||
|
![complex components in Blender](./docs/components_blender_parameters.png)
|
||||||
|
|
||||||
|
In rust:
|
||||||
|
|
||||||
|
![complex components in Blender](./docs/camera_tracking_component.png)
|
||||||
|
|
||||||
|
(the Rust struct for this component for reference is [here](./examples/general/core/camera/camera_tracking.rs#21) )
|
||||||
|
|
||||||
|
There is an other examples of using various Component types: Enums, Tupple structs, strucs with fields etc [here](./examples/general/test_components.rs),
|
||||||
|
even colors, Vecs (arrays), Vec2, Vec3 etc are all supported
|
||||||
|
|
||||||
|
![complex components in Blender](./docs/components_blender_parameters2.png)
|
||||||
|
|
||||||
|
- for collections & their instances:
|
||||||
|
* I usually create a library scene with nested collections
|
||||||
|
* the leaf collections are the assets you use in your level
|
||||||
|
* add an empty called xxxx_components
|
||||||
|
* add the components as explained in the previous part
|
||||||
|
![blender collection asset](./docs/blender_collections.png)
|
||||||
|
|
||||||
|
* In the Level/world itself, just create an instance of the collection (standard Blender, ie Shift+A -> collection instance -> pick the collection)
|
||||||
|
|
||||||
|
|
||||||
|
- export your level as a glb/gltf file :
|
||||||
|
!!**IMPORTANT** you need to check the following:
|
||||||
|
- custom properties
|
||||||
|
- cameras & lights if you want a complete level (as in this example)
|
||||||
|
|
||||||
|
![gltf_export](./docs/gltf_export.png)
|
||||||
|
|
||||||
|
|
||||||
|
- load it in Bevy (see the demo main file for this)
|
||||||
|
- you should see the components attached to your entities in Bevy
|
||||||
|
|
||||||
|
![components in bevy](./docs/components_bevy.png)
|
||||||
|
![components in bevy](./docs/components_bevy2.png)
|
||||||
|
![components in bevy](./docs/components_bevy3.png)
|
||||||
|
|
||||||
|
|
||||||
|
> note: you get a warning if there are any unregistered components in your gltf file (they get ignored)
|
||||||
|
you will get a warning **per entity**
|
||||||
|
![missing components warnings](./docs/component_warnings.png)
|
||||||
|
|
||||||
|
|
||||||
|
### Additional notes
|
||||||
|
|
||||||
|
* You usually define either the Components directly or use ```Proxy components``` that get replaced in Bevy systems with the actual Components that you want (usually when for some reason, ie external crates with unregistered components etc) you cannot use the components directly.
|
||||||
|
|
||||||
|
Included are the following modules / tools
|
||||||
|
* [```process_gltf```](./src/process_gltfs.rs) the most important module: this is the one extracting ```component``` information from the gltf files
|
||||||
|
* [```insert_dependant_component```](./examples/general/core/relationships/relationships_insert_dependant_components.rs) a small utility to automatically inject
|
||||||
|
components that are dependant on an other component
|
||||||
|
for example an Entity with a Player component should also always have a ShouldBeWithPlayer component
|
||||||
|
you get a warning if you use this though, as I consider this to be stop-gap solution (usually you should have either a bundle, or directly define all needed components)
|
||||||
|
* [```camera```](./examples/general/core/camera/) an example post process/replace proxies plugin, for Camera that also adds CameraTracking functions (to enable a camera to follow an object, ie the player)
|
||||||
|
* [```lighting```](./examples/general/core/lighting/) an other example post process/replace proxies plugin for lighting, that toggles shadows, lighting config, etc so that things look closer to the original Blender data
|
||||||
|
* [```physics```](./examples/general/core/physics/) an other example post process/replace proxies plugin for physics, that add [Rapier](https://rapier.rs/docs/user_guides/bevy_plugin/getting_started_bevy) Colliders, Rigidbodies etc . Most of these do not need proxies these days, as the most Rapier components are in the Registry & can be used directly
|
||||||
|
|
||||||
|
Feel free to use as you want, rip it appart, use any/all parts that you need !
|
||||||
|
|
||||||
|
This tooling and workflow has enabled me to go from a blank Bevy + Blender setup to a working barebones level in very little time (30 minutes or so ?) !
|
||||||
|
You can then add your own components & systems for your own gameplay very easilly
|
||||||
|
|
||||||
|
## Information
|
||||||
|
- the Bevy/ Rust code is [here](./examples/general/main.rs)
|
||||||
|
- the Blender file is [here](./assets/models/level.blend)
|
||||||
|
- I added [bevy_editor_pls](https://github.com/jakobhellermann/bevy_editor_pls) as a dependency for convenience so you can inspect your level/components
|
@ -1,6 +1,5 @@
|
|||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
|
|
||||||
|
|
||||||
use ron::Value;
|
use ron::Value;
|
||||||
use serde::de::DeserializeSeed;
|
use serde::de::DeserializeSeed;
|
||||||
|
|
||||||
@ -80,7 +79,7 @@ pub fn gltf_extras_to_components(
|
|||||||
// find a way to link this name to the current entity ? => WOULD BE VERY USEFULL for animations & co !!
|
// find a way to link this name to the current entity ? => WOULD BE VERY USEFULL for animations & co !!
|
||||||
debug!("done pre-processing components, now adding them to entities");
|
debug!("done pre-processing components, now adding them to entities");
|
||||||
for (entity, components) in entity_components {
|
for (entity, components) in entity_components {
|
||||||
if components.len() > 0 {
|
if !components.is_empty() {
|
||||||
debug!("--entity {:?}, components {}", entity, components.len());
|
debug!("--entity {:?}, components {}", entity, components.len());
|
||||||
}
|
}
|
||||||
for component in components {
|
for component in components {
|
||||||
@ -99,8 +98,8 @@ pub fn gltf_extras_to_components(
|
|||||||
// scene.world.components().
|
// scene.world.components().
|
||||||
// TODO: how can we insert any additional components "by hand" here ?
|
// TODO: how can we insert any additional components "by hand" here ?
|
||||||
}
|
}
|
||||||
let e_mut = scene.world.entity_mut(entity);
|
let entity_mut = scene.world.entity_mut(entity);
|
||||||
let archetype = e_mut.archetype().clone();//.components();
|
let archetype = entity_mut.archetype().clone();
|
||||||
let _all_components = archetype.components();
|
let _all_components = archetype.components();
|
||||||
// println!("All components {:?}", all_components);
|
// println!("All components {:?}", all_components);
|
||||||
|
|
||||||
@ -129,7 +128,7 @@ pub fn gltf_extras_to_components(
|
|||||||
parsed_value = str;
|
parsed_value = str;
|
||||||
}
|
}
|
||||||
_=> {
|
_=> {
|
||||||
parsed_value = format!("{}", ron::to_string(&value).unwrap() )
|
parsed_value = ron::to_string(&value).unwrap().to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,12 +179,10 @@ pub fn gltf_extras_to_components(
|
|||||||
formated = parsed_value.parse::<u128>().unwrap().to_string();
|
formated = parsed_value.parse::<u128>().unwrap().to_string();
|
||||||
}
|
}
|
||||||
"glam::f32::vec2::Vec2" => {
|
"glam::f32::vec2::Vec2" => {
|
||||||
//println!("WE HAVE A VEC2 {}", parsed_value);
|
|
||||||
let parsed: Vec<f32> = ron::from_str(&parsed_value).unwrap();
|
let parsed: Vec<f32> = ron::from_str(&parsed_value).unwrap();
|
||||||
formated = format!("(x:{},y:{})", parsed[0], parsed[1]);
|
formated = format!("(x:{},y:{})", parsed[0], parsed[1]);
|
||||||
}
|
}
|
||||||
"glam::f32::vec3::Vec3" => {
|
"glam::f32::vec3::Vec3" => {
|
||||||
//println!("WE HAVE A VEC3 {}", parsed_value);
|
|
||||||
let parsed: Vec<f32> = ron::from_str(&parsed_value).unwrap();
|
let parsed: Vec<f32> = ron::from_str(&parsed_value).unwrap();
|
||||||
formated = format!("(x:{},y:{},z:{})", parsed[0], parsed[1], parsed[2]);
|
formated = format!("(x:{},y:{},z:{})", parsed[0], parsed[1], parsed[2]);
|
||||||
},
|
},
|
||||||
@ -209,7 +206,7 @@ pub fn gltf_extras_to_components(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// println!("parsed value {}",parsed_value);
|
// println!("parsed value {}",parsed_value);
|
||||||
if parsed_value == "" {
|
if parsed_value.is_empty() {
|
||||||
parsed_value = "()".to_string();
|
parsed_value = "()".to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,9 +222,9 @@ pub fn gltf_extras_to_components(
|
|||||||
ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();
|
ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();
|
||||||
println!("serialized Component {}", serialized);*/
|
println!("serialized Component {}", serialized);*/
|
||||||
|
|
||||||
println!("component data ron string {}", ron_string);
|
// println!("component data ron string {}", ron_string);
|
||||||
let mut deserializer = ron::Deserializer::from_str(ron_string.as_str()).unwrap();
|
let mut deserializer = ron::Deserializer::from_str(ron_string.as_str()).unwrap();
|
||||||
let reflect_deserializer = UntypedReflectDeserializer::new(&type_registry);
|
let reflect_deserializer = UntypedReflectDeserializer::new(type_registry);
|
||||||
let component = reflect_deserializer.deserialize(&mut deserializer).expect(format!("failed to deserialize component {} with value: {:?}", key, value).as_str());
|
let component = reflect_deserializer.deserialize(&mut deserializer).expect(format!("failed to deserialize component {} with value: {:?}", key, value).as_str());
|
||||||
|
|
||||||
components.push(component);
|
components.push(component);
|
||||||
|
@ -63,8 +63,8 @@ use super::gltf_extras_to_components;
|
|||||||
// TODO this is a temporary workaround for library management
|
// TODO this is a temporary workaround for library management
|
||||||
if let Some(asset_path) = asset_server.get_handle_path(gltf_handle) {
|
if let Some(asset_path) = asset_server.get_handle_path(gltf_handle) {
|
||||||
let gltf_name = asset_path.path().file_stem().unwrap().to_str().unwrap();
|
let gltf_name = asset_path.path().file_stem().unwrap().to_str().unwrap();
|
||||||
gltf_extras_to_components(gltf, &mut scenes, &*type_registry, &gltf_name);
|
gltf_extras_to_components(gltf, &mut scenes, &*type_registry, gltf_name);
|
||||||
//gltf_extras_to_prefab_infos(gltf, &mut scenes, &*type_registry, &gltf_name);
|
//gltf_extras_to_prefab_infos(gltf, &mut scenes, &*type_registry, gltf_name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gltf_extras_to_components(gltf, &mut scenes, &*type_registry, "");
|
gltf_extras_to_components(gltf, &mut scenes, &*type_registry, "");
|
||||||
|
29
tools/blender_auto_export/README.md
Normal file
29
tools/blender_auto_export/README.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# gltf_auto_export
|
||||||
|
|
||||||
|
For convenience I also added this [Blender addon](./blender_auto_export_gltf.py) that automatically exports your level/world from Blender to gltf whenever you save your Blend file
|
||||||
|
(actually when you save inside your level/world scene or in the "library" scene, where I personally usually store all collections to instanciate).
|
||||||
|
It is **very** barebones and messy, but it does a minimal ok job.
|
||||||
|
|
||||||
|
### Installation:
|
||||||
|
|
||||||
|
* in Blender go to edit => preferences => install
|
||||||
|
|
||||||
|
![blender addon install](../../docs/blender_addon_install.png)
|
||||||
|
|
||||||
|
* choose the path where ```blender_auto_export/blender_auto_export_gltf.py``` is stored
|
||||||
|
|
||||||
|
![blender addon install](../../docs/blender_addon_install2.png)
|
||||||
|
|
||||||
|
### Usage:
|
||||||
|
|
||||||
|
* before it can automatically save to gltf, you need to configure it
|
||||||
|
* go to file => export => gltf auto export
|
||||||
|
|
||||||
|
![blender addon use](../../docs/blender_addon_use.png)
|
||||||
|
|
||||||
|
* set up your parameters: output path, name of your main scene etc
|
||||||
|
|
||||||
|
![blender addon use2](../../docs/blender_addon_use2.png)
|
||||||
|
|
||||||
|
* click on "apply settings"
|
||||||
|
* now next time you save your blend file you will get an automatically exported gltf file
|
Loading…
Reference in New Issue
Block a user