1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
use super::*;
/// `LookAt` struct
///
/// Struct describing a look at camera.
#[derive(Copy, Clone)]
pub struct LookAt {
/// Position of the camera
pub pos: Vec3,
/// Target point of the camera
pub target: Vec3,
/// Up vector of the camera
pub up: Vec3,
}
/// Camera component accessor.
///
/// A camera is represented by an entity with the Camera component.
///
/// It lets you control the local origin and target of the camera and set
/// the perspective mode and fov.
///
/// Call `set_active` or `set_active_for_player` to make the camera the active one.
///
/// An entity with a `Camera` component is special in that the rotation of its
/// `[Transform`] component will be controlled directly by the client of the active player.
/// That is, if you call [`Self::set_active_for_player`] or [`Self::set_active`] the camera will start
/// acting like a first-person camera controlled by mouse movements of the player.
/// If you do not want the player to control the camera rotation,
/// then you need to call `camera_entity.transform().rotation().set(…)` each frame.
pub struct Camera {
id: Entity,
}
impl std::fmt::Debug for Camera {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Camera")
.field("entity", &self.id.name())
.field("local_origin", &self.local_origin().get())
.field("local_forward_vector", &self.local_forward_vector().get())
.field("local_up_vector", &self.local_up_vector().get())
.field("field_of_view", &self.field_of_view().get())
.field("focal_point", &self.focal_point().get())
.field("f_stop", &self.f_stop().get())
.finish()
}
}
impl Camera {
/// Creates a camera entity.
///
/// * `name` - Just a name, to keep track of the entity during development.
pub fn create(name: &str) -> Self {
let id = World::create_entity(name, ffi::EntityTemplate::Camera);
Self { id }
}
impl_world_accessor!(
/// Returns a `ValueAccessor` for the local position of the camera.
///
/// The default is `Vec3::ZERO`.
///
/// The `Transform` component of the entity will be used to compute
/// the world-space camera position.
Camera,
LocalOrigin,
Vec3,
local_origin,
ValueAccessorReadWriteAnimate
);
impl_world_accessor!(
/// Returns a `ValueAccessor` for the local forward-vector of the camera.
///
/// The default is `-Vec3::Z`.
///
/// The `Transform` component of the entity will be used to compute
/// the world-space forward vector.
Camera,
LocalForwardVector,
Vec3,
local_forward_vector,
ValueAccessorReadWriteAnimate
);
impl_world_accessor!(
/// Returns a `ValueAccessor` for the local up vector of the camera.
///
/// The default is `Vec3::Y`.
///
/// The `Transform` component of the entity will be used to compute
/// the world-space up vector.
Camera,
LocalUpVector,
Vec3,
local_up_vector,
ValueAccessorReadWriteAnimate
);
impl_world_accessor!(
/// Returns a `ValueAccessor` for the field of view of the camera.
///
/// Sets/gets the vertical field of view in degrees.
/// Defaults to 60 degrees.
Camera,
FieldOfView,
f32,
field_of_view,
ValueAccessorReadWriteAnimate
);
impl_world_accessor!(
/// Returns a `ValueAccessor` for the focal point of the camera.
///
/// Sets/gets the focal point of the camera in normalized distance units. Set this to 0.0 for automatic focusing.
/// Defaults to 0.0 / automatic focusing.
///
/// note: That this will only have an effect if f-number is also set to >0.
Camera,
FocalPoint,
f32,
focal_point,
ValueAccessorReadWriteAnimate
);
impl_world_accessor!(
/// Returns a `ValueAccessor` for the focal point of the camera.
///
/// Sets/gets the focal point smoothing value of the camera which controls the amount of smoothing to apply to focal point changes.
/// Where 0.0 is no smoothing and 1.0 is the maximum amount of smoothing.
/// Defaults to 0.5.
///
/// note: That this will only have an effect if f-number is also set to >0.
Camera,
FocalPointSmoothing,
f32,
focal_point_smoothing,
ValueAccessorReadWriteAnimate
);
impl_world_accessor!(
/// Returns a `ValueAccessor` for the f-number of the camera.
///
/// Sets/gets the scale of the area that is in focus (cone of confusion).
/// Defaults to 0.0 which means depth of field is disabled
///
/// Note: This parameter will likely change and be replaced with something that is more physical and non-resolution dependent
Camera,
FStop,
f32,
f_stop,
ValueAccessorReadWriteAnimate
);
impl_world_accessor!(
/// Returns a `ValueAccessor` for the screen space 2D offset of the camera.
///
/// Sets/gets an offset in 2D pixel coordinates to shift the viewport by. Useful for centering things
/// under sidebars without viewports.
Camera,
ScreenSpaceOffset,
Vec2,
screen_space_offset,
ValueAccessorReadWriteAnimate
);
/// Currently unimplemented
///
/// Sets the projection mode of the camera (Perspective/Orthographic).
///
/// Default is Perspective.
pub fn set_camera_projection_mode(&self, mode: CameraProjectionMode) {
use ffi::Camera;
World::set_entity_value(
self.id,
ffi::ComponentType::Camera,
Camera::ProjectionMode.into(),
&Value::from_i64(mode as i64),
);
}
/// Accessor for the `Transform` component, if it exists.
pub fn transform(&self) -> Transform {
Transform::from_entity(self.id)
}
/// Sets the look at camera properties using a struct.
#[deprecated = "Position the `Transform` component instead, e.g. with `camera.transform().set_world_to_entity(Affine3A::look_at_rh(…))`"] // 2021-11-25
pub fn set_look_at(&self, look_at: &LookAt) {
self.local_origin().set(look_at.pos);
self.local_forward_vector()
.set((look_at.target - look_at.pos).normalize());
self.local_up_vector().set(look_at.up);
}
/// Makes this the active camera.
///
/// Simplified wrapper for `EntityMessenger::set_active`.
///
/// In a multiplayer environment, `set_active` will activate the camera for the host player.
/// Use `set_active_for_player` for activating a camera for a specific player.
pub fn set_active(&self) {
EntityMessenger::get()
.global_queue()
.set_active(self.id, ComponentType::Camera);
}
/// Makes this the active camera for a specific player.
///
/// Simplified wrapper for `EntityMessenger::set_active_for_player`.
///
/// * `player_id`: this identifier can be retrieved through the Applet API.
pub fn set_active_for_player(&self, player_id: PlayerId) {
EntityMessenger::get().global_queue().set_active_for_player(
self.id,
ComponentType::Camera,
player_id,
);
}
}
impl_world_component!(Camera);