Innumerable camera improvements

This commit is contained in:
Joshua Barretto
2020-05-18 23:40:28 +01:00
parent 68e77f43f8
commit f1b166d15d
7 changed files with 84 additions and 22 deletions

View File

@ -54,7 +54,7 @@ void main() {
vec3 color = mix(mix(surf_color, fog_color, fog_level), clouds.rgb, clouds.a); vec3 color = mix(mix(surf_color, fog_color, fog_level), clouds.rgb, clouds.a);
if ((flags & 1) == 1 && int(cam_mode) == 1) { if ((flags & 1) == 1 && int(cam_mode) == 1) {
float distance = distance(vec3(cam_pos), vec3(model_mat * vec4(vec3(0), 1))) - 2; float distance = distance(vec3(cam_pos), focus_pos.xyz) - 2;
float opacity = clamp(distance / distance_divider, 0, 1); float opacity = clamp(distance / distance_divider, 0, 1);

View File

@ -29,7 +29,7 @@ uniform u_bones {
out vec4 tgt_color; out vec4 tgt_color;
void main() { void main() {
float distance = distance(vec3(cam_pos), vec3(model_mat * vec4(vec3(0), 1))) - 2; float distance = distance(vec3(cam_pos), focus_pos.xyz) - 2;
float opacity = clamp(distance / distance_divider, 0, 1); float opacity = clamp(distance / distance_divider, 0, 1);

View File

@ -91,6 +91,17 @@ impl CharacterState {
} }
} }
pub fn is_aimed(&self) -> bool {
match self {
CharacterState::BasicMelee(_)
| CharacterState::BasicRanged(_)
| CharacterState::DashMelee(_)
| CharacterState::TripleStrike(_)
| CharacterState::BasicBlock => true,
_ => false,
}
}
pub fn is_block(&self) -> bool { pub fn is_block(&self) -> bool {
match self { match self {
CharacterState::BasicBlock => true, CharacterState::BasicBlock => true,

View File

@ -207,6 +207,11 @@ pub struct DebugInfo {
pub num_figures_visible: u32, pub num_figures_visible: u32,
} }
pub struct HudInfo {
pub is_aiming: bool,
pub is_first_person: bool,
}
pub enum Event { pub enum Event {
SendMessage(String), SendMessage(String),
AdjustMousePan(u32), AdjustMousePan(u32),
@ -455,6 +460,7 @@ pub struct Hud {
slot_manager: slots::SlotManager, slot_manager: slots::SlotManager,
hotbar: hotbar::State, hotbar: hotbar::State,
events: Vec<Event>, events: Vec<Event>,
crosshair_opacity: f32,
} }
impl Hud { impl Hud {
@ -529,6 +535,7 @@ impl Hud {
slot_manager, slot_manager,
hotbar: hotbar::State::new(), hotbar: hotbar::State::new(),
events: Vec::new(), events: Vec::new(),
crosshair_opacity: 0.0,
} }
} }
@ -544,6 +551,7 @@ impl Hud {
global_state: &GlobalState, global_state: &GlobalState,
debug_info: DebugInfo, debug_info: DebugInfo,
dt: Duration, dt: Duration,
info: HudInfo,
) -> Vec<Event> { ) -> Vec<Event> {
let mut events = std::mem::replace(&mut self.events, Vec::new()); let mut events = std::mem::replace(&mut self.events, Vec::new());
let (ref mut ui_widgets, ref mut tooltip_manager) = self.ui.set_widgets(); let (ref mut ui_widgets, ref mut tooltip_manager) = self.ui.set_widgets();
@ -602,7 +610,10 @@ impl Hud {
.set(self.ids.death_bg, ui_widgets); .set(self.ids.death_bg, ui_widgets);
} }
// Crosshair // Crosshair
if !self.show.help && !stats.is_dead { let show_crosshair = (info.is_aiming || info.is_first_person) && !stats.is_dead;
self.crosshair_opacity = Lerp::lerp(self.crosshair_opacity, if show_crosshair { 1.0 } else { 0.0 }, 5.0 * dt.as_secs_f32());
if !self.show.help {
Image::new( Image::new(
// TODO: Do we want to match on this every frame? // TODO: Do we want to match on this every frame?
match global_state.settings.gameplay.crosshair_type { match global_state.settings.gameplay.crosshair_type {
@ -617,7 +628,7 @@ impl Hud {
1.0, 1.0,
1.0, 1.0,
1.0, 1.0,
global_state.settings.gameplay.crosshair_transp, self.crosshair_opacity * global_state.settings.gameplay.crosshair_transp,
))) )))
.set(self.ids.crosshair_outer, ui_widgets); .set(self.ids.crosshair_outer, ui_widgets);
Image::new(self.imgs.crosshair_inner) Image::new(self.imgs.crosshair_inner)
@ -2330,6 +2341,7 @@ impl Hud {
debug_info: DebugInfo, debug_info: DebugInfo,
camera: &Camera, camera: &Camera,
dt: Duration, dt: Duration,
info: HudInfo,
) -> Vec<Event> { ) -> Vec<Event> {
// conrod eats tabs. Un-eat a tabstop so tab completion can work // conrod eats tabs. Un-eat a tabstop so tab completion can work
if self.ui.ui.global_input().events().any(|event| { if self.ui.ui.global_input().events().any(|event| {
@ -2355,7 +2367,7 @@ impl Hud {
if let Some(maybe_id) = self.to_focus.take() { if let Some(maybe_id) = self.to_focus.take() {
self.ui.focus_widget(maybe_id); self.ui.focus_widget(maybe_id);
} }
let events = self.update_layout(client, global_state, debug_info, dt); let events = self.update_layout(client, global_state, debug_info, dt, info);
let camera::Dependents { let camera::Dependents {
view_mat, proj_mat, .. view_mat, proj_mat, ..
} = camera.dependents(); } = camera.dependents();

View File

@ -168,9 +168,10 @@ impl Camera {
pub fn zoom_switch(&mut self, delta: f32) { pub fn zoom_switch(&mut self, delta: f32) {
if delta > 0_f32 || self.mode != CameraMode::FirstPerson { if delta > 0_f32 || self.mode != CameraMode::FirstPerson {
let t = self.tgt_dist + delta; let t = self.tgt_dist + delta;
const MIN_THIRD_PERSON: f32 = 2.35;
match self.mode { match self.mode {
CameraMode::ThirdPerson => { CameraMode::ThirdPerson => {
if t < 1_f32 { if t < MIN_THIRD_PERSON {
self.set_mode(CameraMode::FirstPerson); self.set_mode(CameraMode::FirstPerson);
} else { } else {
self.tgt_dist = t; self.tgt_dist = t;
@ -178,14 +179,14 @@ impl Camera {
}, },
CameraMode::FirstPerson => { CameraMode::FirstPerson => {
self.set_mode(CameraMode::ThirdPerson); self.set_mode(CameraMode::ThirdPerson);
self.tgt_dist = 1_f32; self.tgt_dist = MIN_THIRD_PERSON;
}, },
} }
} }
} }
/// Get the distance of the camera from the target /// Get the distance of the camera from the target
pub fn get_distance(&self) -> f32 { self.tgt_dist } pub fn get_distance(&self) -> f32 { self.dist }
/// Set the distance of the camera from the target (i.e., zoom). /// Set the distance of the camera from the target (i.e., zoom).
pub fn set_distance(&mut self, dist: f32) { self.tgt_dist = dist; } pub fn set_distance(&mut self, dist: f32) { self.tgt_dist = dist; }
@ -197,16 +198,32 @@ impl Camera {
self.dist = f32::lerp( self.dist = f32::lerp(
self.dist, self.dist,
self.tgt_dist, self.tgt_dist,
(delta as f32) / self.interp_time(), 0.65 * (delta as f32) / self.interp_time(),
); );
} }
if (self.focus - self.tgt_focus).magnitude() > 0.01 { if (self.focus - self.tgt_focus).magnitude_squared() > 0.001 {
self.focus = Vec3::lerp( let lerped_focus = Lerp::lerp(
self.focus, self.focus,
self.tgt_focus, self.tgt_focus,
(delta as f32) / self.interp_time(), (delta as f32) / self.interp_time() * if matches!(self.mode, CameraMode::FirstPerson) {
2.0
} else {
1.0
},
); );
// Snap when close enough in x/y, but lerp otherwise
if (self.focus.xy() - self.tgt_focus.xy()).magnitude_squared() > 2.0f32.powf(2.0) {
self.focus.x = lerped_focus.x;
self.focus.y = lerped_focus.y;
} else {
self.focus.x = self.tgt_focus.x;
self.focus.y = self.tgt_focus.y;
}
// Always lerp in z
self.focus.z = lerped_focus.z;
} }
let lerp_angle = |a: f32, b: f32, rate: f32| { let lerp_angle = |a: f32, b: f32, rate: f32| {
@ -280,5 +297,13 @@ impl Camera {
} }
/// Get the mode of the camera /// Get the mode of the camera
pub fn get_mode(&self) -> CameraMode { self.mode } pub fn get_mode(&self) -> CameraMode {
// Perfom a bit of a trick... don't report first-person until the camera has lerped close
// enough to the player.
match self.mode {
CameraMode::FirstPerson if self.dist < 0.5 => CameraMode::FirstPerson,
CameraMode::FirstPerson => CameraMode::ThirdPerson,
mode => mode,
}
}
} }

View File

@ -198,7 +198,8 @@ impl Scene {
let is_running = ecs let is_running = ecs
.read_storage::<comp::Vel>() .read_storage::<comp::Vel>()
.get(scene_data.player_entity) .get(scene_data.player_entity)
.map(|v| v.0.magnitude_squared() > RUNNING_THRESHOLD.powi(2)); .map(|v| v.0.magnitude_squared() > RUNNING_THRESHOLD.powi(2))
.unwrap_or(false);
let on_ground = ecs let on_ground = ecs
.read_storage::<comp::PhysicsState>() .read_storage::<comp::PhysicsState>()
@ -229,17 +230,17 @@ impl Scene {
CameraMode::FirstPerson => { CameraMode::FirstPerson => {
if player_rolling { if player_rolling {
player_scale * 0.8 player_scale * 0.8
} else if is_running.unwrap_or(false) && on_ground.unwrap_or(false) { } else if is_running && on_ground.unwrap_or(false) {
player_scale * 1.6 + (scene_data.state.get_time() as f32 * 17.0).sin() * 0.05 player_scale * 1.65 + (scene_data.state.get_time() as f32 * 17.0).sin() * 0.05
} else { } else {
player_scale * 1.6 player_scale * 1.65
} }
}, },
CameraMode::ThirdPerson => 1.2, CameraMode::ThirdPerson => 1.65,
}; };
self.camera.set_focus_pos( self.camera.set_focus_pos(
player_pos + Vec3::unit_z() * (up + dist * 0.15 - tilt.min(0.0) * dist * 0.4), player_pos + Vec3::unit_z() * (up - tilt.min(0.0).sin() * dist * 0.6),
); );
// Tick camera for interpolation. // Tick camera for interpolation.

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
ecs::MyEntity, ecs::MyEntity,
hud::{DebugInfo, Event as HudEvent, Hud, PressBehavior}, hud::{DebugInfo, Event as HudEvent, Hud, HudInfo, PressBehavior},
i18n::{i18n_asset_key, VoxygenLocalization}, i18n::{i18n_asset_key, VoxygenLocalization},
key_state::KeyState, key_state::KeyState,
menu::char_selection::CharSelectionState, menu::char_selection::CharSelectionState,
@ -511,6 +511,19 @@ impl PlayState for SessionState {
}, },
&self.scene.camera(), &self.scene.camera(),
clock.get_last_delta(), clock.get_last_delta(),
HudInfo {
is_aiming: {
let client = self.client.borrow();
let aimed = client
.state()
.read_storage::<comp::CharacterState>()
.get(client.entity())
.map(|cs| cs.is_aimed())
.unwrap_or(false);
aimed
},
is_first_person: matches!(self.scene.camera().get_mode(), camera::CameraMode::FirstPerson),
},
); );
// Look for changes in the localization files // Look for changes in the localization files