diff --git a/Cargo.toml b/Cargo.toml index 4f6429b..c0d0cd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ bevy = { version = "0.10", default-features = false, features = [ "png", "x11", ] } +bevy_mod_gltf_patched = "0.2" [features] default = ["bevy_ui"] @@ -49,4 +50,8 @@ path = "examples/render_layers.rs" [[example]] name = "animated_fox" -path = "examples/animated_fox.rs" \ No newline at end of file +path = "examples/animated_fox.rs" + +[[example]] +name = "hollow" +path = "examples/hollow.rs" \ No newline at end of file diff --git a/README.md b/README.md index 088f1b9..6acb3db 100644 --- a/README.md +++ b/README.md @@ -37,12 +37,18 @@ enabled. cargo run --example render_layers ``` -An animated jointed model with an outline. +An animated jointed glTF model with an outline. ```shell cargo run --example animated_fox ``` +A glTF model with pre-baked outline normals. + +```shell +cargo run --example hollow +``` + ## Versions | This Version | Bevy version | diff --git a/assets/hollow.glb b/assets/hollow.glb new file mode 100644 index 0000000..263d688 Binary files /dev/null and b/assets/hollow.glb differ diff --git a/examples/hollow.rs b/examples/hollow.rs new file mode 100644 index 0000000..c12dcff --- /dev/null +++ b/examples/hollow.rs @@ -0,0 +1,126 @@ +use std::f32::consts::{PI, TAU}; + +use bevy::{prelude::*, scene::SceneInstance, window::close_on_esc}; +use bevy_mod_gltf_patched::GltfPlugin; +use bevy_mod_outline::*; + +fn main() { + App::new() + // Disable built-in glTF plugin + .add_plugins(DefaultPlugins.build().disable::()) + // Register outline normal vertex attribute with bevy_mod_gltf_patched + .add_plugin( + GltfPlugin::default() + .add_custom_vertex_attribute("_OUTLINE_NORMAL", ATTRIBUTE_OUTLINE_NORMAL), + ) + .add_plugin(OutlinePlugin) + .insert_resource(AmbientLight { + color: Color::WHITE, + brightness: 1.0, + }) + .add_startup_system(setup) + .add_system(setup_scene_once_loaded) + .add_system(rotates) + .add_system(rotates_hue) + .add_system(close_on_esc) + .run(); +} + +#[derive(Component)] +struct Rotates; + +#[derive(Component)] +struct RotatesHue; + +fn setup(mut commands: Commands, asset_server: Res) { + // Camera + commands.spawn(Camera3dBundle { + transform: Transform::from_xyz(20.0, 20.0, 30.0) + .looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y), + ..default() + }); + + // Light + commands.spawn(DirectionalLightBundle { + transform: Transform::from_rotation(Quat::from_euler(EulerRot::ZYX, 0.0, 1.0, -PI / 4.)), + directional_light: DirectionalLight { + shadows_enabled: true, + ..default() + }, + ..default() + }); + + // Hollow + commands + .spawn(SceneBundle { + scene: asset_server.load("hollow.glb#Scene0"), + ..default() + }) + .insert(Rotates) + .insert(ComputedOutlineDepth::default()); +} + +// Once the scene is loaded, start the animation and add an outline +fn setup_scene_once_loaded( + mut commands: Commands, + scene_query: Query<&SceneInstance>, + scene_manager: Res, + name_query: Query<&Name, With>>, + mut done: Local, +) { + if !*done { + if let Ok(scene) = scene_query.get_single() { + if scene_manager.instance_is_ready(**scene) { + for entity in scene_manager.iter_instance_entities(**scene) { + commands + .entity(entity) + .insert(OutlineBundle { + outline: OutlineVolume { + visible: true, + width: 7.5, + colour: Color::BLUE, + }, + stencil: OutlineStencil { + enabled: true, + offset: 0.0, + }, + ..default() + }) + .insert(InheritOutlineDepth); + if let Ok(name) = name_query.get(entity) { + if name.as_str() == "inside" { + commands.entity(entity).insert(RotatesHue); + } + } + } + *done = true; + } + } + } +} + +fn rotates(mut query: Query<&mut Transform, With>, timer: Res