Blender_bevy_components_wor.../crates/bevy_gltf_blueprints
Mark Moissette e1aa510457
feat(materials): Materials libraries tooling & bevy code for material/texture reuse (#71)
* updates both gltf_auto_export & bevy_gltf_blueprints to avoid duplicating common materials across blueprints
* feat(tools/gltf_auto_export): added materials library export !
 * export all materials in use by blueprints to a separate temporary scene with cubes (for now)
   with the materials assigned
 * injecting MaterialInfo components to each blueprint above with Material name + library name
 * generated gltf is named based on the project/blend file, so multiple blend file projects
   can each have their own material libraries
 * added preferences & ui & handling to be able to toggle material library exports
* feat(bevy_gltf_blueprints): added support for materials library!
 * material injection (toggleable via the plugin configuration)
 * added example
 * added materials library + texture files + updated assets
 * added physics debug toggling
* updated documentation
* closes #63
2023-12-12 13:21:53 +01:00
..
src feat(materials): Materials libraries tooling & bevy code for material/texture reuse (#71) 2023-12-12 13:21:53 +01:00
Cargo.toml feat(materials): Materials libraries tooling & bevy code for material/texture reuse (#71) 2023-12-12 13:21:53 +01:00
LICENSE.md fix(): various Fixes and tweaks (#7) 2023-09-28 16:53:21 +02:00
LICENSE_APACHE.md feat(): Blueprints, crates, enhanced Blender tooling & more (#5) 2023-09-28 14:10:45 +02:00
LICENSE_MIT.md feat(): Blueprints, crates, enhanced Blender tooling & more (#5) 2023-09-28 14:10:45 +02:00
README.md feat(materials): Materials libraries tooling & bevy code for material/texture reuse (#71) 2023-12-12 13:21:53 +01:00

README.md

Crates.io Docs License Bevy tracking

bevy_gltf_blueprints

Built upon bevy_gltf_components this crate adds the ability to define Blueprints/Prefabs for Bevy inside gltf files and spawn them in Bevy.

  • Allows you to create lightweight levels, where all assets are different gltf files and loaded after the main level is loaded
  • Allows you to spawn different entities from gtlf files at runtime in a clean manner, including simplified animation support !

A blueprint is a set of overrideable components + a hierarchy: ie

* just a Gltf file with Gltf_extras specifying components 
* a component called BlueprintName

Particularly useful when using Blender as an editor for the Bevy game engine, combined with the Blender plugin that does a lot of the work for you

Usage

Here's a minimal usage example:

# Cargo.toml
[dependencies]
bevy="0.12"
bevy_gltf_blueprints = { version = "0.4"} 

use bevy::prelude::*;
use bevy_gltf_blueprints::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(BlueprintsPlugin)

        .run();
}

// not shown here: any other setup that is not specific to blueprints

fn spawn_blueprint(
    mut commands: Commands,
    keycode: Res<Input<KeyCode>>,
){
    if keycode.just_pressed(KeyCode::S) {
        let new_entity = commands.spawn((
            BlueprintName("Health_Pickup".to_string()), // mandatory !!
            SpawnHere, // mandatory !!
            TransformBundle::from_transform(Transform::from_xyz(x, 2.0, y)), // VERY important !!
            // any other component you want to insert
        ));
    }
}

Installation

Add the following to your [dependencies] section in Cargo.toml:

bevy_gltf_blueprints = "0.4"

Or use cargo add:

cargo add bevy_gltf_blueprints

Setup

use bevy::prelude::*;
use bevy_gltf_blueprints::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugin(BlueprintsPlugin)

        .run();
}

you may want to configure your "library"/"blueprints" settings:

use bevy::prelude::*;
use bevy_gltf_blueprints::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugin(
             BlueprintsPlugin{
                library_folder: "advanced/models/library".into() // replace this with your blueprints library path , relative to the assets folder,
                format: GltfFormat::GLB,// optional, use either  format: GltfFormat::GLB, or  format: GltfFormat::GLTF, or  ..Default::default() if you want to keep the default .glb extension, this sets what extensions/ gltf files will be looked for by the library
                aabbs: true, // defaults to false, enable this to automatically calculate aabb for the scene/blueprint
                material_library: true,  // defaults to false, enable this to enable automatic injection of materials from material library files
                material_library_folder: "materials".into() //defaults to "materials" the folder to look for for the material files
                ..Default::default()
            }
        )
        .run();
}

Spawning entities from blueprints

You can spawn entities from blueprints like this:

commands.spawn((
    BlueprintName("Health_Pickup".to_string()), // mandatory !!
    SpawnHere, // mandatory !!
    TransformBundle::from_transform(Transform::from_xyz(x, 2.0, y)), // VERY important !!
    // any other component you want to insert
))

Once spawning of the actual entity is done, the spawned Blueprint will be gone/merged with the contents of Blueprint !

Important : you can add or override components present inside your Blueprint when spawning the BluePrint itself: ie

Adding components not specified inside the blueprint

you can just add any additional components you need when spawning :

commands.spawn((
    BlueprintName("Health_Pickup".to_string()),
    SpawnHere,
    TransformBundle::from_transform(Transform::from_xyz(x, 2.0, y)),
    // from Rapier/bevy_xpbd: this means the entity will also have a velocity component when inserted into the world
    Velocity {
        linvel: Vec3::new(vel_x, vel_y, vel_z),
        angvel: Vec3::new(0.0, 0.0, 0.0),
      },
))

Overriding components specified inside the blueprint

any component you specify when spawning the Blueprint that is also specified within the Blueprint will override that component in the final spawned entity

for example

commands.spawn((
    BlueprintName("Health_Pickup".to_string()),
    SpawnHere,
    TransformBundle::from_transform(Transform::from_xyz(x, 2.0, y)),
    HealthPowerUp(20)// if this is component is also present inside the "Health_Pickup" blueprint, that one will be replaced with this component during spawning
))

BluePrintBundle

There is also a bundle for convenience , which just has

  • a BlueprintName component
  • a SpawnHere component
  • a TransformBundle sub-bundle (so we know where to spawn)

BluePrintBundle

SystemSet

the ordering of systems is very important !

For example to replace your proxy components (stand-in components when you cannot/ do not want to use real components in the gltf file) with actual ones, which should happen AFTER the Blueprint based spawning,

so bevy_gltf_blueprints provides a SystemSet for that purpose:GltfBlueprintsSet

Typically , the order of systems should be

bevy_gltf_components (GltfComponentsSet::Injection) => bevy_gltf_blueprints (GltfBlueprintsSet::Spawn, GltfBlueprintsSet::AfterSpawn) => replace_proxies

see https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/basic for how to set it up correctly

Animation

bevy_gltf_blueprints provides some lightweight helpers to deal with animations stored in gltf files

  • an Animations component that gets inserted into spawned (root) entities that contains a hashmap of all animations contained inside that entity/gltf file . (this is a copy of the named_animations inside Bevy's gltf structures )
  • an AnimationPlayerLink component that gets inserted into spawned (root) entities, to make it easier to trigger/ control animations than it usually is inside Bevy + Gltf files

The workflow for animations is as follows:

  • create a gltf file with animations (using Blender & co) as you would normally do
  • inside Bevy, use the bevy_gltf_blueprints boilerplate (see sections above), no specific setup beyond that is required
  • to control the animation of an entity, you need to query for entities that have both AnimationPlayerLink and Animations components (added by bevy_gltf_blueprints) AND entities with the AnimationPlayer component

For example:

// example of changing animation of entities based on proximity to the player, for "fox" entities (Tag component)
pub fn animation_change_on_proximity_foxes(
    players: Query<&GlobalTransform, With<Player>>,
    animated_foxes: Query<(&GlobalTransform, &AnimationPlayerLink, &Animations ), With<Fox>>,

    mut animation_players: Query<&mut AnimationPlayer>,

){
    for player_transforms in players.iter() {
        for (fox_tranforms, link, animations) in animated_foxes.iter() {
            let distance = player_transforms
                .translation()
                .distance(fox_tranforms.translation());
            let mut anim_name = "Walk"; 
            if distance < 8.5 {
                anim_name = "Run"; 
            }
            else if distance >= 8.5 && distance < 10.0{
                anim_name = "Walk";
            }
            else if distance >= 10.0 && distance < 15.0{
                anim_name = "Survey";
            }
            // now play the animation based on the chosen animation name
            let mut animation_player = animation_players.get_mut(link.0).unwrap();
            animation_player.play_with_transition(
                animations.named_animations.get(anim_name).expect("animation name should be in the list").clone(), 
                Duration::from_secs(3)
            ).repeat();
        }
    }
}

see https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/animation for how to set it up correctly

particularly from https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/animation/game/in_game.rs#86 onward

Materials

You have the option of 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 56 times !!

you can configure this with the settings:

material_library: true  // defaults to false, enable this to enable automatic injection of materials from material library files
material_library_folder: "materials".into() //defaults to "materials" the folder to look for for the material files

Important! you must take care of preloading your material librairy gltf files in advance, using for example bevy_asset_loadersince bevy_gltf_blueprints currently does NOT take care of loading those at runtime

see https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/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

Examples

https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/basic

https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/basic_xpbd_physics

https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/animation

https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/multiple_levels

https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/materials

Compatible Bevy versions

The main branch is compatible with the latest Bevy release, while the branch bevy_main tries to track the main branch of Bevy (PRs updating the tracked commit are welcome).

Compatibility of bevy_gltf_blueprints versions:

bevy_gltf_blueprints bevy
0.3 - 0.4 0.12
0.1 - 0.2 0.11
branch main 0.12
branch bevy_main main

License

This crate, all its code, contents & assets is Dual-licensed under either of