chore(Blenvy): more general cleanups & doc updates

* also more work done on example upgrades
This commit is contained in:
kaosat.dev 2024-07-16 23:51:49 +02:00
parent 30b052d4d2
commit b756819088
22 changed files with 126 additions and 752 deletions

View File

@ -1,7 +1,6 @@
[workspace] [workspace]
members = [ members = [
"crates/*", "crates/*",
"examples/common*",
"examples/blenvy/*", "examples/blenvy/*",
"testing/bevy_example/", "testing/bevy_example/",
] ]

View File

@ -1,6 +1,6 @@
# Blender add-ons # Blender add-ons
- gltf_auto_export and bevy_components have been replaced with a single add-on for simplicity - gltf_auto_export and bevy_components have been replaced with a single Blenvy add-on for simplicity
## Components: ## Components:
@ -111,7 +111,7 @@ Blenvy will take care of loading all needed blueprints & other assets for you
``` ```
## BlueprintDisabled ## BlueprintInstanceDisabled
you can now query for this component you can now query for this component

13
TODO.md
View File

@ -58,7 +58,7 @@ Components:
- [x] BLENVY_OT_component_rename_component - [x] BLENVY_OT_component_rename_component
- [x] BLENVY_OT_component_fix - [x] BLENVY_OT_component_fix
- [x] add handling for core::ops::Range<f32> & other ranges - [x] add handling for core::ops::Range<f32> & other ranges
- [x] fix is_component_valid that is used in gltf_auto_export - [x] fix is_component_valid that is used in blenvy
- [x] Hashmap Support - [x] Hashmap Support
- [x] fix parsing of keys's type either on Bevy side (prefered) or on the Blender side - [x] fix parsing of keys's type either on Bevy side (prefered) or on the Blender side
- [x] fix weird issue with missing "0" property when adding new entry in empty hashmap => happens only if the values for the "setter" have never been set - [x] fix weird issue with missing "0" property when adding new entry in empty hashmap => happens only if the values for the "setter" have never been set
@ -286,7 +286,7 @@ Bevy Side:
- [ ] invalidate despawned entity & parent entities AABB - [ ] invalidate despawned entity & parent entities AABB
- [ ] add unloading/cache removal of materials - [ ] add unloading/cache removal of materials
- [ ] add back and upgrade save-load
- [x] review & change general component insertion & spawning ordering & logic - [x] review & change general component insertion & spawning ordering & logic
- GltfComponentsSet::Injection => GltfBlueprintsSet::Spawn => GltfBlueprintsSet::AfterSpawn - GltfComponentsSet::Injection => GltfBlueprintsSet::Spawn => GltfBlueprintsSet::AfterSpawn
@ -299,8 +299,13 @@ Bevy Side:
- [x] how to deal with animation graphs ? - [x] how to deal with animation graphs ?
- [ ] remove "Library" component & co - [x] remove "Library" component & co
- [ ] BlueprintDisabled => BlueprintInstanceDisabled - [x] make "InBlueprint" non optional,
- [ ] and perhaps rename it to "FromBlueprint(BlueprintInfo)"
- [x] BlueprintInstanceDisabled => BlueprintInstanceDisabled
- [x] fix "remove component" operator from the rename/fix/update components panel
- [ ] replace string in BlueprintInfo path with PathBuf ?
- [ ] update main docs - [ ] update main docs
- [ ] rename project to Blenvy - [ ] rename project to Blenvy

View File

@ -33,7 +33,7 @@ Its main use case is as a backbone for the [```blenvy``` Blender add-on](https:/
* ability to specify **which resources** to save or to exclude * ability to specify **which resources** to save or to exclude
* small(er) save files (only a portion of the entities is saved) * small(er) save files (only a portion of the entities is saved)
Particularly useful when using [Blender](https://www.blender.org/) as an editor for the [Bevy](https://bevyengine.org/) game engine, combined with the [Blender plugin](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/tools/gltf_auto_export) that does a lot of the work for you (including spliting generating seperate gltf files for your static vs dynamic assets) Particularly useful when using [Blender](https://www.blender.org/) as an editor for the [Bevy](https://bevyengine.org/) game engine, combined with the [Blender plugin](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/tools/blenvy) that does a lot of the work for you (including spliting generating seperate gltf files for your static vs dynamic assets)
## Usage ## Usage
@ -290,37 +290,25 @@ particularly from https://github.com/kaosat-dev/Blenvy/tree/main/examples/blenvy
## Materials ## Materials
You have the option of using "material libraries" to share common textures/materials between blueprints, in order to avoid asset & memory bloat: Ff you enable it on the blender side, Blenvy will be using "material libraries" to share common textures/materials between blueprints, in order to avoid asset & memory bloat:
Ie for example without this option, 56 different blueprints using the same material with a large texture would lead to the material/texture being embeded Ie for example without this option, 56 different blueprints using the same material with a large texture would lead to the material/texture being embeded
56 times !! 56 times !!
you can configure this with the settings: Generating optimised blueprints and material libraries can be automated using the latests version of the [Blender plugin](https://github.com/kaosat-dev/Blenvy/tree/main/tools/blenvy)
```rust
material_library: true // defaults to false, enable this to enable automatic injection of materials from material library files
```
> Important! you must take care of preloading your material librairy gltf files in advance, using for example ```bevy_asset_loader```since
```blenvy``` currently does NOT take care of loading those at runtime
see https://github.com/kaosat-dev/Blenvy/tree/main/examples/blenvy/materials for how to set it up correctly
Generating optimised blueprints and material libraries can be automated using the latests version of the [Blender plugin](https://github.com/kaosat-dev/Blenvy/tree/main/tools/gltf_auto_export)
## Examples ## Examples
https://github.com/kaosat-dev/Blenvy/tree/main/examples/blenvy/basic https://github.com/kaosat-dev/Blenvy/tree/main/examples/blenvy/components
https://github.com/kaosat-dev/Blenvy/tree/main/examples/blenvy/basic_xpbd_physics https://github.com/kaosat-dev/Blenvy/tree/main/examples/blenvy/blueprints
https://github.com/kaosat-dev/Blenvy/tree/main/examples/blenvy/animation https://github.com/kaosat-dev/Blenvy/tree/main/examples/blenvy/animation
https://github.com/kaosat-dev/Blenvy/tree/main/examples/blenvy/materials https://github.com/kaosat-dev/Blenvy/tree/main/examples/blenvy/save_load
https://github.com/kaosat-dev/Blenvy/tree/main/examples/blenvy/multiple_levels_multiple_blendfiles https://github.com/kaosat-dev/Blenvy/tree/main/examples/blenvy/demo (a full fledged demo)
## Compatible Bevy versions ## Compatible Bevy versions

View File

@ -45,7 +45,7 @@ pub struct AnimationInfo {
} }
/// Stores information about animations, to make things a bit easier api wise: /// Stores information about animations, to make things a bit easier api wise:
/// these components are automatically inserted by `gltf_auto_export` on entities that have animations /// these components are automatically inserted by the `blenvy` Blender add-on on entities that have animations
#[derive(Component, Reflect, Default, Debug)] #[derive(Component, Reflect, Default, Debug)]
#[reflect(Component)] #[reflect(Component)]
pub struct AnimationInfos { pub struct AnimationInfos {

View File

@ -2,7 +2,7 @@
# Materials example/demo # Materials example/demo
Example of materials use & reuse (including textures) to avoid redundant materials in blueprints gltfs that lead to asset & memory bloat Example of materials use & reuse (including textures) to avoid redundant materials in blueprints gltfs that lead to asset & memory bloat
- to be used together with ```gltf_auto_export``` version >0.6 with the "materials library" option for exports - to be used together with ```blenvy``` version >0.6 with the "materials library" option for exports
- It shows you how ou can configure```Bevy_gltf_blueprints``` to support material libraries - It shows you how ou can configure```Bevy_gltf_blueprints``` to support material libraries
- material library is [here](./assets/materials/) - material library is [here](./assets/materials/)

View File

@ -7,4 +7,3 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
bevy = { version = "0.14", features = ["dynamic_linking"] } bevy = { version = "0.14", features = ["dynamic_linking"] }
blenvy = { path = "../../../crates/blenvy" } blenvy = { path = "../../../crates/blenvy" }
#bevy_gltf_worlflow_examples_common_rapier = { path = "../../common_rapier" }

View File

@ -5,12 +5,9 @@ edition = "2021"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
bevy = { version = "0.13", features = ["dynamic_linking"] } bevy = { version = "0.14", features = ["dynamic_linking"] }
bevy_gltf_blueprints = { path = "../../../crates/bevy_gltf_blueprints" } blenvy = { path = "../../../crates/blenvy" }
bevy_gltf_save_load = { path = "../../../crates/bevy_gltf_save_load" }
bevy_gltf_worlflow_examples_common_rapier = { path = "../../common_rapier" }
serde_json = "1.0.108" serde_json = "1.0.108"
serde = "1.0.193" serde = "1.0.193"
bevy_rapier3d = { version = "0.25.0", features = ["serde-serialize", "debug-render-3d", "enhanced-determinism"] }
rand = "0.8.5" rand = "0.8.5"

View File

@ -60,8 +60,8 @@ pub enum EnumTest {
None, None,
} }
pub struct ComponentsTestPlugin; pub struct ComponentsExamplesPlugin;
impl Plugin for ComponentsTestPlugin { impl Plugin for ComponentsExamplesPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.register_type::<BasicTest>() app.register_type::<BasicTest>()
.register_type::<UnitTest>() .register_type::<UnitTest>()

View File

@ -1,43 +0,0 @@
use bevy::{
core_pipeline::tonemapping::Tonemapping,
prelude::*,
render::{camera::CameraRenderGraph, primitives::Frustum, view::VisibleEntities},
utils::HashSet,
};
use bevy_gltf_blueprints::*;
use bevy_gltf_save_load::*;
use bevy_gltf_worlflow_examples_common_rapier::{CameraTrackingOffset, Pickable};
use bevy_rapier3d::dynamics::Velocity;
use std::any::TypeId;
pub struct CorePlugin;
impl Plugin for CorePlugin {
fn build(&self, app: &mut App) {
app.add_plugins((
SaveLoadPlugin {
save_path: "scenes".into(),
component_filter: SceneFilter::Allowlist(HashSet::from([
TypeId::of::<Name>(),
TypeId::of::<Transform>(),
TypeId::of::<Velocity>(),
TypeId::of::<InheritedVisibility>(),
TypeId::of::<Camera>(),
TypeId::of::<Camera3d>(),
TypeId::of::<Tonemapping>(),
TypeId::of::<CameraTrackingOffset>(),
TypeId::of::<Projection>(),
TypeId::of::<CameraRenderGraph>(),
TypeId::of::<Frustum>(),
TypeId::of::<GlobalTransform>(),
TypeId::of::<VisibleEntities>(),
TypeId::of::<Pickable>(),
])),
..Default::default()
},
BlueprintsPlugin {
aabbs: true,
..Default::default()
},
));
}
}

View File

@ -1,5 +1,8 @@
use bevy::prelude::*; use std::any::TypeId;
use bevy_gltf_worlflow_examples_common_rapier::CommonPlugin;
use bevy::{prelude::*, utils::hashbrown::HashSet};
use blenvy::{AddToGameWorld, BlenvyPlugin, BluePrintBundle, BlueprintInfo, DynamicBlueprintInstance, GameWorldTag, HideUntilReady, SpawnBlueprint};
use rand::Rng;
mod core; mod core;
use crate::core::*; use crate::core::*;
@ -7,18 +10,99 @@ use crate::core::*;
mod game; mod game;
use game::*; use game::*;
mod test_components; mod component_examples;
use test_components::*; use component_examples::*;
fn main() { fn main() {
App::new() App::new()
.add_plugins(( .add_plugins((
DefaultPlugins.set(AssetPlugin::default()), DefaultPlugins.set(AssetPlugin::default()),
BlenvyPlugin {
save_component_filter: SceneFilter::Allowlist(HashSet::from([
TypeId::of::<Name>(),
TypeId::of::<Transform>(),
//TypeId::of::<Velocity>(),
TypeId::of::<InheritedVisibility>(),
TypeId::of::<Camera>(),
TypeId::of::<Camera3d>(),
//TypeId::of::<Tonemapping>(),
//TypeId::of::<CameraTrackingOffset>(),
TypeId::of::<Projection>(),
//TypeId::of::<CameraRenderGraph>(),
//TypeId::of::<Frustum>(),
TypeId::of::<GlobalTransform>(),
//TypeId::of::<VisibleEntities>(),
//TypeId::of::<Pickable>(),
])),
..Default::default()
},
// our custom plugins // our custom plugins
CommonPlugin,
CorePlugin, // reusable plugins CorePlugin, // reusable plugins
GamePlugin, // specific to our game GamePlugin, // specific to our game
ComponentsTestPlugin, // Showcases different type of components /structs ComponentsExamplesPlugin, // Showcases different type of components /structs
)) ))
.add_systems(Startup, setup_game)
.add_systems(Update, (spawn_blueprint_instance, save_game, load_game))
.run(); .run();
} }
// this is how you setup & spawn a level from a blueprint
fn setup_game(
mut commands: Commands,
) {
// here we spawn our game world/level, which is also a blueprint !
commands.spawn((
BlueprintInfo::from_path("levels/World.glb"), // all we need is a Blueprint info...
SpawnBlueprint, // and spawnblueprint to tell blenvy to spawn the blueprint now
HideUntilReady, // only reveal the level once it is ready
GameWorldTag,
));
}
// you can also spawn blueprint instances at runtime
fn spawn_blueprint_instance(
keycode: Res<ButtonInput<KeyCode>>,
mut commands: Commands,
) {
if keycode.just_pressed(KeyCode::KeyT) {
// random position
let mut rng = rand::thread_rng();
let range = 5.5;
let x: f32 = rng.gen_range(-range..range);
let y: f32 = rng.gen_range(-range..range);
// random name
let name_index: u64 = rng.gen();
commands
.spawn((
BlueprintInfo::from_path("blueprints/test.glb"),
SpawnBlueprint,
DynamicBlueprintInstance,
bevy::prelude::Name::from(format!("test{}", name_index)),
HideUntilReady,
AddToGameWorld,
TransformBundle::from_transform(Transform::from_xyz(x, 2.0, y)),
));
}
}
fn save_game(
keycode: Res<ButtonInput<KeyCode>>,
) {
if keycode.just_pressed(KeyCode::KeyS) {
}
}
fn load_game(
keycode: Res<ButtonInput<KeyCode>>,
) {
if keycode.just_pressed(KeyCode::KeyL) {
}
}

View File

@ -1,12 +1,11 @@
[package] [package]
name = "bevy_gltf_blueprints_multiple_levels_multiple_blendfiles" name = "blenvy_demo"
version = "0.3.0" version = "0.3.0"
edition = "2021" edition = "2021"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
bevy = { version = "0.13", features = ["dynamic_linking"] } bevy = { version = "0.14", features = ["dynamic_linking"] }
bevy_gltf_blueprints = { path = "../../../crates/bevy_gltf_blueprints" } blenvy = { path = "../../../crates/blenvy" }
bevy_gltf_worlflow_examples_common_rapier = { path = "../../common_rapier" }
bevy_rapier3d = { version = "0.25.0", features = ["serde-serialize", "debug-render-3d", "enhanced-determinism"] } bevy_rapier3d = { version = "0.25.0", features = ["serde-serialize", "debug-render-3d", "enhanced-determinism"] }
rand = "0.8.5" rand = "0.8.5"

View File

@ -7,13 +7,6 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
bevy = { version = "0.14", features = ["dynamic_linking"] } bevy = { version = "0.14", features = ["dynamic_linking"] }
blenvy = { path = "../../crates/blenvy" } blenvy = { path = "../../crates/blenvy" }
# bevy_gltf_blueprints = { path = "../../crates/bevy_gltf_blueprints" }
# bevy_registry_export = { path = "../../crates/bevy_registry_export" }
# bevy_gltf_worlflow_examples_common_rapier = { path = "../../examples/common_rapier" }
#bevy_gltf_worlflow_examples_common = { path = "../../examples/common" }
#evy_rapier3d = { version = "0.25.0", features = ["serde-serialize", "debug-render-3d", "enhanced-determinism"] }
#bevy_asset_loader = { version = "0.20", features = ["standard_dynamic_assets"] }
#bevy_editor_pls = { version = "0.8" } #bevy_editor_pls = { version = "0.8" }
rand = "0.8.5" rand = "0.8.5"
json-writer ="0.3" json-writer ="0.3"

View File

@ -9,7 +9,7 @@ use bevy::{animation::RepeatAnimation, gltf::Gltf, prelude::*};
use blenvy::{ use blenvy::{
AnimationInfos, AnimationMarkerReached, BlueprintAnimationPlayerLink, BlueprintAnimations, AnimationInfos, AnimationMarkerReached, BlueprintAnimationPlayerLink, BlueprintAnimations,
BlueprintDisabled, SceneAnimationPlayerLink, SceneAnimations, BlueprintInstanceDisabled, SceneAnimationPlayerLink, SceneAnimations,
}; };
#[derive(Component, Reflect, Default, Debug)] #[derive(Component, Reflect, Default, Debug)]
@ -87,7 +87,7 @@ pub fn check_animations(
Option<&BlueprintAnimationPlayerLink>, Option<&BlueprintAnimationPlayerLink>,
Option<&SceneAnimationPlayerLink>, Option<&SceneAnimationPlayerLink>,
), ),
(With<MarkerAllFoxes>, Without<BlueprintDisabled>), (With<MarkerAllFoxes>, Without<BlueprintInstanceDisabled>),
>, >,
foo: Query< foo: Query<
@ -96,7 +96,7 @@ pub fn check_animations(
Option<&BlueprintAnimationPlayerLink>, Option<&BlueprintAnimationPlayerLink>,
Option<&SceneAnimationPlayerLink>, Option<&SceneAnimationPlayerLink>,
), ),
(With<Marker1>, Without<BlueprintDisabled>), (With<Marker1>, Without<BlueprintInstanceDisabled>),
>, >,
bar: Query< bar: Query<
( (
@ -104,7 +104,7 @@ pub fn check_animations(
Option<&BlueprintAnimationPlayerLink>, Option<&BlueprintAnimationPlayerLink>,
Option<&SceneAnimationPlayerLink>, Option<&SceneAnimationPlayerLink>,
), ),
(With<Marker2>, Without<BlueprintDisabled>), (With<Marker2>, Without<BlueprintInstanceDisabled>),
>, >,
baz: Query< baz: Query<
( (
@ -112,7 +112,7 @@ pub fn check_animations(
Option<&BlueprintAnimationPlayerLink>, Option<&BlueprintAnimationPlayerLink>,
Option<&SceneAnimationPlayerLink>, Option<&SceneAnimationPlayerLink>,
), ),
(With<Marker3>, Without<BlueprintDisabled>), (With<Marker3>, Without<BlueprintInstanceDisabled>),
>, >,
bli: Query<(Entity, &AnimationInfos)>, bli: Query<(Entity, &AnimationInfos)>,

View File

@ -1,229 +0,0 @@
Basics
- [x] add panel
- [x] add a "create blueprint" button
- [x] when clicked:
- [x] create collection
- [x] add an empty inside collection and name it <COLLECTION_NAME>_components
- [x] add a **AutoExport** Boolean property to collection
- [x] add name imput(popup for name input ?)
- [x] add a list of existing components/custom properties
- [x] add an "edit blueprint" section
- [x] only filled when there is ONE selection, and that selection is a collection
- [x] add a dropdown of possible components
- [x] add a checkbox for enabling disabling a component (enabled by default)
- [x] add a button for copying a component
- [x] add a button for pasting a component
UI:
- [x] filterable list of components to DISPLAY for selection : ComponentDefinitionsList
- Filter out invalid objects for components that have no _components suffix ? (that is too limiting I think)
- -[x] How to deal with pre-existing custom properties that have NO metadata
* if there is one without metadata: find if there is an available component with the same name & type ?
* if there is , insert metadata
* otherwise, mark it in some way visually ?
- [x] for OBJECT enums: add two ui pieces
- [x] one for selecting the TYPE to choose (ie normal enum)
- [x] one for setting the VALUE inside that
- [x] vecs => (not vec2, vec3 etc) more complex UI to add items in a list
- [x] generate contained CollectionGroup
- [x] CollectionProperty => type = the above
- [x] find ways to "collapse" the different levels of nested data of structs/tupples into a single custom property (ideally on the fly, but we can do without)
- [x] for single tupple components that represent a single unit type, re_use the base type's UIPropertyGroup instead of creating specific ones (ie TuppleTestF32_ui...) => will not work, would cause overriden "update callback"
- [x] pre_generate default values/values for each main type
- [x] fix issues with vec2 etc not having the correct number of items
- [x] fix bad defaults in ui group
- [x] fix object enums handling on updates (??)
- [x] fix issues with lambads in loops
- [x] object enum should be <EntryName>(params)
ie *Collider:
* Cuboid(Vec3)
* Sphere(radius)
- [x] deal with enums variants that do not have any data: ex {
"long_name": "Mesh"
}
- [x] remove / change use of ComponentDefinitionsList
- when filling the list, use the long_name as index ie items.append((str(index), item.name, item.long_name)) => items.append((item.long_name, item.name, item.long_name))
- [x] when removing a component, reset the value of the attribute in the property group (or not ? could be a feature)
- [x] deal correctly with fields of types that are NOT in the schema.json (for ex PlayingAnimation in AnimationPlayer)
- [ ] deal correctly with complex types
CascadeShadowConfig: has an array/list
ClusterConfig: one of the enum variants is an object
- [ ] possibly allow Color to be an enum as it should be ?
- [x] for sub items , the update functions "Name" should be the one of the root object
- [x] fix copy & pasting
- it actually works, but the value of the custom property are not copied back to the UI, need to implement property_group_value_from_custom_property_value
- [ ] we need a notion of "root propertyGroup" =?
- [x] notify user of missing entries in schema (ie , unregistered data types)
- [x] clarify propgroup_ui vs named nested fields
- [x] fix basic enums handling
- [x] add a list of not found components to the registry, add to them on the fly
- [x] add configuration panel (open the first time, closed on further user once configured)
- [x] add limits to ixxx types vs utypes
- [x] only display the "generate components xx" when relevant ie:
- go through list of custom properties in current object
- if one does not have metadata and / or propgroup:
break
- [x] remove custom property of disabled component ? => NOpe, as we need custom properties to iterate over
- [x] what to do with components with n/a fields ? perhaps disable the component ? add a "invalid" field to meta ?
- [x] format output as correct RON
- [x] fix issue with empty strings
- [x] change custom property => propGroup to convert RON => Json first => obsolete
- [x] cleanup process_lists
- [x] fix issues with enum variants with only a long_name
- [x] display single item enums inline, others in a seperate row
- [x] add button to "apply all" (in configuration), to apply/update all custom properties to ALL objects where relevant
- [x] add button to "apply to current" to do the same with current
- [x] add warning sign to the above
- [x] what about metadata ?
- [x] only upgrade custom properties to metadata when asked/relevant
- [x] implement move list up/down
- [ ] change property_group_value_from_custom_property_value => just disregard it for now, its point is very limited (helping people with old custom properties by attempting to generate real values)
and give the change to a real ron format, it is too limiting
- [x] fix reload registry clearing list of missing types
- [x] clean up metadata module, a lot of repeated code
- [x] some fields when original is 0 or 0.0 are not copyable ? (seems like a bad boolean check )
- [x] fix issues with object variants in enums (see clusterconfig)
- perhaps directly export default values within the schema.json ?
- for most types , it is straighforward, but others, not so much: like the default color in Bevy , etc
- [x] change default schema.json to registry.json
- [x] pasted components do not get updated value in custom_property
- [x] finish documentation
- [x] add storage of registry path
- [x] save after setting the data (browse for)
- [x] load after each reload ?
# Additional
- [x] check if output "string" in custom properties are correct
- gltf_auto_export
- [x] add support for "enabled" flag
- [ ] add special components
- "AutoExport" => Needed
- "Dynamic" ? naah wait that should be exported by the Bevy side
- [x] filter out Components_meta ??
- [x] add legacy mode to the persisted parameters
- bevy_gltf_components:
- [x] first release patch for current issues
- [x] make configurable
- [x] add "compatibility mode" and deprecation warnings for the current hack-ish conversion of fake ron
- [x] update docs to show we need to use ComponentsFromGltfPlugin::default
- bevy_gltf_blueprints
- [x] update dependency
- [x] update version
- [x] add ability to set legacy mode for bevy_gltf_components ?
- [x] release all versions
- [x] update main documentation, add compatibility version grid
## Phase 2
- [x] fix handling of long component names
- [x] fix nesting level handling issue for new system : ie basic component DOES NOT work, but nestedLevel2 does
- add goddam tests !
- [ ] verify some weird prop => custom property values (Calculated Clip for example)
- [x] fix "reload registry" not clearing all previous data (reloading registry does not seem to account for added/removed components in the registry )
- add file watcher for registry
- [x] have the watcher work as expected
- [ ] add handling of removed registry file
- [ ] clear & reset handler when the file browser for the registry is used
- [ ] re-enable watcher
- tests
clear && pytest -svv --blender-executable <path_to_blender>/blender/blender-4.0.2-linux-x64/blender
- [x] load registry
- just check list of components vs lists in registry
- [x] try adding all components
- [x] select an object
- [x] call the add_component operator
- [x] change params
- use field names + component definitions to set values
- [x] find a way to shuffle params of ALL components based on a reliable, repeatable seed
- [x] test propgroup values => custom property values
- [x] test custom property value => propgroup value
- check if all went well
- [x] fix issues with incorect custom_property generation
- [x] fix issue with object variants for enums
- [ ] add handling for core::ops::Range<f32> & other ranges
- [x] add handling for alloc::borrow::Cow<str>
- [x] add handling of isize
- [x] indirection level
- currently
- short_name +_"ui => direct lookup
- problem : max 64 chars for propertyGroupNames
- possible solution
- propertyGroupName storage: simple , incremented INT (call it propGroupId for ex)
- lookup shortName => propGroupId
- do a first pass, by replacing manual propGroupNames creation with a function
- in a second pass, replace the innards
- add button to regenerate cutom prop values from custom properties (allows us to sidestep any future issues with internals changing)
- [x] fix lists
- [x] fix enums (see Clusterconfig)
- [x] need an example with one tupple one struct
- [x] projection
- [x] additionalmassproperties
- [x] fix tupleStructs (see TupleVecF32F32) => always the same problem of having us pre-parse data without knowing what we have inside
- find a way to only split by level 0 (highest level) nesting "," seperators, ignoring any level of nesting until we dig one level deeper
- solve nesting level use issues
- [x] remove metadata when deleting components
- [x] add try catch around custom_prop => propGroup
- [x] enhance the BLENVY_OT_component_from_custom_property to use the new system to actually generate the stuff
- coherence in operators:
- component_name vs component_type
- [x] delete => remove
- [x] clean up reloading of registry settings
- [x] clean up file watcher
=========================================
Restructuring of storage of components
- [x] marking of invalid root propgroups/components should be based on long name
- [x] overhaul & check each prop group type's use of short names => long names
- [x] lists
- [x] property_name = short_name in process enum: will likely require to use another indirection helper to keep the propery names short
- [x] in conversions from propgroups
component_name = definition["short_name"]
- [ ] fix is_component_valid that is used in gltf_auto_export
- [x] update all tests
- Hashmap Support
- [x] fix parsing of keys's type either on Bevy side (prefered) or on the Blender side
- [x] fix weird issue with missing "0" property when adding new entry in empty hashmap => happens only if the values for the "setter" have never been set
- [ ] handle missing types in registry for keys & values
- [ ] Add correct upgrade handling from individual component to bevy_components

View File

@ -28,7 +28,7 @@ def gltf_post_export_callback(data):
gltf_settings_backup = tracker.gltf_settings_backup gltf_settings_backup = tracker.gltf_settings_backup
gltf_filepath = data["gltf_filepath"] gltf_filepath = data["gltf_filepath"]
gltf_export_id = data['gltf_export_id'] gltf_export_id = data['gltf_export_id']
if gltf_export_id == "gltf_auto_export": if gltf_export_id == "blenvy":
# some more absurdity: apparently the file is not QUITE done when the export callback is called, so we have to introduce this timer to remove the temporary file correctly # some more absurdity: apparently the file is not QUITE done when the export callback is called, so we have to introduce this timer to remove the temporary file correctly
tracker.dummy_file_path = gltf_filepath tracker.dummy_file_path = gltf_filepath
try: try:

View File

@ -1,402 +0,0 @@
bl_info = {
"name": "gltf_auto_export",
"author": "kaosigh",
"version": (0, 10, 0),
"blender": (3, 4, 0),
"location": "File > Import-Export",
"description": "glTF/glb auto-export",
"warning": "",
"wiki_url": "https://github.com/kaosat-dev/Blender_bevy_components_workflow",
"tracker_url": "https://github.com/kaosat-dev/Blender_bevy_components_workflow/issues/new",
"category": "Import-Export"
}
import bpy
from bpy.props import (BoolProperty,
IntProperty,
StringProperty,
EnumProperty,
CollectionProperty
)
# glTF extensions are named following a convention with known prefixes.
# See: https://github.com/KhronosGroup/glTF/tree/main/extensions#about-gltf-extensions
# also: https://github.com/KhronosGroup/glTF/blob/main/extensions/Prefixes.md
glTF_extension_name = "EXT_auto_export"
# Support for an extension is "required" if a typical glTF viewer cannot be expected
# to load a given model without understanding the contents of the extension.
# For example, a compression scheme or new image format (with no fallback included)
# would be "required", but physics metadata or app-specific settings could be optional.
extension_is_required = False
from io_scene_gltf2 import (GLTF_PT_export_main, GLTF_PT_export_include)
class ExampleExtensionProperties(bpy.types.PropertyGroup):
enabled: bpy.props.BoolProperty(
name=bl_info["name"],
description='Include this extension in the exported glTF file.',
default=True
)
auto_export_main_scene_name: StringProperty(
name='Main scene',
description='The name of the main scene/level/world to auto export',
default='Scene'
)
auto_export_output_folder: StringProperty(
name='Export folder (relative)',
description='The root folder for all exports(relative to current file) Defaults to current folder',
default=''
)
auto_export_library_scene_name: StringProperty(
name='Library scene',
description='The name of the library scene to auto export',
default='Library'
)
# scene components
auto_export_scene_settings: BoolProperty(
name='Export scene settings',
description='Export scene settings ie AmbientLighting, Bloom, AO etc',
default=False
)
# blueprint settings
auto_export_blueprints: BoolProperty(
name='Export Blueprints',
description='Replaces collection instances with an Empty with a BlueprintInfo custom property',
default=True
)
auto_export_blueprints_path: StringProperty(
name='Blueprints path',
description='path to export the blueprints to (relative to the Export folder)',
default='library'
)
auto_export_materials_library: BoolProperty(
name='Export materials library',
description='remove materials from blueprints and use the material library instead',
default=False
)
auto_export_materials_path: StringProperty(
name='Materials path',
description='path to export the materials libraries to (relative to the root folder)',
default='materials'
)
def register():
bpy.utils.register_class(ExampleExtensionProperties)
bpy.types.Scene.ExampleExtensionProperties = bpy.props.PointerProperty(type=ExampleExtensionProperties)
def register_panel():
# Register the panel on demand, we need to be sure to only register it once
# This is necessary because the panel is a child of the extensions panel,
# which may not be registered when we try to register this extension
try:
bpy.utils.register_class(GLTF_PT_UserExtensionPanel)
except Exception:
pass
# If the glTF exporter is disabled, we need to unregister the extension panel
# Just return a function to the exporter so it can unregister the panel
return unregister_panel
def unregister_panel():
# Since panel is registered on demand, it is possible it is not registered
try:
bpy.utils.unregister_class(GLTF_PT_UserExtensionPanel)
except Exception:
pass
def unregister():
unregister_panel()
bpy.utils.unregister_class(ExampleExtensionProperties)
del bpy.types.Scene.ExampleExtensionProperties
class GLTF_PT_UserExtensionPanel(bpy.types.Panel):
bl_space_type = 'FILE_BROWSER'
bl_region_type = 'TOOL_PROPS'
bl_label = "Enabled"
bl_parent_id = "GLTF_PT_export_user_extensions"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
sfile = context.space_data
operator = sfile.active_operator
return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
def draw_header(self, context):
props = bpy.context.scene.ExampleExtensionProperties
self.layout.prop(props, 'enabled')
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
props = bpy.context.scene.ExampleExtensionProperties
layout.active = props.enabled
props = bpy.context.scene.ExampleExtensionProperties
for bla in props.__annotations__:
layout.prop(props, bla)
class glTF2ExportUserExtension:
def __init__(self):
# We need to wait until we create the gltf2UserExtension to import the gltf2 modules
# Otherwise, it may fail because the gltf2 may not be loaded yet
from io_scene_gltf2.io.com.gltf2_io_extensions import Extension
self.Extension = Extension
self.properties = bpy.context.scene.ExampleExtensionProperties
def gather_node_hook(self, gltf2_object, blender_object, gltf_export_settings):
if self.properties.enabled:
if gltf2_object.extensions is None:
gltf2_object.extensions = {}
print("bla bla")
gltf2_object.extensions[glTF_extension_name] = self.Extension(
name=glTF_extension_name,
extension={"auto_export_blueprints": self.properties.auto_export_blueprints},
required=extension_is_required
)
def did_export_parameters_change(current_params, previous_params):
set1 = set(previous_params.items())
set2 = set(current_params.items())
difference = dict(set1 ^ set2)
changed_param_names = list(set(difference.keys())- set(AutoExportGltfPreferenceNames))
changed_parameters = len(changed_param_names) > 0
return changed_parameters
# original in export_blueprints => export_collections
# The part below is not necessary NORMALLY , but blender crashes in the "normal" case when using bpy.context.temp_override,
#if relevant we replace sub collections instances with placeholders too
# this is not needed if a collection/blueprint does not have sub blueprints or sub collections
collection_in_blueprint_hierarchy = collection_name in blueprint_hierarchy and len(blueprint_hierarchy[collection_name]) > 0
collection_has_child_collections = len(bpy.data.collections[collection_name].children) > 0
#if collection_in_blueprint_hierarchy or collection_has_child_collections:
"""else:
print("standard export")
# set active scene to be the library scene
original_scene = bpy.context.window.scene
bpy.context.window.scene = library_scene
with bpy.context.temp_override(scene=library_scene):
print("active scene", bpy.context.scene)
export_gltf(gltf_output_path, gltf_export_settings)
bpy.context.window.scene = original_scene"""
"""
blueprint_template = object['Template'] if 'Template' in object else False
if blueprint_template and parent_empty is None: # ONLY WORKS AT ROOT LEVEL
print("BLUEPRINT TEMPLATE", blueprint_template, destination_collection, parent_empty)
for object in source_collection.objects:
if object.type == 'EMPTY' and object.name.endswith("components"):
original_collection = bpy.data.collections[collection_name]
components_holder = object
print("WE CAN INJECT into", object, "data from", original_collection)
# now we look for components inside the collection
components = {}
for object in original_collection.objects:
if object.type == 'EMPTY' and object.name.endswith("components"):
for component_name in object.keys():
if component_name not in '_RNA_UI':
print( component_name , "-" , object[component_name] )
components[component_name] = object[component_name]
# copy template components into target object
for key in components:
print("copying ", key,"to", components_holder)
if not key in components_holder:
components_holder[key] = components[key]
"""
# potentially useful alternative
def duplicate_object2(object, original_name):
print("copy object", object)
with bpy.context.temp_override(object=object, active_object = object):
bpy.ops.object.duplicate(linked=False)
new_obj = bpy.context.active_object
print("new obj", new_obj, "bpy.context.view_layer", bpy.context.view_layer.objects)
for obj in bpy.context.view_layer.objects:
print("obj", obj)
bpy.context.view_layer.update()
new_obj.name = original_name
if object.animation_data:
print("OJECT ANIMATION")
new_obj.animation_data.action = object.animation_data.action.copy()
return new_obj
if active_operator:
# print("Operator", active_operator.bl_label, active_operator.bl_idname, "bla", bpy.context.window_manager.gltf_exporter_running)
if active_operator.bl_idname == "EXPORT_SCENE_OT_gltf" : #and not bpy.context.window_manager.gltf_exporter_running:
# we force saving params
active_operator.will_save_settings = True
if active_operator.bl_idname == "EXPORT_SCENES_OT_auto_gltf":
# we force saving params
active_operator.will_save_settings = True
"""
print("matching")
try:
bpy.app.timers.unregister(cls.gltf_exporter_handler)
except:pass
bpy.app.timers.register(cls.gltf_exporter_handler, first_interval=3)
# we backup any existing gltf export settings, if there where any
scene = bpy.context.scene
if "glTF2ExportSettings" in scene:
existing_setting = scene["glTF2ExportSettings"]
cls.existing_gltf_settings = existing_setting
bpy.context.window_manager.gltf_exporter_running = True
else:
if bpy.context.window_manager.gltf_exporter_running:
bpy.context.window_manager.gltf_exporter_running = False"""
"""@classmethod
def gltf_exporter_handler(cls):
# FOr some reason, the active operator here is always None, so using a workaround
# active_operator = bpy.context.active_operator
print("here", bpy.context.window_manager.gltf_exporter_running)
if bpy.context.window_manager.gltf_exporter_running:
try:
dummy_file_path = "/home/ckaos/projects/bevy/Blender_bevy_components_worklflow/testing/bevy_example/assets/dummy.glb"
import os
if os.path.exists(dummy_file_path):
print("dummy file exists, assuming it worked")
os.unlink(dummy_file_path)
# get the parameters
scene = bpy.context.scene
if "glTF2ExportSettings" in scene:
settings = scene["glTF2ExportSettings"]
formatted_settings = dict(settings)
gltf_export_settings = bpy.data.texts[".blenvy_gltf_settings"] if ".blenvy_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".blenvy_gltf_settings")
#check if params have changed
bpy.context.window_manager.gltf_settings_changed = sorted(json.loads(gltf_export_settings.as_string()).items()) != sorted(formatted_settings.items())
print("gltf NEW settings", formatted_settings, "OLD settings", gltf_export_settings, "CHANGED ?", bpy.context.window_manager.gltf_settings_changed)
# now write new settings
gltf_export_settings.clear()
gltf_export_settings.write(json.dumps(formatted_settings))
# now reset the original gltf_settings
if getattr(cls, "existing_gltf_settings", None) is not None:
print("resetting original gltf settings")
scene["glTF2ExportSettings"] = cls.existing_gltf_settings
else:
print("no pre_existing settings")
if "glTF2ExportSettings" in scene:
del scene["glTF2ExportSettings"]
cls.existing_gltf_settings = None
except:pass
bpy.context.window_manager.gltf_exporter_running = False
return None
else:
try:
bpy.app.timers.unregister(cls.gltf_exporter_handler)
except:pass
return None
return 1"""
def invoke_override(self, context, event):
settings = context.scene.get(self.scene_key)
self.will_save_settings = False
if settings:
try:
for (k, v) in settings.items():
setattr(self, k, v)
self.will_save_settings = True
# Update filter if user saved settings
if hasattr(self, 'export_format'):
self.filter_glob = '*.glb' if self.export_format == 'GLB' else '*.gltf'
except (AttributeError, TypeError):
self.report({"ERROR"}, "Loading export settings failed. Removed corrupted settings")
del context.scene[self.scene_key]
import sys
preferences = bpy.context.preferences
for addon_name in preferences.addons.keys():
try:
if hasattr(sys.modules[addon_name], 'glTF2ExportUserExtension') or hasattr(sys.modules[addon_name], 'glTF2ExportUserExtensions'):
pass #exporter_extension_panel_unregister_functors.append(sys.modules[addon_name].register_panel())
except Exception:
pass
# self.has_active_exporter_extensions = len(exporter_extension_panel_unregister_functors) > 0
print("ovverride")
wm = context.window_manager
wm.fileselect_add(self)
return {'RUNNING_MODAL'}
from io_scene_gltf2 import (ExportGLTF2, GLTF_PT_export_main, GLTF_PT_export_include)
from io_scene_gltf2 import (ExportGLTF2, GLTF_PT_export_main,ExportGLTF2_Base, GLTF_PT_export_include)
import io_scene_gltf2 as gltf_exporter_original
#import io_scene_gltf2.GLTF_PT_export_data_scene as GLTF_PT_export_data_scene_original
"""
class GLTF_PT_export_data(gltf_exporter_original.GLTF_PT_export_data):
bl_space_type = 'FILE_BROWSER'
bl_region_type = 'TOOL_PROPS'
bl_label = "Data"
bl_parent_id = "GLTF_PT_auto_export_gltf"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
sfile = context.space_data
operator = sfile.active_operator
return operator.bl_idname == "EXPORT_SCENES_OT_auto_gltf"
class GLTF_PT_export_data_scene(gltf_exporter_original.GLTF_PT_export_data_scene):
bl_space_type = 'FILE_BROWSER'
bl_region_type = 'TOOL_PROPS'
bl_label = "Scene Graph"
bl_parent_id = "GLTF_PT_export_data"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
sfile = context.space_data
operator = sfile.active_operator
return operator.bl_idname == "EXPORT_SCENES_OT_auto_gltf"
def draw(self, context):
return super().draw(context)"""

View File

@ -86,7 +86,7 @@ class AutoExportTracker(PropertyGroup):
active_operator = getattr(bpy.context, 'active_operator' , None) active_operator = getattr(bpy.context, 'active_operator' , None)
if active_operator is not None: if active_operator is not None:
#print("Operator", active_operator.bl_label, active_operator.bl_idname) #print("Operator", active_operator.bl_label, active_operator.bl_idname)
if active_operator.bl_idname == "EXPORT_SCENE_OT_gltf" and active_operator.gltf_export_id == "gltf_auto_export": if active_operator.bl_idname == "EXPORT_SCENE_OT_gltf" and active_operator.gltf_export_id == "blenvy":
# we backup any existing gltf export settings, if there were any # we backup any existing gltf export settings, if there were any
scene = bpy.context.scene scene = bpy.context.scene
if "glTF2ExportSettings" in scene: if "glTF2ExportSettings" in scene:

View File

@ -21,7 +21,7 @@ def draw_settings_ui(layout, auto_export_settings):
op.use_active_collection_with_nested=True op.use_active_collection_with_nested=True
op.use_active_scene = True op.use_active_scene = True
op.filepath="____dummy____" op.filepath="____dummy____"
op.gltf_export_id = "gltf_auto_export" # we specify that we are in a special case op.gltf_export_id = "blenvy" # we specify that we are in a special case
section.prop(auto_export_settings, "export_scene_settings") section.prop(auto_export_settings, "export_scene_settings")

View File

@ -1,6 +0,0 @@
import rna_prop_ui
# fake way to make our operator's changes be visible to the change/depsgraph update handler in gltf_auto_export
def ping_depsgraph_update(object):
rna_prop_ui.rna_idprop_ui_create(object, "________temp", default=0)
rna_prop_ui.rna_idprop_ui_prop_clear(object, "________temp")

View File

@ -1,10 +0,0 @@
import bpy
import rna_prop_ui
# fake way to make our operator's changes be visible to the change/depsgraph update handler in gltf_auto_export
def ping_depsgraph_update(object=None):
if object == None:
object = bpy.data.scenes[0]
rna_prop_ui.rna_idprop_ui_create(object, "________temp", default=0)
rna_prop_ui.rna_idprop_ui_prop_clear(object, "________temp")
return None

View File

@ -26,7 +26,7 @@ class BLENVY_PT_SidePanel(bpy.types.Panel):
bl_label = "" bl_label = ""
bl_space_type = 'VIEW_3D' bl_space_type = 'VIEW_3D'
bl_region_type = 'UI' bl_region_type = 'UI'
bl_category = "Bevy" bl_category = "Blenvy"
#bl_context = "objectmode" #bl_context = "objectmode"
def draw_header(self, context): def draw_header(self, context):