pub struct TrackballCamera {
pub frame: Frame<f32>,
pub scope: Scope<f32>,
pub blend: f32,
pub reset: Frame<f32>,
pub clamp: Option<Box<dyn Clamp<f32>>>,
pub group: HashMap<Entity, bool>,
/* private fields */
}
Fields§
§frame: Frame<f32>
Camera frame defining Transform
.
Comprises following properties:
- target position as trackball center
- camera eye rotation on trackball surface (incl. roll, gimbal lock-free using quaternion)
- trackball radius
scope: Scope<f32>
Camera scope defining Projection
.
Comprises following properties:
- field of view angle (default is 45 degrees) and its mode of either
Fixed::Ver
(default),Fixed::Hor
, orFixed::Upp
. - projection mode of either perspective (default) or orthographic (scale preserving)
- clip planes either measured from eye (default) or target (object inspection mode)
blend: f32
Blend half-life from 0 (fast) to 1000 (slow) milliseconds. Default is 40.0
.
It is the time passed until halfway of fps-agnostic exponential ease-out.
reset: Frame<f32>
Camera frame to reset to when TrackballInput::reset_key
is pressed.
clamp: Option<Box<dyn Clamp<f32>>>
User boundary conditions clamping camera Frame
.
Allows to limit target/eye position or minimal/maximal target/eye distance or up rotation.
group: HashMap<Entity, bool>
Additional TrackballController
entities to which this camera is sensitive.
It is always sensitive to its own controller if it has one. A mapped value of true
will
clamp the active controller as well and hence all other cameras of this group whenever this
camera is clamped. If false
, only this camera is clamped whereas other cameras of this
group continue to follow the active controller.
Implementations§
Source§impl TrackballCamera
impl TrackballCamera
Sourcepub fn look_at(target: Vec3, eye: Vec3, up: Vec3) -> Self
pub fn look_at(target: Vec3, eye: Vec3, up: Vec3) -> Self
Defines camera with target
position and eye
position inclusive its roll attitude (up
).
Examples found in repository?
34fn setup(
35 mut commands: Commands,
36 mut meshes: ResMut<Assets<Mesh>>,
37 mut materials: ResMut<Assets<StandardMaterial>>,
38) {
39 // circular base
40 commands.spawn((
41 Mesh3d(meshes.add(Circle::new(4.0))),
42 MeshMaterial3d(materials.add(Color::WHITE)),
43 Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
44 ));
45 // cube
46 commands.spawn((
47 Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
48 MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
49 Transform::from_xyz(0.0, 0.5, 0.0),
50 ));
51 // light
52 commands.spawn((
53 PointLight {
54 shadows_enabled: true,
55 ..default()
56 },
57 Transform::from_xyz(4.0, 8.0, 4.0),
58 ));
59 // camera
60 commands.spawn((
61 TrackballController::default(),
62 TrackballCamera::look_at(Vec3::Y * 0.5, Vec3::new(-2.5, 4.5, 9.0), Vec3::Y),
63 Camera3d::default(),
64 ));
65}
More examples
28fn setup(
29 mut windows: Query<&mut Window>,
30 mut commands: Commands,
31 mut meshes: ResMut<Assets<Mesh>>,
32 mut materials: ResMut<Assets<StandardMaterial>>,
33) {
34 // circular base
35 commands.spawn((
36 Mesh3d(meshes.add(Circle::new(4.0))),
37 MeshMaterial3d(materials.add(Color::WHITE)),
38 Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
39 ));
40 // cube
41 commands.spawn((
42 Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
43 MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
44 Transform::from_xyz(0.0, 0.5, 0.0),
45 ));
46 // light
47 commands.spawn((
48 PointLight {
49 shadows_enabled: true,
50 ..default()
51 },
52 Transform::from_xyz(4.0, 8.0, 4.0),
53 ));
54
55 // Windows
56 let mut window1 = windows.single_mut().unwrap();
57 "Fixed Vertical Field of View (Perspective vs Orthographic)".clone_into(&mut window1.title);
58 let res = &window1.resolution;
59 let max = Vec2::new(res.width() * 0.5, res.height()).into();
60 // Left and right camera orientation.
61 let [target, eye, up] = [Vec3::Y * 0.5, Vec3::new(-2.5, 4.5, 9.0) * 1.2, Vec3::Y];
62 // Spawn a 2nd window.
63 let window2 = commands
64 .spawn(Window {
65 title: "Fixed Horizontal Field of View (Perspective vs Orthographic)".to_owned(),
66 ..default()
67 })
68 .id();
69 // Spawn a 3rd window.
70 let window3 = commands
71 .spawn(Window {
72 title: "Fixed Unit Per Pixels (Perspective vs Orthographic)".to_owned(),
73 ..default()
74 })
75 .id();
76
77 // Cameras
78 let mut order = 0;
79 let fov = Fixed::default();
80 for (fov, window) in [
81 (fov, WindowRef::Primary),
82 (fov.to_hor(&max), WindowRef::Entity(window2)),
83 (fov.to_upp(&max), WindowRef::Entity(window3)),
84 ] {
85 let mut scope = Scope::default();
86 scope.set_fov(fov);
87 // Left trackball controller and camera 3D bundle.
88 let left = commands
89 .spawn((
90 TrackballController::default(),
91 Camera {
92 target: RenderTarget::Window(window),
93 // Renders the right camera after the left camera,
94 // which has a default priority of 0.
95 order,
96 ..default()
97 },
98 Camera3d::default(),
99 LeftCamera,
100 ))
101 .id();
102 order += 1;
103 // Right trackball controller and camera 3D bundle.
104 let right = commands
105 .spawn((
106 TrackballController::default(),
107 Camera {
108 target: RenderTarget::Window(window),
109 // Renders the right camera after the left camera,
110 // which has a default priority of 0.
111 order,
112 // Don't clear on the second camera
113 // because the first camera already cleared the window.
114 clear_color: ClearColorConfig::None,
115 ..default()
116 },
117 Camera3d::default(),
118 RightCamera,
119 ))
120 .id();
121 order += 1;
122 // Insert left trackball camera and make it sensitive to right trackball controller as well.
123 commands.entity(left).insert(
124 TrackballCamera::look_at(target, eye, up)
125 .with_scope(scope)
126 .add_controller(right, true),
127 );
128 // Set orthographic projection mode for right camera.
129 scope.set_ortho(true);
130 // Insert right trackball camera and make it sensitive to left trackball controller as well.
131 commands.entity(right).insert(
132 TrackballCamera::look_at(target, eye, up)
133 .with_scope(scope)
134 .add_controller(left, true),
135 );
136 }
137}
Sourcepub const fn with_scope(self, scope: Scope<f32>) -> Self
pub const fn with_scope(self, scope: Scope<f32>) -> Self
Defines scope, see Self::scope
.
Examples found in repository?
28fn setup(
29 mut windows: Query<&mut Window>,
30 mut commands: Commands,
31 mut meshes: ResMut<Assets<Mesh>>,
32 mut materials: ResMut<Assets<StandardMaterial>>,
33) {
34 // circular base
35 commands.spawn((
36 Mesh3d(meshes.add(Circle::new(4.0))),
37 MeshMaterial3d(materials.add(Color::WHITE)),
38 Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
39 ));
40 // cube
41 commands.spawn((
42 Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
43 MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
44 Transform::from_xyz(0.0, 0.5, 0.0),
45 ));
46 // light
47 commands.spawn((
48 PointLight {
49 shadows_enabled: true,
50 ..default()
51 },
52 Transform::from_xyz(4.0, 8.0, 4.0),
53 ));
54
55 // Windows
56 let mut window1 = windows.single_mut().unwrap();
57 "Fixed Vertical Field of View (Perspective vs Orthographic)".clone_into(&mut window1.title);
58 let res = &window1.resolution;
59 let max = Vec2::new(res.width() * 0.5, res.height()).into();
60 // Left and right camera orientation.
61 let [target, eye, up] = [Vec3::Y * 0.5, Vec3::new(-2.5, 4.5, 9.0) * 1.2, Vec3::Y];
62 // Spawn a 2nd window.
63 let window2 = commands
64 .spawn(Window {
65 title: "Fixed Horizontal Field of View (Perspective vs Orthographic)".to_owned(),
66 ..default()
67 })
68 .id();
69 // Spawn a 3rd window.
70 let window3 = commands
71 .spawn(Window {
72 title: "Fixed Unit Per Pixels (Perspective vs Orthographic)".to_owned(),
73 ..default()
74 })
75 .id();
76
77 // Cameras
78 let mut order = 0;
79 let fov = Fixed::default();
80 for (fov, window) in [
81 (fov, WindowRef::Primary),
82 (fov.to_hor(&max), WindowRef::Entity(window2)),
83 (fov.to_upp(&max), WindowRef::Entity(window3)),
84 ] {
85 let mut scope = Scope::default();
86 scope.set_fov(fov);
87 // Left trackball controller and camera 3D bundle.
88 let left = commands
89 .spawn((
90 TrackballController::default(),
91 Camera {
92 target: RenderTarget::Window(window),
93 // Renders the right camera after the left camera,
94 // which has a default priority of 0.
95 order,
96 ..default()
97 },
98 Camera3d::default(),
99 LeftCamera,
100 ))
101 .id();
102 order += 1;
103 // Right trackball controller and camera 3D bundle.
104 let right = commands
105 .spawn((
106 TrackballController::default(),
107 Camera {
108 target: RenderTarget::Window(window),
109 // Renders the right camera after the left camera,
110 // which has a default priority of 0.
111 order,
112 // Don't clear on the second camera
113 // because the first camera already cleared the window.
114 clear_color: ClearColorConfig::None,
115 ..default()
116 },
117 Camera3d::default(),
118 RightCamera,
119 ))
120 .id();
121 order += 1;
122 // Insert left trackball camera and make it sensitive to right trackball controller as well.
123 commands.entity(left).insert(
124 TrackballCamera::look_at(target, eye, up)
125 .with_scope(scope)
126 .add_controller(right, true),
127 );
128 // Set orthographic projection mode for right camera.
129 scope.set_ortho(true);
130 // Insert right trackball camera and make it sensitive to left trackball controller as well.
131 commands.entity(right).insert(
132 TrackballCamera::look_at(target, eye, up)
133 .with_scope(scope)
134 .add_controller(left, true),
135 );
136 }
137}
Sourcepub const fn with_blend(self, blend: f32) -> Self
pub const fn with_blend(self, blend: f32) -> Self
Defines blend half-life, see Self::blend
.
Sourcepub const fn with_reset(self, reset: Frame<f32>) -> Self
pub const fn with_reset(self, reset: Frame<f32>) -> Self
Defines reset frame, see Self::reset
.
Sourcepub fn with_clamp(self, clamp: impl Clamp<f32>) -> Self
pub fn with_clamp(self, clamp: impl Clamp<f32>) -> Self
Defines user boundary conditions, see Self::clamp
.
Sourcepub fn add_controller(self, id: Entity, rigid: bool) -> Self
pub fn add_controller(self, id: Entity, rigid: bool) -> Self
Adds additional controller to which this camera is sensitive, see Self::group
.
Examples found in repository?
28fn setup(
29 mut windows: Query<&mut Window>,
30 mut commands: Commands,
31 mut meshes: ResMut<Assets<Mesh>>,
32 mut materials: ResMut<Assets<StandardMaterial>>,
33) {
34 // circular base
35 commands.spawn((
36 Mesh3d(meshes.add(Circle::new(4.0))),
37 MeshMaterial3d(materials.add(Color::WHITE)),
38 Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
39 ));
40 // cube
41 commands.spawn((
42 Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
43 MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
44 Transform::from_xyz(0.0, 0.5, 0.0),
45 ));
46 // light
47 commands.spawn((
48 PointLight {
49 shadows_enabled: true,
50 ..default()
51 },
52 Transform::from_xyz(4.0, 8.0, 4.0),
53 ));
54
55 // Windows
56 let mut window1 = windows.single_mut().unwrap();
57 "Fixed Vertical Field of View (Perspective vs Orthographic)".clone_into(&mut window1.title);
58 let res = &window1.resolution;
59 let max = Vec2::new(res.width() * 0.5, res.height()).into();
60 // Left and right camera orientation.
61 let [target, eye, up] = [Vec3::Y * 0.5, Vec3::new(-2.5, 4.5, 9.0) * 1.2, Vec3::Y];
62 // Spawn a 2nd window.
63 let window2 = commands
64 .spawn(Window {
65 title: "Fixed Horizontal Field of View (Perspective vs Orthographic)".to_owned(),
66 ..default()
67 })
68 .id();
69 // Spawn a 3rd window.
70 let window3 = commands
71 .spawn(Window {
72 title: "Fixed Unit Per Pixels (Perspective vs Orthographic)".to_owned(),
73 ..default()
74 })
75 .id();
76
77 // Cameras
78 let mut order = 0;
79 let fov = Fixed::default();
80 for (fov, window) in [
81 (fov, WindowRef::Primary),
82 (fov.to_hor(&max), WindowRef::Entity(window2)),
83 (fov.to_upp(&max), WindowRef::Entity(window3)),
84 ] {
85 let mut scope = Scope::default();
86 scope.set_fov(fov);
87 // Left trackball controller and camera 3D bundle.
88 let left = commands
89 .spawn((
90 TrackballController::default(),
91 Camera {
92 target: RenderTarget::Window(window),
93 // Renders the right camera after the left camera,
94 // which has a default priority of 0.
95 order,
96 ..default()
97 },
98 Camera3d::default(),
99 LeftCamera,
100 ))
101 .id();
102 order += 1;
103 // Right trackball controller and camera 3D bundle.
104 let right = commands
105 .spawn((
106 TrackballController::default(),
107 Camera {
108 target: RenderTarget::Window(window),
109 // Renders the right camera after the left camera,
110 // which has a default priority of 0.
111 order,
112 // Don't clear on the second camera
113 // because the first camera already cleared the window.
114 clear_color: ClearColorConfig::None,
115 ..default()
116 },
117 Camera3d::default(),
118 RightCamera,
119 ))
120 .id();
121 order += 1;
122 // Insert left trackball camera and make it sensitive to right trackball controller as well.
123 commands.entity(left).insert(
124 TrackballCamera::look_at(target, eye, up)
125 .with_scope(scope)
126 .add_controller(right, true),
127 );
128 // Set orthographic projection mode for right camera.
129 scope.set_ortho(true);
130 // Insert right trackball camera and make it sensitive to left trackball controller as well.
131 commands.entity(right).insert(
132 TrackballCamera::look_at(target, eye, up)
133 .with_scope(scope)
134 .add_controller(left, true),
135 );
136 }
137}
Trait Implementations§
Source§impl Component for TrackballCamera
impl Component for TrackballCamera
Source§const STORAGE_TYPE: StorageType = bevy::ecs::component::StorageType::Table
const STORAGE_TYPE: StorageType = bevy::ecs::component::StorageType::Table
Source§type Mutability = Mutable
type Mutability = Mutable
Component<Mutability = Mutable>
],
while immutable components will instead have [Component<Mutability = Immutable>
]. Read moreSource§fn register_required_components(
requiree: ComponentId,
components: &mut ComponentsRegistrator<'_>,
required_components: &mut RequiredComponents,
inheritance_depth: u16,
recursion_check_stack: &mut Vec<ComponentId>,
)
fn register_required_components( requiree: ComponentId, components: &mut ComponentsRegistrator<'_>, required_components: &mut RequiredComponents, inheritance_depth: u16, recursion_check_stack: &mut Vec<ComponentId>, )
Source§fn clone_behavior() -> ComponentCloneBehavior
fn clone_behavior() -> ComponentCloneBehavior
Source§fn register_component_hooks(hooks: &mut ComponentHooks)
fn register_component_hooks(hooks: &mut ComponentHooks)
Component::on_add
, etc.)ComponentHooks
.Source§fn on_add() -> Option<for<'w> fn(_: DeferredWorld<'w>, _: HookContext)>
fn on_add() -> Option<for<'w> fn(_: DeferredWorld<'w>, _: HookContext)>
Source§fn on_insert() -> Option<for<'w> fn(_: DeferredWorld<'w>, _: HookContext)>
fn on_insert() -> Option<for<'w> fn(_: DeferredWorld<'w>, _: HookContext)>
Source§fn on_replace() -> Option<for<'w> fn(_: DeferredWorld<'w>, _: HookContext)>
fn on_replace() -> Option<for<'w> fn(_: DeferredWorld<'w>, _: HookContext)>
Source§fn on_remove() -> Option<for<'w> fn(_: DeferredWorld<'w>, _: HookContext)>
fn on_remove() -> Option<for<'w> fn(_: DeferredWorld<'w>, _: HookContext)>
Source§fn on_despawn() -> Option<for<'w> fn(_: DeferredWorld<'w>, _: HookContext)>
fn on_despawn() -> Option<for<'w> fn(_: DeferredWorld<'w>, _: HookContext)>
Source§fn map_entities<E>(_this: &mut Self, _mapper: &mut E)where
E: EntityMapper,
fn map_entities<E>(_this: &mut Self, _mapper: &mut E)where
E: EntityMapper,
EntityMapper
. This is used to remap entities in contexts like scenes and entity cloning.
When deriving Component
, this is populated by annotating fields containing entities with #[entities]
Read moreAuto Trait Implementations§
impl Freeze for TrackballCamera
impl !RefUnwindSafe for TrackballCamera
impl Send for TrackballCamera
impl Sync for TrackballCamera
impl Unpin for TrackballCamera
impl !UnwindSafe for TrackballCamera
Blanket Implementations§
Source§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
Source§fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
T
ShaderType
for self
. When used in AsBindGroup
derives, it is safe to assume that all images in self
exist.Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<C> Bundle for Cwhere
C: Component,
impl<C> Bundle for Cwhere
C: Component,
fn component_ids( components: &mut ComponentsRegistrator<'_>, ids: &mut impl FnMut(ComponentId), )
Source§fn register_required_components(
components: &mut ComponentsRegistrator<'_>,
required_components: &mut RequiredComponents,
)
fn register_required_components( components: &mut ComponentsRegistrator<'_>, required_components: &mut RequiredComponents, )
Bundle
.Source§fn get_component_ids(
components: &Components,
ids: &mut impl FnMut(Option<ComponentId>),
)
fn get_component_ids( components: &Components, ids: &mut impl FnMut(Option<ComponentId>), )
Source§impl<C> BundleFromComponents for Cwhere
C: Component,
impl<C> BundleFromComponents for Cwhere
C: Component,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
, which can then be
downcast
into Box<dyn ConcreteType>
where ConcreteType
implements Trait
.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
, which can then be further
downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<C> DynamicBundle for Cwhere
C: Component,
impl<C> DynamicBundle for Cwhere
C: Component,
fn get_components( self, func: &mut impl FnMut(StorageType, OwningPtr<'_>), ) -> <C as DynamicBundle>::Effect
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self
from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self
is actually part of its subset T
(and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset
but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self
to the equivalent element of its superset.