Skip to content

Commit

Permalink
wip: procedural animation
Browse files Browse the repository at this point in the history
  • Loading branch information
mrchantey committed Oct 20, 2024
1 parent e29426d commit 129e4bd
Show file tree
Hide file tree
Showing 10 changed files with 244 additions and 16 deletions.
18 changes: 7 additions & 11 deletions crates/beet_examples/src/emote_agent/render_texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,16 @@ pub struct RenderTexture {
pub const RENDER_TEXTURE_LAYER: usize = 1;


pub fn create_render_camera(
mut commands: Commands,
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
pub fn render_texture_bundle(
images: &mut Assets<Image>,
materials: &mut Assets<StandardMaterial>,
) -> impl Bundle {
let size = Extent3d {
width: 512,
height: 512,
..default()
};

// This is the texture that will be rendered to.
let mut image = Image {
texture_descriptor: TextureDescriptor {
label: None,
Expand All @@ -42,7 +40,6 @@ pub fn create_render_camera(
},
..default()
};

// fill image.data with zeroes
image.resize(size);

Expand All @@ -54,8 +51,7 @@ pub fn create_render_camera(
..default()
});

commands.spawn((
Camera2d,
(
Camera {
order: -1,
target: image_handle.into(),
Expand All @@ -64,5 +60,5 @@ pub fn create_render_camera(
},
RenderLayers::layer(RENDER_TEXTURE_LAYER),
material_handle,
));
}
)
}
4 changes: 2 additions & 2 deletions crates/beet_examples/src/emote_agent/scenes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ pub use self::barbarian::*;
pub mod inverse_kinematics;
#[allow(unused_imports)]
pub use self::inverse_kinematics::*;
pub mod phone_screen;
pub mod phone_texture;
#[allow(unused_imports)]
pub use self::phone_screen::*;
pub use self::phone_texture::*;
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::prelude::*;
use bevy::prelude::*;
use bevy::render::view::RenderLayers;

pub fn phone_screen(
pub fn phone_texture(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut texture_atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
Expand All @@ -25,3 +25,15 @@ pub fn phone_screen(
RenderLayers::layer(RENDER_TEXTURE_LAYER),
));
}

pub fn phone_texture_camera(
mut commands: Commands,
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
commands.spawn((
render_texture_bundle(&mut images, &mut materials),
// Camera3d::default(),
Camera2d,
));
}
2 changes: 2 additions & 0 deletions crates/beet_spatial/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pub mod animation;
#[cfg(feature = "assets")]
pub mod asset_actions;
pub mod procedural_animation;
pub mod inverse_kinematics;
pub mod movement;
pub mod plugins;
Expand All @@ -16,6 +17,7 @@ pub mod prelude {
pub use crate::animation::*;
#[cfg(feature = "assets")]
pub use crate::asset_actions::*;
pub use crate::procedural_animation::*;
pub use crate::inverse_kinematics::*;
pub use crate::movement::*;
pub use crate::plugins::*;
Expand Down
12 changes: 12 additions & 0 deletions crates/beet_spatial/src/procedural_animation/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
pub mod play_procedural_animation;
#[allow(unused_imports)]
pub use self::play_procedural_animation::*;
pub mod procedural_animation_plugin;
#[allow(unused_imports)]
pub use self::procedural_animation_plugin::*;
pub mod procedural_animation_shape;
#[allow(unused_imports)]
pub use self::procedural_animation_shape::*;
pub mod procedural_animation_speed;
#[allow(unused_imports)]
pub use self::procedural_animation_speed::*;
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use crate::prelude::*;
use beet_flow::prelude::*;
use bevy::animation::RepeatAnimation;
use bevy::prelude::*;


#[derive(Debug, Clone, PartialEq, Component, Reflect, Action)]
#[observers(play_procedural_animation)]
#[reflect(Default, Component, ActionMeta)]
pub struct PlayProceduralAnimation {
pub shape: ProceduralAnimationShape,
pub speed: ProceduralAnimationSpeed,
pub repeat: RepeatAnimation,
pub num_animations: u32,
pub last_t: f32,
}

impl Default for PlayProceduralAnimation {
fn default() -> Self {
Self {
shape:default(),
repeat: default(),
speed: default(),
num_animations: 0,
last_t: 0.0,
}
}
}

impl PlayProceduralAnimation {
pub fn get_fraction(&self,time:Res<Time>) -> f32 {
match self.speed{
ProceduralAnimationSpeed::MetersPerSecond(mps) => mps * time.delta_seconds(),
ProceduralAnimationSpeed::FractionPerSecond(fps) => fps,
}
}

}

fn play_procedural_animation(
trigger: Trigger<OnRun>,
time:Res<Time>,
mut transforms: Query<&mut Transform>,
mut query: Query<(&mut PlayProceduralAnimation, &TargetAgent)>,
) {
let (mut play_procedural_animation, target_agent) = query
.get_mut(trigger.entity())
.expect(expect_action::ACTION_QUERY_MISSING);

let mut transform = transforms
.get_mut(target_agent.0)
.expect(expect_action::TARGET_MISSING);

// let t =

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use crate::prelude::*;
use beet_flow::prelude::*;
use bevy::prelude::*;


pub fn procedural_animation_plugin(app: &mut App) {
app.add_plugins(ActionPlugin::<(
InsertOnTrigger<OnRun, PlayProceduralAnimation>,
)>::default());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use bevy::prelude::*;

pub trait ProceduralAnimationStrategy {
/// For a given value between 0 (inclusive) and 1 (not inclusive), return a position.
///
/// # Panics
/// May panic if `t` is:
/// - less than zero
/// - equal to or greater than 1
fn get_position(&self, t: f32) -> Vec3;
/// Sum of the lengths of all segments.
/// For some shapes this may be an approximation.
fn total_length(&self) -> f32;


}

#[derive(Debug, Clone, PartialEq, Component, Reflect)]
#[reflect(Debug, Default, PartialEq)]
pub enum ProceduralAnimationShape {
Circle(CircleAnimation),
Points(PointsAnimation),
}

impl Default for ProceduralAnimationShape {
fn default() -> Self {
Self::Circle(CircleAnimation::default())
}
}



impl ProceduralAnimationStrategy for ProceduralAnimationShape {
fn get_position(&self, t: f32) -> Vec3 {
match self {
ProceduralAnimationShape::Circle(circle) => circle.get_position(t),
ProceduralAnimationShape::Points(points) => points.get_position(t),
}
}
fn total_length(&self) -> f32 {
match self {
ProceduralAnimationShape::Circle(circle) => circle.total_length(),
ProceduralAnimationShape::Points(points) => points.total_length(),
}
}
}


#[derive(Debug, Clone, PartialEq, Component, Reflect)]
#[reflect(Debug, Default, PartialEq)]
pub struct CircleAnimation {
pub radius: f32,
pub position: Vec3,
pub rotation: Quat,
}

impl Default for CircleAnimation {
fn default() -> Self {
Self {
radius: 0.5,
position: Vec3::ZERO,
rotation: Quat::IDENTITY,
}
}
}


impl ProceduralAnimationStrategy for CircleAnimation {
/// C = 2πr
fn total_length(&self) -> f32 { std::f32::consts::PI * 2.0 * self.radius }

fn get_position(&self, t: f32) -> Vec3 {
let angle = t * std::f32::consts::PI * 2.0;
let x = self.rotation * Vec3::X * angle.cos() * self.radius;
let y = self.rotation * Vec3::Y * angle.sin() * self.radius;
self.position + x + y
}
}


#[derive(Debug, Clone, PartialEq, Component, Reflect)]
#[reflect(Debug, Default, PartialEq)]
pub struct PointsAnimation {
pub wrap: bool,
pub points: Vec<Vec3>,
}

impl Default for PointsAnimation {
fn default() -> Self {
Self {
points: vec![-Vec3::X, Vec3::X],
wrap: false,
}
}
}

impl PointsAnimation {
pub fn num_segments(&self) -> usize {
if self.wrap {
self.points.len()
} else {
self.points.len() - 1
}
}
}

impl ProceduralAnimationStrategy for PointsAnimation {
fn get_position(&self, t: f32) -> Vec3 {
let t = t.clamp(0.0, 1.0);
let t = t * self.num_segments() as f32;
let segment = t.floor() as usize;
let t = t - segment as f32;
let i1 = segment;
let i2 = (segment + 1) % self.points.len();
self.points[i1].lerp(self.points[i2], t)
}

fn total_length(&self) -> f32 {
let mut length = 0.0;
for i in 0..self.num_segments() {
let i1 = i;
let i2 = (i + 1) % self.points.len();
length += self.points[i1].distance(self.points[i2]);
}
length
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use bevy::prelude::*;


#[derive(Debug, Clone, PartialEq, Component, Reflect)]
#[reflect(Debug, PartialEq, Default)]
pub enum ProceduralAnimationSpeed {
MetersPerSecond(f32),
FractionPerSecond(f32),
}

impl Default for ProceduralAnimationSpeed {
fn default() -> Self { Self::MetersPerSecond(1.0) }
}
4 changes: 2 additions & 2 deletions examples/inverse_kinematics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ pub fn main() {
(
beetmash::core::scenes::lighting_3d,
beetmash::core::scenes::ground_3d,
beet_examples::emote_agent::create_render_camera,
beet_examples::emote_agent::scenes::inverse_kinematics,
beet_examples::emote_agent::scenes::phone_screen,
beet_examples::emote_agent::scenes::phone_texture,
beet_examples::emote_agent::scenes::phone_texture_camera,
),
)
.run();
Expand Down

0 comments on commit 129e4bd

Please sign in to comment.