From 1f2401e7aadbabde16f2f80aab04395c9ae0d3ec Mon Sep 17 00:00:00 2001 From: Peter Hayman Date: Tue, 29 Oct 2024 16:54:04 +1100 Subject: [PATCH] wip: combine arm with animation --- .../src/scenes/spatial/inverse_kinematics.rs | 4 - .../src/inverse_kinematics/ik_spawner.rs | 17 ++-- crates/emby/examples/arm_animation.rs | 70 +--------------- crates/emby/examples/emote_arm.rs | 21 +++++ crates/emby/examples/interaction.rs | 23 +----- crates/emby/examples/render_texture.rs | 15 +--- crates/emby/src/emote_agent/render_texture.rs | 10 ++- crates/emby/src/plugins/emby_plugin.rs | 10 ++- crates/emby/src/scenes/barbarian.rs | 40 --------- crates/emby/src/scenes/emote_arm.rs | 77 +++++++++++++++++ crates/emby/src/scenes/mod.rs | 3 + crates/emby/src/scenes/phone_texture.rs | 82 ++++++++++++------- 12 files changed, 180 insertions(+), 192 deletions(-) create mode 100644 crates/emby/examples/emote_arm.rs create mode 100644 crates/emby/src/scenes/emote_arm.rs diff --git a/crates/beet_examples/src/scenes/spatial/inverse_kinematics.rs b/crates/beet_examples/src/scenes/spatial/inverse_kinematics.rs index dfdcc7f4..c10f6ab4 100644 --- a/crates/beet_examples/src/scenes/spatial/inverse_kinematics.rs +++ b/crates/beet_examples/src/scenes/spatial/inverse_kinematics.rs @@ -15,10 +15,6 @@ pub fn spawn_ik_camera(mut commands: Commands) { pub fn spawn_arm_with_keyboard_target(mut commands: Commands) { let target = spawn_keyboard_target(&mut commands); - spawn_arm(&mut commands, target); -} - -pub fn spawn_arm(commands: &mut Commands, target: Entity) { commands.spawn(( Name::new("scene"), BundlePlaceholder::Gltf("robot-arm/robot-arm.glb".into()), diff --git a/crates/beet_spatial/src/inverse_kinematics/ik_spawner.rs b/crates/beet_spatial/src/inverse_kinematics/ik_spawner.rs index fc8ebfae..542f7da4 100644 --- a/crates/beet_spatial/src/inverse_kinematics/ik_spawner.rs +++ b/crates/beet_spatial/src/inverse_kinematics/ik_spawner.rs @@ -49,11 +49,8 @@ pub fn ik_spawner( }; let Some(items) = - find_by_name_recursive(&child_nodes_query, &arm_root.3, vec![ - "Base", "Segment1", "Segment2", "Segment3", - "Gripper", - // "Target", - // "Phone", + map_names_to_query_entries(&child_nodes_query, &arm_root.3, vec![ + "Base", "Segment1", "Segment2", "Segment3", "Gripper", ]) else { return; @@ -64,9 +61,6 @@ pub fn ik_spawner( let segment2 = items[2]; let segment3 = items[3]; let gripper = items[4]; - // let target = items[5]; - // let phone = items[6]; - // hack until globaltransform calculated in sceneinstanceready let scale = transform.scale.x; @@ -83,8 +77,6 @@ pub fn ik_spawner( IkSegment::DEG_360.with_len(segment3_to_gripper), ); - println!("ik: {:?}", ik); - let ik_transforms = IkArm4DofTransforms::new( ik, **target, base.0, segment1.0, segment2.0, segment3.0, ); @@ -99,8 +91,9 @@ pub fn ik_spawner( // )); } -/// Provided a list of names, each being a child of the previous, returns that list of entities. -fn find_by_name_recursive<'a>( +/// Provided a list of names, each being a child of the previous, +/// returns that list of entities. +fn map_names_to_query_entries<'a>( query: &'a Query<(Entity, &Name, &Transform, &Children)>, children: &Children, names: Vec<&str>, diff --git a/crates/emby/examples/arm_animation.rs b/crates/emby/examples/arm_animation.rs index f5485879..1863f4de 100644 --- a/crates/emby/examples/arm_animation.rs +++ b/crates/emby/examples/arm_animation.rs @@ -1,11 +1,6 @@ -use beet::prelude::*; use beet_examples::prelude::*; -use beetmash::prelude::*; -use bevy::color::palettes::tailwind; use bevy::prelude::*; use emby::prelude::*; -use forky::prelude::TransformExt; -use std::time::Duration; pub fn main() { App::new() @@ -17,71 +12,8 @@ pub fn main() { beetmash::core::scenes::ground_3d, beet_examples::scenes::flow::beet_debug_start_and_stop, beet_examples::scenes::spatial::spawn_ik_camera, - setup, + emby::scenes::emote_arm, ), ) .run(); } - - -fn setup(mut commands: Commands) { - let mut target = Entity::PLACEHOLDER; - let pos_happy = Vec3::new(0., 3., 0.); - let pos_idle = Vec3::new(0., 2., 0.); - - let transform_idle = Transform::from_translation(pos_idle) - .with_scale_value(2.) - .looking_to(Dir3::NEG_Y, Dir3::X); - - - - let target_parent = commands - // target parent is used to define offset transform - .spawn((Name::new("Target Parent"), transform_idle)) - .with_children(|parent| { - target = parent - .spawn((Name::new("Target"), BundlePlaceholder::Pbr { - mesh: Sphere::new(0.2).into(), - material: MaterialPlaceholder::unlit(tailwind::BLUE_500), - })) - .id(); - }) - .id(); - commands - .spawn(( - Name::new("Behavior"), - RunOnSpawn, - Repeat::default(), - SequenceFlow, - )) - .with_children(|parent| { - parent.spawn(( - Name::new("New Pos"), - InsertOnRun::new(transform_idle).with_target(target_parent), - TargetAgent(target), - SetCurveOnRun::default(), - PlayProceduralAnimation::default() - // .with_meter_per_second(1.), - .with_duration_secs(2.), - )); - parent.spawn(( - Name::new("Idle Pause"), - TriggerInDuration::with_range( - OnRunResult::success(), - Duration::from_secs(1)..Duration::from_secs(4), - ), - )); - parent.spawn(( - Name::new("Happy"), - TargetAgent(target_parent), - SetCurveOnRun::PingPongPause { - target: pos_happy, - pause: 1., - func: EaseFunction::CubicInOut, - }, - PlayProceduralAnimation::default().with_duration_secs(4.), - )); - }); - - beet_examples::scenes::spatial::spawn_arm(&mut commands, target); -} diff --git a/crates/emby/examples/emote_arm.rs b/crates/emby/examples/emote_arm.rs new file mode 100644 index 00000000..fe57ebc1 --- /dev/null +++ b/crates/emby/examples/emote_arm.rs @@ -0,0 +1,21 @@ +use beet_examples::prelude::*; +use bevy::prelude::*; +use emby::prelude::*; + +pub fn main() { + App::new() + .add_plugins((crate_test_beet_example_plugin, EmbyPlugin)) + .add_systems( + Startup, + ( + beetmash::core::scenes::lighting_3d, + beetmash::core::scenes::ground_3d, + beet_examples::scenes::flow::beet_debug_start_and_stop, + beet_examples::scenes::spatial::spawn_ik_camera, + emby::scenes::emote_arm, + emby::scenes::spawn_barbarian, + emby::scenes::phone_texture_camera_3d, + ), + ) + .run(); +} diff --git a/crates/emby/examples/interaction.rs b/crates/emby/examples/interaction.rs index b099349a..68204ecd 100644 --- a/crates/emby/examples/interaction.rs +++ b/crates/emby/examples/interaction.rs @@ -17,31 +17,12 @@ fn main() { emby::scenes::spawn_barbarian, ), ) - // .add_systems(Update,disable_barbarian) .run(); } - -fn setup(mut commands: Commands, asset_server: Res) { +fn setup(mut commands: Commands) { commands.spawn(( Camera3d::default(), - Transform::from_xyz(0., 1.6, 5.), // .looking_at(Vec3::ZERO, Vec3::Y), + Transform::from_xyz(0., 1.6, 5.) )); - - commands.insert_resource(EmojiMap::new(&asset_server)); } - - - -// fn emoji(mut commands: Commands, asset_server: Res) { -// commands.spawn(( -// Name::new("PhoneTexture"), -// SpriteBundle { -// // transform: Transform::from_scale(Vec3::splat(10.)), -// // transform: Transform::default().with_scale(Vec3::splat(10.)), -// texture: asset_server.load(EmojiMap::file_path(EmojiMap::HAPPY)), -// ..default() -// }, -// RenderLayers::layer(RENDER_TEXTURE_LAYER), -// )); -// } diff --git a/crates/emby/examples/render_texture.rs b/crates/emby/examples/render_texture.rs index 3d852fd0..ff228530 100644 --- a/crates/emby/examples/render_texture.rs +++ b/crates/emby/examples/render_texture.rs @@ -2,8 +2,6 @@ use beet::prelude::*; use beet_examples::prelude::*; use bevy::prelude::*; use emby::prelude::*; -// use bevy::render::view::RenderLayers; - fn main() { App::new() @@ -17,18 +15,13 @@ fn main() { beetmash::core::scenes::ground_3d, beetmash::core::scenes::ui_terminal_input, emby::scenes::spawn_barbarian, + emby::scenes::phone_texture_camera_3d, ), ) - // .add_systems(Update,disable_barbarian) + .add_observer(emby::scenes::add_phone_render_texture_to_arm) .run(); } - -fn setup(mut commands: Commands, asset_server: Res) { - commands.spawn(( - Camera3d::default(), - Transform::from_xyz(0., 1.6, 5.), // .looking_at(Vec3::ZERO, Vec3::Y), - )); - - commands.insert_resource(EmojiMap::new(&asset_server)); +fn setup(mut commands: Commands) { + commands.spawn((Camera3d::default(), Transform::from_xyz(0., 1.6, 5.))); } diff --git a/crates/emby/src/emote_agent/render_texture.rs b/crates/emby/src/emote_agent/render_texture.rs index b35f6615..fc943de8 100644 --- a/crates/emby/src/emote_agent/render_texture.rs +++ b/crates/emby/src/emote_agent/render_texture.rs @@ -1,4 +1,3 @@ -use beetmash::prelude::HandleWrapper; use bevy::prelude::*; use bevy::render::render_resource::*; use bevy::render::view::RenderLayers; @@ -12,6 +11,10 @@ pub struct RenderTexture { pub handle: Handle, } +impl RenderTexture { + pub fn new(handle: Handle) -> Self { Self { handle } } +} + /// The layer used for rendering to a texture instead of the main camera. pub const RENDER_TEXTURE_LAYER: usize = 1; @@ -56,10 +59,11 @@ pub fn render_texture_bundle( Camera { order: -1, target: image_handle.into(), - clear_color: Color::WHITE.into(), + clear_color: Color::srgba_u8(0, 0, 0, 0).into(), + // clear_color: Color::WHITE.into(), ..default() }, RenderLayers::layer(RENDER_TEXTURE_LAYER), - HandleWrapper(material_handle), + RenderTexture::new(material_handle), ) } diff --git a/crates/emby/src/plugins/emby_plugin.rs b/crates/emby/src/plugins/emby_plugin.rs index 2dddf6c5..33b004bc 100644 --- a/crates/emby/src/plugins/emby_plugin.rs +++ b/crates/emby/src/plugins/emby_plugin.rs @@ -6,8 +6,12 @@ pub struct EmbyPlugin; impl Plugin for EmbyPlugin { fn build(&self, app: &mut App) { - /*-*/ - - app.add_plugins(emote_agent_plugin); + app.add_plugins(emote_agent_plugin) + .add_systems(Startup, setup) + .add_observer(crate::scenes::add_phone_render_texture_to_arm); } } + +fn setup(mut commands: Commands, asset_server: Res) { + commands.insert_resource(EmojiMap::new(&asset_server)); +} diff --git a/crates/emby/src/scenes/barbarian.rs b/crates/emby/src/scenes/barbarian.rs index d0832cf0..062daecb 100644 --- a/crates/emby/src/scenes/barbarian.rs +++ b/crates/emby/src/scenes/barbarian.rs @@ -68,46 +68,6 @@ pub fn spawn_barbarian(mut commands: Commands) { - - -// pub fn disable_barbarian( -// mut commands: Commands, -// mut events: EventReader>, -// query: Populated<(Entity, &SceneRoot)>, -// names: Query<&Name>, -// children: Query<&Children>, -// ) { -// for ev in events.read() { -// let AssetEvent::LoadedWithDependencies { id } = ev else { -// continue; -// }; -// let Some((entity, _)) = -// query.iter().find(|(_, scene)| scene.id() == *id) -// else { -// continue; -// }; - -// let to_disable: HashSet<&'static str> = -// vec!["Mug"].into_iter().collect(); - -// for entity in children.iter_descendants(entity) { -// if let Ok(name) = names.get(entity) { -// println!("it has name: {}", name); -// if to_disable.contains(name.as_str()) { -// commands.entity(entity).insert(Visibility::Hidden); -// } -// }else{ -// println!("it has no name"); -// } -// } -// } -// } - - - - - - /* # meshes diff --git a/crates/emby/src/scenes/emote_arm.rs b/crates/emby/src/scenes/emote_arm.rs new file mode 100644 index 00000000..897859f0 --- /dev/null +++ b/crates/emby/src/scenes/emote_arm.rs @@ -0,0 +1,77 @@ +use beet::prelude::*; +use beetmash::prelude::*; +use bevy::color::palettes::tailwind; +use bevy::prelude::*; +use forky::prelude::TransformExt; +use std::time::Duration; + + +pub fn emote_arm(mut commands: Commands) { + let mut target = Entity::PLACEHOLDER; + let pos_happy = Vec3::new(0., 3., 0.); + let pos_idle = Vec3::new(0., 2., 0.); + + let transform_idle = Transform::from_translation(pos_idle) + .with_scale_value(2.) + .looking_to(Dir3::NEG_Y, Dir3::X); + + + + let target_parent = commands + // target parent is used to define offset transform + .spawn((Name::new("Target Parent"), transform_idle)) + .with_children(|parent| { + target = parent + .spawn((Name::new("Target"), BundlePlaceholder::Pbr { + mesh: Sphere::new(0.2).into(), + material: MaterialPlaceholder::unlit(tailwind::BLUE_500), + })) + .id(); + }) + .id(); + + + commands.spawn(( + Name::new("Emote Arm"), + BundlePlaceholder::Gltf("robot-arm/robot-arm-phone.glb".into()), + Transform::from_scale(Vec3::splat(10.)), + TargetAgent(target), + IkSpawner::default(), + )); + + commands + .spawn(( + Name::new("Behavior"), + RunOnSpawn, + Repeat::default(), + SequenceFlow, + )) + .with_children(|parent| { + parent.spawn(( + Name::new("New Pos"), + InsertOnRun::new(transform_idle).with_target(target_parent), + TargetAgent(target), + SetCurveOnRun::default(), + PlayProceduralAnimation::default() + // .with_meter_per_second(1.), + .with_duration_secs(2.), + )); + parent.spawn(( + Name::new("Idle Pause"), + TriggerInDuration::with_range( + OnRunResult::success(), + Duration::from_secs(1)..Duration::from_secs(4), + ), + )); + parent.spawn(( + Name::new("Happy"), + TargetAgent(target_parent), + SetCurveOnRun::PingPongPause { + target: pos_happy, + pause: 1., + func: EaseFunction::CubicInOut, + }, + PlayProceduralAnimation::default().with_duration_secs(4.), + )); + }); +} diff --git a/crates/emby/src/scenes/mod.rs b/crates/emby/src/scenes/mod.rs index 059b4ed7..e84784ea 100644 --- a/crates/emby/src/scenes/mod.rs +++ b/crates/emby/src/scenes/mod.rs @@ -1,6 +1,9 @@ pub mod barbarian; #[allow(unused_imports)] pub use self::barbarian::*; +pub mod emote_arm; +#[allow(unused_imports)] +pub use self::emote_arm::*; pub mod phone_texture; #[allow(unused_imports)] pub use self::phone_texture::*; diff --git a/crates/emby/src/scenes/phone_texture.rs b/crates/emby/src/scenes/phone_texture.rs index 746d7ab7..6beb9d39 100644 --- a/crates/emby/src/scenes/phone_texture.rs +++ b/crates/emby/src/scenes/phone_texture.rs @@ -1,46 +1,70 @@ use crate::prelude::*; +use bevy::pbr::CascadeShadowConfigBuilder; use bevy::prelude::*; use bevy::render::view::RenderLayers; +use bevy::scene::SceneInstanceReady; +use std::f32::consts::PI; -pub fn phone_texture_emoji( - mut commands: Commands, - asset_server: Res, - mut texture_atlas_layouts: ResMut>, -) { - let layout = - TextureAtlasLayout::from_grid(UVec2::splat(72), 16, 10, None, None); - let texture_atlas_layout = texture_atlas_layouts.add(layout); - commands.spawn(( - Name::new("PhoneTexture"), - Transform::from_scale(Vec3::splat(10.)), - // transform: Transform::default().with_scale(Vec3::splat(10.)), - Sprite::from_image(asset_server.load("openmoji/smileys-emotion.png")), - TextureAtlas { - layout: texture_atlas_layout, - index: 0, - }, - RenderLayers::layer(RENDER_TEXTURE_LAYER), - )); -} - -pub fn phone_texture_camera_2d( +pub fn phone_texture_camera_3d( mut commands: Commands, mut images: ResMut>, mut materials: ResMut>, ) { commands.spawn(( render_texture_bundle(&mut images, &mut materials), - // Camera3d::default(), - Camera2d, + Camera3d::default(), + // ClearColorConfig::Custom(Color::srgba(0., 0., 0., 0.)), + Transform::from_xyz(0., 1.9, 3.), )); } -pub fn phone_texture_camera_3d( + + +pub fn add_phone_render_texture_to_arm( + trigger: Trigger, + names: Query<&Name>, + children: Query<&Children>, mut commands: Commands, - mut images: ResMut>, - mut materials: ResMut>, + mut meshes: ResMut>, + query: Single<&RenderTexture>, ) { + let Some(phone_entity) = + children.iter_descendants(trigger.entity()).find(|c| { + names + .get(*c) + .map(|n| n.as_str() == "Phone") + .unwrap_or(false) + }) + else { + return; + }; + + + + commands.entity(phone_entity).with_child(( + Name::new("Phone Texture"), + Transform::from_xyz(0., 0.1, 0.).looking_to(Dir3::Z, Dir3::Y), + Mesh3d(meshes.add(Plane3d::new(Vec3::Y, Vec2::splat(0.9)))), + MeshMaterial3d(query.handle.clone()), + )); + // Light commands.spawn(( - render_texture_bundle(&mut images, &mut materials), - Camera3d::default(), + DirectionalLight { + shadows_enabled: true, + ..default() + }, + Transform::from_rotation(Quat::from_euler( + EulerRot::ZYX, + 0.0, + 1.0, + -PI / 4., + )), + RenderLayers::layer(RENDER_TEXTURE_LAYER), + // temp hack to get lights in render texture + CascadeShadowConfigBuilder { + first_cascade_far_bound: 20.0, + maximum_distance: 40.0, + ..default() + } + .build(), )); }