Merge branch 'scott-c/first-person-model' into 'master'

Add first person models

See merge request veloren/veloren!443
This commit is contained in:
Joshua Barretto 2019-09-06 13:02:03 +00:00
commit 66c58840ef
6 changed files with 167 additions and 49 deletions

View File

@ -2,7 +2,7 @@ use specs::{Component, FlaggedStorage, HashMapStorage};
//use specs_idvs::IDVStorage; //use specs_idvs::IDVStorage;
use std::time::Duration; use std::time::Duration;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub enum MovementState { pub enum MovementState {
Stand, Stand,
Run, Run,
@ -22,7 +22,7 @@ impl MovementState {
} }
} }
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub enum ActionState { pub enum ActionState {
Idle, Idle,
Wield { time_left: Duration }, Wield { time_left: Duration },
@ -57,7 +57,7 @@ impl ActionState {
} }
} }
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct CharacterState { pub struct CharacterState {
pub movement: MovementState, pub movement: MovementState,
pub action: ActionState, pub action: ActionState,

View File

@ -164,6 +164,8 @@ impl Scene {
Body::Humanoid(body), Body::Humanoid(body),
Some(equipment), Some(equipment),
client.get_tick(), client.get_tick(),
CameraMode::default(),
None,
) )
.0; .0;

View File

@ -7,16 +7,23 @@ use vek::*;
const NEAR_PLANE: f32 = 0.01; const NEAR_PLANE: f32 = 0.01;
const FAR_PLANE: f32 = 10000.0; const FAR_PLANE: f32 = 10000.0;
const INTERP_TIME: f32 = 0.1; const FIRST_PERSON_INTERP_TIME: f32 = 0.05;
const THIRD_PERSON_INTERP_TIME: f32 = 0.1;
pub const MIN_ZOOM: f32 = 0.1; pub const MIN_ZOOM: f32 = 0.1;
// Possible TODO: Add more modes // Possible TODO: Add more modes
#[derive(PartialEq, Clone, Copy)] #[derive(PartialEq, Clone, Copy, Eq, Hash)]
pub enum CameraMode { pub enum CameraMode {
FirstPerson, FirstPerson,
ThirdPerson, ThirdPerson,
} }
impl Default for CameraMode {
fn default() -> Self {
Self::ThirdPerson
}
}
pub struct Camera { pub struct Camera {
tgt_focus: Vec3<f32>, tgt_focus: Vec3<f32>,
focus: Vec3<f32>, focus: Vec3<f32>,
@ -166,11 +173,26 @@ impl Camera {
// This is horribly frame time dependent, but so is most of the game // This is horribly frame time dependent, but so is most of the game
let delta = self.last_time.replace(time).map_or(0.0, |t| time - t); let delta = self.last_time.replace(time).map_or(0.0, |t| time - t);
if (self.dist - self.tgt_dist).abs() > 0.01 { if (self.dist - self.tgt_dist).abs() > 0.01 {
self.dist = f32::lerp(self.dist, self.tgt_dist, (delta as f32) / INTERP_TIME); self.dist = f32::lerp(
self.dist,
self.tgt_dist,
(delta as f32) / self.interp_time(),
);
} }
if (self.focus - self.tgt_focus).magnitude() > 0.01 { if (self.focus - self.tgt_focus).magnitude() > 0.01 {
self.focus = Vec3::lerp(self.focus, self.tgt_focus, (delta as f32) / INTERP_TIME); self.focus = Vec3::lerp(
self.focus,
self.tgt_focus,
(delta as f32) / self.interp_time(),
);
}
}
pub fn interp_time(&self) -> f32 {
match self.mode {
CameraMode::FirstPerson => FIRST_PERSON_INTERP_TIME,
CameraMode::ThirdPerson => THIRD_PERSON_INTERP_TIME,
} }
} }

View File

@ -2,17 +2,18 @@ use super::load::*;
use crate::{ use crate::{
anim::SkeletonAttr, anim::SkeletonAttr,
render::{FigurePipeline, Mesh, Model, Renderer}, render::{FigurePipeline, Mesh, Model, Renderer},
scene::camera::CameraMode,
}; };
use common::{ use common::{
assets::watch::ReloadIndicator, assets::watch::ReloadIndicator,
comp::{Body, Equipment}, comp::{Body, CharacterState, Equipment},
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
#[derive(PartialEq, Eq, Hash, Clone)] #[derive(PartialEq, Eq, Hash, Clone)]
enum FigureKey { enum FigureKey {
Simple(Body), Simple(Body),
Complex(Body, Option<Equipment>), Complex(Body, Option<Equipment>, CameraMode, Option<CharacterState>),
} }
pub struct FigureModelCache { pub struct FigureModelCache {
@ -34,9 +35,16 @@ impl FigureModelCache {
body: Body, body: Body,
equipment: Option<&Equipment>, equipment: Option<&Equipment>,
tick: u64, tick: u64,
camera_mode: CameraMode,
character_state: Option<&CharacterState>,
) -> &(Model<FigurePipeline>, SkeletonAttr) { ) -> &(Model<FigurePipeline>, SkeletonAttr) {
let key = if equipment.is_some() { let key = if equipment.is_some() {
FigureKey::Complex(body, equipment.cloned()) FigureKey::Complex(
body,
equipment.cloned(),
camera_mode,
character_state.cloned(),
)
} else { } else {
FigureKey::Simple(body) FigureKey::Simple(body)
}; };
@ -54,27 +62,84 @@ impl FigureModelCache {
HumHeadSpec::load_watched(&mut self.manifest_indicator); HumHeadSpec::load_watched(&mut self.manifest_indicator);
let bone_meshes = match body { let bone_meshes = match body {
Body::Humanoid(body) => [ Body::Humanoid(body) => [
Some(humanoid_head_spec.mesh_head( match camera_mode {
body.race, CameraMode::ThirdPerson => {
body.body_type, Some(humanoid_head_spec.mesh_head(
body.hair_color, body.race,
body.hair_style, body.body_type,
body.beard, body.hair_color,
body.eye_color, body.hair_style,
body.skin, body.beard,
body.eyebrows, body.eye_color,
body.accessory, body.skin,
)), body.eyebrows,
Some(mesh_chest(body.chest)), body.accessory,
Some(mesh_belt(body.belt)), ))
Some(mesh_pants(body.pants)), }
Some(mesh_left_hand(body.hand)), CameraMode::FirstPerson => None,
Some(mesh_right_hand(body.hand)), },
Some(mesh_left_foot(body.foot)), match camera_mode {
Some(mesh_right_foot(body.foot)), CameraMode::ThirdPerson => Some(mesh_chest(body.chest)),
Some(mesh_main(equipment.and_then(|e| e.main.as_ref()))), CameraMode::FirstPerson => None,
Some(mesh_left_shoulder(body.shoulder)), },
Some(mesh_right_shoulder(body.shoulder)), match camera_mode {
CameraMode::ThirdPerson => Some(mesh_belt(body.belt)),
CameraMode::FirstPerson => None,
},
match camera_mode {
CameraMode::ThirdPerson => Some(mesh_pants(body.pants)),
CameraMode::FirstPerson => None,
},
if camera_mode == CameraMode::FirstPerson
&& character_state
.map(|cs| cs.movement.is_roll())
.unwrap_or_default()
{
None
} else {
Some(mesh_left_hand(body.hand))
},
if character_state
.map(|cs| cs.movement.is_roll())
.unwrap_or_default()
{
None
} else {
Some(mesh_right_hand(body.hand))
},
match camera_mode {
CameraMode::ThirdPerson => Some(mesh_left_foot(body.foot)),
CameraMode::FirstPerson => None,
},
match camera_mode {
CameraMode::ThirdPerson => Some(mesh_right_foot(body.foot)),
CameraMode::FirstPerson => None,
},
if camera_mode != CameraMode::FirstPerson
|| character_state
.map(|cs| {
cs.action.is_attack()
|| cs.action.is_block()
|| cs.action.is_wield()
})
.unwrap_or_default()
{
Some(mesh_main(equipment.and_then(|e| e.main.as_ref())))
} else {
None
},
match camera_mode {
CameraMode::ThirdPerson => {
Some(mesh_left_shoulder(body.shoulder))
}
CameraMode::FirstPerson => None,
},
match camera_mode {
CameraMode::ThirdPerson => {
Some(mesh_right_shoulder(body.shoulder))
}
CameraMode::FirstPerson => None,
},
Some(mesh_draw()), Some(mesh_draw()),
None, None,
None, None,

View File

@ -116,7 +116,14 @@ impl FigureMgr {
let skeleton_attr = &self let skeleton_attr = &self
.model_cache .model_cache
.get_or_create_model(renderer, *body, stats.map(|s| &s.equipment), tick) .get_or_create_model(
renderer,
*body,
stats.map(|s| &s.equipment),
tick,
CameraMode::default(),
None,
)
.1; .1;
match body { match body {
@ -341,6 +348,11 @@ impl FigureMgr {
let frustum = camera.frustum(client); let frustum = camera.frustum(client);
let character_state_storage = client
.state()
.read_storage::<common::comp::CharacterState>();
let character_state = character_state_storage.get(client.entity());
for (entity, _, _, _, body, stats, _) in ( for (entity, _, _, _, body, stats, _) in (
&ecs.entities(), &ecs.entities(),
&ecs.read_storage::<Pos>(), &ecs.read_storage::<Pos>(),
@ -381,23 +393,26 @@ impl FigureMgr {
.get(&entity) .get(&entity)
.map(|state| (state.locals(), state.bone_consts())), .map(|state| (state.locals(), state.bone_consts())),
} { } {
let is_player = entity == client.entity();
let player_camera_mode = if is_player {
camera.get_mode()
} else {
CameraMode::default()
};
let model = &self let model = &self
.model_cache .model_cache
.get_or_create_model(renderer, *body, stats.map(|s| &s.equipment), tick) .get_or_create_model(
renderer,
*body,
stats.map(|s| &s.equipment),
tick,
player_camera_mode,
if is_player { character_state } else { None },
)
.0; .0;
// Don't render the player's body while in first person mode
if camera.get_mode() == CameraMode::FirstPerson
&& client
.state()
.read_storage::<Body>()
.get(client.entity())
.is_some()
&& entity == client.entity()
{
continue;
}
renderer.render_figure(model, globals, locals, bone_consts, lights); renderer.render_figure(model, globals, locals, bone_consts, lights);
} else { } else {
debug!("Body has no saved figure"); debug!("Body has no saved figure");

View File

@ -134,14 +134,28 @@ impl Scene {
.get(client.entity()) .get(client.entity())
.map_or(Vec3::zero(), |pos| pos.0); .map_or(Vec3::zero(), |pos| pos.0);
let player_rolling = client
.state()
.ecs()
.read_storage::<comp::CharacterState>()
.get(client.entity())
.map_or(false, |cs| cs.movement.is_roll());
// Alter camera position to match player. // Alter camera position to match player.
let tilt = self.camera.get_orientation().y; let tilt = self.camera.get_orientation().y;
let dist = self.camera.get_distance(); let dist = self.camera.get_distance();
let up = if self.camera.get_mode() == CameraMode::FirstPerson {
1.5 let up = match self.camera.get_mode() {
} else { CameraMode::FirstPerson => {
1.2 if player_rolling {
0.75
} else {
1.5
}
}
CameraMode::ThirdPerson => 1.2,
}; };
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.75), player_pos + Vec3::unit_z() * (up + dist * 0.15 - tilt.min(0.0) * dist * 0.75),
); );