Merge branch 'qutrin/camera-modes' into 'master'

Camera Modes

See merge request veloren/veloren!355
This commit is contained in:
Joshua Barretto 2019-07-25 13:14:00 +00:00
commit d77d4dc60e
5 changed files with 87 additions and 19 deletions

View File

@ -9,7 +9,7 @@ use crate::{
PostProcessLocals, PostProcessPipeline, Renderer, SkyboxLocals, SkyboxPipeline,
},
scene::{
camera::Camera,
camera::{Camera, CameraMode},
figure::{FigureModelCache, FigureState},
},
};
@ -52,7 +52,7 @@ impl Scene {
Self {
globals: renderer.create_consts(&[Globals::default()]).unwrap(),
lights: renderer.create_consts(&[Light::default(); 32]).unwrap(),
camera: Camera::new(resolution.x / resolution.y),
camera: Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson),
skybox: Skybox {
model: renderer.create_model(&create_skybox_mesh()).unwrap(),

View File

@ -7,6 +7,14 @@ const NEAR_PLANE: f32 = 0.01;
const FAR_PLANE: f32 = 10000.0;
const INTERP_TIME: f32 = 0.1;
pub const MIN_ZOOM: f32 = 0.1;
// Possible TODO: Add more modes
#[derive(PartialEq, Clone, Copy)]
pub enum CameraMode {
FirstPerson,
ThirdPerson,
}
pub struct Camera {
tgt_focus: Vec3<f32>,
@ -16,13 +24,14 @@ pub struct Camera {
dist: f32,
fov: f32,
aspect: f32,
mode: CameraMode,
last_time: Option<f64>,
}
impl Camera {
/// Create a new `Camera` with default parameters.
pub fn new(aspect: f32) -> Self {
pub fn new(aspect: f32, mode: CameraMode) -> Self {
Self {
tgt_focus: Vec3::unit_z() * 10.0,
focus: Vec3::unit_z() * 10.0,
@ -31,6 +40,8 @@ impl Camera {
dist: 10.0,
fov: 1.1,
aspect,
mode,
last_time: None,
}
}
@ -103,8 +114,13 @@ impl Camera {
/// Zoom the camera by the given delta, limiting the input accordingly.
pub fn zoom_by(&mut self, delta: f32) {
// Clamp camera dist to the 0 <= x <= infinity range
self.tgt_dist = (self.tgt_dist + delta).max(0.0);
match self.mode {
CameraMode::ThirdPerson => {
// Clamp camera dist to the 2 <= x <= infinity range
self.tgt_dist = (self.tgt_dist + delta).max(2.0);
}
CameraMode::FirstPerson => {}
};
}
/// Get the distance of the camera from the target
@ -156,4 +172,24 @@ impl Camera {
pub fn get_fov(&self) -> f32 {
self.fov
}
/// Set the mode of the camera.
pub fn set_mode(&mut self, mode: CameraMode) {
if self.mode != mode {
self.mode = mode;
match self.mode {
CameraMode::ThirdPerson => {
self.zoom_by(5.0);
}
CameraMode::FirstPerson => {
self.set_distance(MIN_ZOOM);
}
}
}
}
/// Get the mode of the camera
pub fn get_mode(&self) -> CameraMode {
self.mode
}
}

View File

@ -7,6 +7,7 @@ use crate::{
render::{
Consts, FigureBoneData, FigureLocals, FigurePipeline, Globals, Light, Mesh, Model, Renderer,
},
scene::camera::{Camera, CameraMode},
};
use client::Client;
use common::{
@ -842,6 +843,7 @@ impl FigureMgr {
client: &mut Client,
globals: &Consts<Globals>,
lights: &Consts<Light>,
camera: &Camera,
) {
let tick = client.get_tick();
let ecs = client.state().ecs();
@ -897,6 +899,18 @@ impl FigureMgr {
.get_or_create_model(renderer, *body, tick)
.0;
// Don't render the player's body while in first person mode
if camera.get_mode() == CameraMode::FirstPerson
&& client
.state()
.read_storage::<comp::Body>()
.get(client.entity())
.is_some()
&& entity == client.entity()
{
continue;
}
renderer.render_figure(model, globals, locals, bone_consts, lights);
} else {
warn!("Body has no saved figure");

View File

@ -2,7 +2,11 @@ pub mod camera;
pub mod figure;
pub mod terrain;
use self::{camera::Camera, figure::FigureMgr, terrain::Terrain};
use self::{
camera::{Camera, CameraMode},
figure::FigureMgr,
terrain::Terrain,
};
use crate::{
render::{
create_pp_mesh, create_skybox_mesh, Consts, Globals, Light, Model, PostProcessLocals,
@ -52,7 +56,7 @@ impl Scene {
Self {
globals: renderer.create_consts(&[Globals::default()]).unwrap(),
lights: renderer.create_consts(&[Light::default(); 32]).unwrap(),
camera: Camera::new(resolution.x / resolution.y),
camera: Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson),
skybox: Skybox {
model: renderer.create_model(&create_skybox_mesh()).unwrap(),
@ -191,6 +195,17 @@ impl Scene {
proj_mat,
);
if client
.state()
.read_storage::<comp::CanBuild>()
.get(client.entity())
.is_some()
{
self.camera.set_mode(CameraMode::FirstPerson);
} else {
self.camera.set_mode(CameraMode::ThirdPerson);
}
// Maintain the figures.
self.figure_mgr.maintain(renderer, client);
@ -206,7 +221,7 @@ impl Scene {
// Render terrain and figures.
self.terrain.render(renderer, &self.globals, &self.lights);
self.figure_mgr
.render(renderer, client, &self.globals, &self.lights);
.render(renderer, client, &self.globals, &self.lights, &self.camera);
renderer.render_post_process(
&self.postprocess.model,

View File

@ -2,7 +2,7 @@ use crate::{
hud::{DebugInfo, Event as HudEvent, Hud},
key_state::KeyState,
render::Renderer,
scene::Scene,
scene::{camera::Camera, Scene},
settings::Settings,
window::{Event, GameInput, Window},
Direction, Error, GlobalState, PlayState, PlayStateResult,
@ -91,6 +91,13 @@ impl PlayState for SessionState {
self.client.borrow_mut().send_chat(cmd.to_string());
}
}
// Compute camera data
let get_cam_data = |camera: &Camera, client: &Client| {
let (view_mat, _, cam_pos) = camera.compute_dependents(client);
let cam_dir: Vec3<f32> = Vec3::from(view_mat.inverted() * -Vec4::unit_z());
(cam_dir, cam_pos)
};
// Game loop
let mut current_client_state = self.client.borrow().get_client_state();
@ -121,9 +128,7 @@ impl PlayState for SessionState {
.get(client.entity())
.is_some()
{
let cam_pos = self.scene.camera().compute_dependents(&client).2;
let cam_dir =
(self.scene.camera().get_focus_pos() - cam_pos).normalized();
let (cam_dir, cam_pos) = get_cam_data(&self.scene.camera(), &client);
let (d, b) = {
let terrain = client.state().terrain();
@ -134,7 +139,7 @@ impl PlayState for SessionState {
if b {
let pos =
(cam_pos + cam_dir * (d - 0.01)).map(|e| e.floor() as i32);
client.place_block(pos, self.selected_block); // TODO: Handle block color with a command
client.place_block(pos, self.selected_block);
}
} else {
self.controller.attack = state
@ -150,9 +155,8 @@ impl PlayState for SessionState {
.get(client.entity())
.is_some()
{
let cam_pos = self.scene.camera().compute_dependents(&client).2;
let cam_dir =
(self.scene.camera().get_focus_pos() - cam_pos).normalized();
let (cam_dir, cam_pos) =
get_cam_data(&self.scene.camera(), &client);
let (d, b) = {
let terrain = client.state().terrain();
@ -179,9 +183,8 @@ impl PlayState for SessionState {
.is_some()
{
if state {
let cam_pos = self.scene.camera().compute_dependents(&client).2;
let cam_dir =
(self.scene.camera().get_focus_pos() - cam_pos).normalized();
let (cam_dir, cam_pos) =
get_cam_data(&self.scene.camera(), &client);
if let Ok(Some(block)) = client
.state()