mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-29 09:08:58 +00:00
Composite Mode Camera Motions (#86)
This PR adds the camera motions to the composite mode. There are currently 4 camera motion modes: `Orbit`, `Static`, `Pan`, `Zoom`. They are accessed by using the `--camera-motion [motion]` argument. For example, if I want to render a scene with an orbiting motion, I would do the following: `studio-headless scene --camera-motion orbit scene.ron ` Some things to note: - The argument `--orbit` no longer is there. It has been deprecated! - Currently the speed is hard coded. This can be set as a command arg later. - This only works with scenes, as this is intended for the `sample-room` scene. May not work great for other scenes Let me know if there is anything that I can fix!
This commit is contained in:
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"space_editor_core::hotkeys::HotkeySet<space_editor_ui::tools::gizmo::GizmoHotkey>": "{\"space_editor_core::hotkeys::HotkeySet<space_editor_ui::tools::gizmo::GizmoHotkey>\":(bindings:{Rotate:[R],Translate:[G],Scale:[S],Multiple:[ShiftLeft],Clone:[AltLeft],Delete:[X]},name:\"GizmoHotkey\")}",
|
|
||||||
"space_undo::ChangeChainSettings": "{\"space_undo::ChangeChainSettings\":(max_change_chain_size:200)}",
|
|
||||||
"space_persistence::PersistenceSettings": "{\"space_persistence::PersistenceSettings\":(load_on_startup:true,save_on_close:true)}",
|
"space_persistence::PersistenceSettings": "{\"space_persistence::PersistenceSettings\":(load_on_startup:true,save_on_close:true)}",
|
||||||
"space_editor_ui::settings::NewWindowSettings": "{\"space_editor_ui::settings::NewWindowSettings\":(new_tab:SameNode)}",
|
"space_editor_ui::settings::NewWindowSettings": "{\"space_editor_ui::settings::NewWindowSettings\":(new_tab:SameNode)}",
|
||||||
|
"space_undo::ChangeChainSettings": "{\"space_undo::ChangeChainSettings\":(max_change_chain_size:200)}",
|
||||||
|
"space_editor_core::hotkeys::HotkeySet<space_editor_ui::tools::gizmo::GizmoHotkey>": "{\"space_editor_core::hotkeys::HotkeySet<space_editor_ui::tools::gizmo::GizmoHotkey>\":(bindings:{Rotate:[R],Translate:[G],Scale:[S],Multiple:[ShiftLeft],Clone:[AltLeft],Delete:[X]},name:\"GizmoHotkey\")}",
|
||||||
}
|
}
|
||||||
+1
-1
@@ -26,7 +26,7 @@ mod mixamo;
|
|||||||
mod path;
|
mod path;
|
||||||
mod persistance;
|
mod persistance;
|
||||||
mod remote;
|
mod remote;
|
||||||
mod scene;
|
pub mod scene;
|
||||||
pub mod screenshot;
|
pub mod screenshot;
|
||||||
mod skybox;
|
mod skybox;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|||||||
+85
-29
@@ -1,6 +1,9 @@
|
|||||||
use bevy::{prelude::*, render::render_resource::Extent3d, transform::components::Transform};
|
use bevy::{prelude::*, render::render_resource::Extent3d, transform::components::Transform};
|
||||||
use clap::{Args, Parser, Subcommand};
|
use clap::{Args, Parser, Subcommand};
|
||||||
use studio::headless::{start_headless, HeadlessMode};
|
use studio::{
|
||||||
|
headless::{start_headless, HeadlessMode},
|
||||||
|
scene::SceneState,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(name = "StorytellerStudioHeadless")]
|
#[command(name = "StorytellerStudioHeadless")]
|
||||||
@@ -20,11 +23,7 @@ enum Subcommands {
|
|||||||
Scene {
|
Scene {
|
||||||
scene_dir: String,
|
scene_dir: String,
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
orbit: bool,
|
camera_motion: Option<String>,
|
||||||
#[arg(long, value_parser = clap::value_parser!(f32))]
|
|
||||||
orbit_radius: Option<f32>,
|
|
||||||
#[arg(long, value_parser = clap::value_parser!(f32))]
|
|
||||||
orbit_speed: Option<f32>,
|
|
||||||
#[arg(long, short)]
|
#[arg(long, short)]
|
||||||
output_dir: Option<String>,
|
output_dir: Option<String>,
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
@@ -73,9 +72,7 @@ fn main() {
|
|||||||
let mut app = match args.subcommand {
|
let mut app = match args.subcommand {
|
||||||
Subcommands::Scene {
|
Subcommands::Scene {
|
||||||
scene_dir,
|
scene_dir,
|
||||||
orbit,
|
camera_motion,
|
||||||
orbit_speed,
|
|
||||||
orbit_radius,
|
|
||||||
skybox,
|
skybox,
|
||||||
output_dir,
|
output_dir,
|
||||||
output_resolution,
|
output_resolution,
|
||||||
@@ -98,15 +95,28 @@ fn main() {
|
|||||||
frames,
|
frames,
|
||||||
output_res,
|
output_res,
|
||||||
);
|
);
|
||||||
let orbit_speed = orbit_speed.unwrap_or(1.0);
|
|
||||||
let orbit_radius = orbit_radius.unwrap_or(8.0);
|
|
||||||
|
|
||||||
if orbit {
|
if let Some(camera_motion) = camera_motion {
|
||||||
app.insert_resource(OrbitSettings {
|
match camera_motion.as_str() {
|
||||||
radius: orbit_radius,
|
"orbit" => {
|
||||||
speed: orbit_speed,
|
app.insert_resource(CameraMotion::Orbit);
|
||||||
})
|
}
|
||||||
.add_systems(Update, orbit_scene);
|
"pan" => {
|
||||||
|
app.insert_resource(CameraMotion::Pan);
|
||||||
|
}
|
||||||
|
"zoom" => {
|
||||||
|
app.insert_resource(CameraMotion::Zoom);
|
||||||
|
}
|
||||||
|
"static" => {
|
||||||
|
app.insert_resource(CameraMotion::Static);
|
||||||
|
}
|
||||||
|
_ => panic!("Unsupported camera motion type."),
|
||||||
|
}
|
||||||
|
|
||||||
|
app.add_systems(
|
||||||
|
Update,
|
||||||
|
update_camera_motion.run_if(in_state(SceneState::Active)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
app
|
app
|
||||||
@@ -166,27 +176,73 @@ fn main() {
|
|||||||
app.run();
|
app.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const SPEED: f32 = 0.1;
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
struct OrbitSettings {
|
enum CameraMotion {
|
||||||
radius: f32,
|
Orbit,
|
||||||
speed: f32,
|
Pan,
|
||||||
|
Zoom,
|
||||||
|
Static,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn orbit_scene(
|
pub(crate) fn update_camera_motion(
|
||||||
mut camera: Query<&mut Transform, With<Camera>>,
|
mut camera: Query<&mut Transform, (With<Camera>, Without<Parent>)>,
|
||||||
orbit_settings: Res<OrbitSettings>,
|
camera_motion: Res<CameraMotion>,
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
) {
|
) {
|
||||||
|
println!("{}", camera.iter().count());
|
||||||
let Ok(mut main_cam_transform) = camera.get_single_mut() else {
|
let Ok(mut main_cam_transform) = camera.get_single_mut() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
main_cam_transform.translation = Vec3::new(
|
println!("Updating camera motion");
|
||||||
orbit_settings.radius * (time.elapsed_seconds() * orbit_settings.speed).cos(),
|
|
||||||
6.0,
|
match *camera_motion {
|
||||||
orbit_settings.radius * (time.elapsed_seconds() * orbit_settings.speed).sin(),
|
CameraMotion::Orbit => {
|
||||||
);
|
orbit_camera(&mut main_cam_transform, &time);
|
||||||
main_cam_transform.look_at(Vec3::ZERO, Vec3::Y);
|
}
|
||||||
|
CameraMotion::Pan => {
|
||||||
|
pan_camera(&mut main_cam_transform, &time);
|
||||||
|
}
|
||||||
|
CameraMotion::Zoom => {
|
||||||
|
zoom_camera(&mut main_cam_transform, &time);
|
||||||
|
}
|
||||||
|
CameraMotion::Static => {}
|
||||||
|
}
|
||||||
|
// main_cam_transform.look_at(Vec3::ZERO, Vec3::Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zoom_camera(main_cam_transform: &mut Transform, time: &Time<()>) {
|
||||||
|
let scaled_time = time.elapsed().as_secs_f32() * SPEED;
|
||||||
|
let normalized_cos = (-scaled_time.cos() + 1.0) / 2.0;
|
||||||
|
let start_pos = Vec3::new(0.366, 1.1, 2.5);
|
||||||
|
let end_pos = Vec3::new(0.366, 1.1, -0.5);
|
||||||
|
|
||||||
|
main_cam_transform.translation = start_pos.lerp(end_pos, normalized_cos);
|
||||||
|
main_cam_transform.rotation = Quat::from_euler(EulerRot::XYZ, 0.0, 0.0, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pan_camera(main_cam_transform: &mut Transform, time: &Time<()>) {
|
||||||
|
let scaled_time = time.elapsed().as_secs_f32() * SPEED;
|
||||||
|
let normalized_cos = (scaled_time.cos() + 1.0) / 2.0;
|
||||||
|
let start_pos = Vec3::new(1.617, 0.9, 2.177);
|
||||||
|
let end_pos = Vec3::new(-0.365, 0.9, 2.323);
|
||||||
|
|
||||||
|
main_cam_transform.translation = start_pos.lerp(end_pos, normalized_cos);
|
||||||
|
main_cam_transform.rotation = Quat::from_euler(EulerRot::XYZ, 0.0, 0.0, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn orbit_camera(main_cam_transform: &mut Mut<'_, Transform>, time: &Res<'_, Time>) {
|
||||||
|
let scaled_time = time.elapsed().as_secs_f32() * SPEED;
|
||||||
|
let max_angle = std::f32::consts::PI / 2.0;
|
||||||
|
let normalized_cos = (scaled_time.cos() + 1.0) / 2.0;
|
||||||
|
let angle = max_angle * normalized_cos;
|
||||||
|
|
||||||
|
// let t = (time.elapsed().as_secs_f32() / 5.0) % 1.0;
|
||||||
|
|
||||||
|
main_cam_transform.translation = Vec3::new(-2.2 * angle.cos(), 1.0, 2.5 * angle.sin());
|
||||||
|
main_cam_transform.look_at(Vec3::new(0.347, 0.556, -1.0), Vec3::Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|||||||
+3
-3
@@ -3,7 +3,7 @@ use bevy::{
|
|||||||
window::{close_on_esc, Window},
|
window::{close_on_esc, Window},
|
||||||
};
|
};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use studio::{screenshot::ScreenShotPlugin, InitAsset, InitParams, StudioMode};
|
use studio::{InitAsset, InitParams, StudioMode};
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(name = "StorytellerStudio")]
|
#[command(name = "StorytellerStudio")]
|
||||||
@@ -19,7 +19,7 @@ struct StudioArgs {
|
|||||||
fn main() {
|
fn main() {
|
||||||
let args = StudioArgs::parse();
|
let args = StudioArgs::parse();
|
||||||
|
|
||||||
let object_id = args.model.unwrap_or("Mannequin.gltf".to_string());
|
let object_id = args.model.unwrap_or("sample-room.gltf".to_string());
|
||||||
let skybox_id = args.skybox.unwrap_or("gum_trees_4k".to_string());
|
let skybox_id = args.skybox.unwrap_or("gum_trees_4k".to_string());
|
||||||
|
|
||||||
// Edit the arguments here to change the default startup scene or skybox
|
// Edit the arguments here to change the default startup scene or skybox
|
||||||
@@ -37,7 +37,7 @@ fn main() {
|
|||||||
|
|
||||||
// Add any additional systems, resources, etc. for local debugging
|
// Add any additional systems, resources, etc. for local debugging
|
||||||
app.add_systems(Update, close_on_esc);
|
app.add_systems(Update, close_on_esc);
|
||||||
app.add_plugins(ScreenShotPlugin);
|
// app.add_plugins(ScreenShotPlugin);
|
||||||
|
|
||||||
app.run();
|
app.run();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user