mirror of
https://github.com/bevyengine/bevy
synced 2024-11-26 06:30:19 +00:00
fcd7c0fc3d
Rebased and finished version of https://github.com/bevyengine/bevy/pull/8407. Huge thanks to @GitGhillie for adjusting all the examples, and the many other people who helped write this PR (@superdump , @coreh , among others) :) Fixes https://github.com/bevyengine/bevy/issues/8369 --- ## Changelog - Added a `brightness` control to `Skybox`. - Added an `intensity` control to `EnvironmentMapLight`. - Added `ExposureSettings` and `PhysicalCameraParameters` for controlling exposure of 3D cameras. - Removed the baked-in `DirectionalLight` exposure Bevy previously hardcoded internally. ## Migration Guide - If using a `Skybox` or `EnvironmentMapLight`, use the new `brightness` and `intensity` controls to adjust their strength. - All 3D scene will now have different apparent brightnesses due to Bevy implementing proper exposure controls. You will have to adjust the intensity of your lights and/or your camera exposure via the new `ExposureSettings` component to compensate. --------- Co-authored-by: Robert Swain <robert.swain@gmail.com> Co-authored-by: GitGhillie <jillisnoordhoek@gmail.com> Co-authored-by: Marco Buono <thecoreh@gmail.com> Co-authored-by: vero <email@atlasdostal.com> Co-authored-by: atlas dostal <rodol@rivalrebels.com>
154 lines
5.5 KiB
Rust
154 lines
5.5 KiB
Rust
//! Create and play an animation defined by code that operates on the [`Transform`] component.
|
|
|
|
use std::f32::consts::PI;
|
|
|
|
use bevy::prelude::*;
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins)
|
|
.insert_resource(AmbientLight {
|
|
color: Color::WHITE,
|
|
brightness: 150.0,
|
|
})
|
|
.add_systems(Startup, setup)
|
|
.run();
|
|
}
|
|
|
|
fn setup(
|
|
mut commands: Commands,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
|
mut animations: ResMut<Assets<AnimationClip>>,
|
|
) {
|
|
// Camera
|
|
commands.spawn(Camera3dBundle {
|
|
transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
|
|
..default()
|
|
});
|
|
|
|
// The animation API uses the `Name` component to target entities
|
|
let planet = Name::new("planet");
|
|
let orbit_controller = Name::new("orbit_controller");
|
|
let satellite = Name::new("satellite");
|
|
|
|
// Creating the animation
|
|
let mut animation = AnimationClip::default();
|
|
// A curve can modify a single part of a transform, here the translation
|
|
animation.add_curve_to_path(
|
|
EntityPath {
|
|
parts: vec![planet.clone()],
|
|
},
|
|
VariableCurve {
|
|
keyframe_timestamps: vec![0.0, 1.0, 2.0, 3.0, 4.0],
|
|
keyframes: Keyframes::Translation(vec![
|
|
Vec3::new(1.0, 0.0, 1.0),
|
|
Vec3::new(-1.0, 0.0, 1.0),
|
|
Vec3::new(-1.0, 0.0, -1.0),
|
|
Vec3::new(1.0, 0.0, -1.0),
|
|
// in case seamless looping is wanted, the last keyframe should
|
|
// be the same as the first one
|
|
Vec3::new(1.0, 0.0, 1.0),
|
|
]),
|
|
interpolation: Interpolation::Linear,
|
|
},
|
|
);
|
|
// Or it can modify the rotation of the transform.
|
|
// To find the entity to modify, the hierarchy will be traversed looking for
|
|
// an entity with the right name at each level
|
|
animation.add_curve_to_path(
|
|
EntityPath {
|
|
parts: vec![planet.clone(), orbit_controller.clone()],
|
|
},
|
|
VariableCurve {
|
|
keyframe_timestamps: vec![0.0, 1.0, 2.0, 3.0, 4.0],
|
|
keyframes: Keyframes::Rotation(vec![
|
|
Quat::IDENTITY,
|
|
Quat::from_axis_angle(Vec3::Y, PI / 2.),
|
|
Quat::from_axis_angle(Vec3::Y, PI / 2. * 2.),
|
|
Quat::from_axis_angle(Vec3::Y, PI / 2. * 3.),
|
|
Quat::IDENTITY,
|
|
]),
|
|
interpolation: Interpolation::Linear,
|
|
},
|
|
);
|
|
// If a curve in an animation is shorter than the other, it will not repeat
|
|
// until all other curves are finished. In that case, another animation should
|
|
// be created for each part that would have a different duration / period
|
|
animation.add_curve_to_path(
|
|
EntityPath {
|
|
parts: vec![planet.clone(), orbit_controller.clone(), satellite.clone()],
|
|
},
|
|
VariableCurve {
|
|
keyframe_timestamps: vec![0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0],
|
|
keyframes: Keyframes::Scale(vec![
|
|
Vec3::splat(0.8),
|
|
Vec3::splat(1.2),
|
|
Vec3::splat(0.8),
|
|
Vec3::splat(1.2),
|
|
Vec3::splat(0.8),
|
|
Vec3::splat(1.2),
|
|
Vec3::splat(0.8),
|
|
Vec3::splat(1.2),
|
|
Vec3::splat(0.8),
|
|
]),
|
|
interpolation: Interpolation::Linear,
|
|
},
|
|
);
|
|
// There can be more than one curve targeting the same entity path
|
|
animation.add_curve_to_path(
|
|
EntityPath {
|
|
parts: vec![planet.clone(), orbit_controller.clone(), satellite.clone()],
|
|
},
|
|
VariableCurve {
|
|
keyframe_timestamps: vec![0.0, 1.0, 2.0, 3.0, 4.0],
|
|
keyframes: Keyframes::Rotation(vec![
|
|
Quat::IDENTITY,
|
|
Quat::from_axis_angle(Vec3::Y, PI / 2.),
|
|
Quat::from_axis_angle(Vec3::Y, PI / 2. * 2.),
|
|
Quat::from_axis_angle(Vec3::Y, PI / 2. * 3.),
|
|
Quat::IDENTITY,
|
|
]),
|
|
interpolation: Interpolation::Linear,
|
|
},
|
|
);
|
|
|
|
// Create the animation player, and set it to repeat
|
|
let mut player = AnimationPlayer::default();
|
|
player.play(animations.add(animation)).repeat();
|
|
|
|
// Create the scene that will be animated
|
|
// First entity is the planet
|
|
commands
|
|
.spawn((
|
|
PbrBundle {
|
|
mesh: meshes.add(Mesh::try_from(shape::Icosphere::default()).unwrap()),
|
|
material: materials.add(Color::rgb(0.8, 0.7, 0.6)),
|
|
..default()
|
|
},
|
|
// Add the Name component, and the animation player
|
|
planet,
|
|
player,
|
|
))
|
|
.with_children(|p| {
|
|
// This entity is just used for animation, but doesn't display anything
|
|
p.spawn((
|
|
SpatialBundle::INHERITED_IDENTITY,
|
|
// Add the Name component
|
|
orbit_controller,
|
|
))
|
|
.with_children(|p| {
|
|
// The satellite, placed at a distance of the planet
|
|
p.spawn((
|
|
PbrBundle {
|
|
transform: Transform::from_xyz(1.5, 0.0, 0.0),
|
|
mesh: meshes.add(shape::Cube { size: 0.5 }),
|
|
material: materials.add(Color::rgb(0.3, 0.9, 0.3)),
|
|
..default()
|
|
},
|
|
// Add the Name component
|
|
satellite,
|
|
));
|
|
});
|
|
});
|
|
}
|