diff --git a/voxygen/shaders/figure.frag b/voxygen/shaders/figure.frag index 60b1454ce3..a51a540a39 100644 --- a/voxygen/shaders/figure.frag +++ b/voxygen/shaders/figure.frag @@ -1,6 +1,7 @@ #version 330 core in vec3 f_pos; +in vec3 f_norm; in vec3 f_col; layout (std140) @@ -22,5 +23,13 @@ uniform u_globals { out vec4 tgt_color; void main() { - tgt_color = vec4(f_col, 1.0); + vec3 world_norm = (model_mat * vec4(f_norm, 0.0)).xyz; + + float ambient = 0.5; + + vec3 sun_dir = normalize(vec3(1.3, 1.7, 1.1)); + + float sun_diffuse = dot(sun_dir, world_norm) * 0.5; + + tgt_color = vec4(f_col * (ambient + sun_diffuse), 1.0); } diff --git a/voxygen/shaders/figure.vert b/voxygen/shaders/figure.vert index 2a27b94a49..52d8d385df 100644 --- a/voxygen/shaders/figure.vert +++ b/voxygen/shaders/figure.vert @@ -1,6 +1,7 @@ #version 330 core in vec3 v_pos; +in vec3 v_norm; in vec3 v_col; in uint v_bone_idx; @@ -30,10 +31,12 @@ uniform u_bones { }; out vec3 f_pos; +out vec3 f_norm; out vec3 f_col; void main() { f_pos = v_pos; + f_norm = v_norm; f_col = v_col; gl_Position = diff --git a/voxygen/src/anim/mod.rs b/voxygen/src/anim/mod.rs index afe754cba3..5d4ba84268 100644 --- a/voxygen/src/anim/mod.rs +++ b/voxygen/src/anim/mod.rs @@ -6,7 +6,7 @@ use crate::render::FigureBoneData; #[derive(Copy, Clone)] pub struct Bone { - parent: Option, // MUST be less than the current bone index + parent_idx: Option, // MUST be less than the current bone index pub offset: Vec3, pub ori: Quaternion, } @@ -14,50 +14,122 @@ pub struct Bone { impl Bone { pub fn default() -> Self { Self { - parent: None, + parent_idx: None, offset: Vec3::zero(), ori: Quaternion::identity(), } } + pub fn get_parent_idx(&self) -> Option { self.parent_idx } + + pub fn set_parent_idx(&mut self, parent_idx: u8) { + self.parent_idx = Some(parent_idx); + } + pub fn compute_base_matrix(&self) -> Mat4 { Mat4::::translation_3d(self.offset) * Mat4::from(self.ori) } } -#[derive(Copy, Clone)] -pub struct Skeleton { - bones: [Bone; 16], +pub trait Skeleton { + fn compute_matrices(&self) -> [FigureBoneData; 16]; } -impl Skeleton { - pub fn default() -> Self { +pub struct CharacterSkeleton { + head: Bone, + chest: Bone, + belt: Bone, + leggings: Bone, + l_hand: Bone, + r_hand: Bone, + l_foot: Bone, + r_foot: Bone, + back: Bone, +} + +impl CharacterSkeleton { + pub fn new() -> Self { Self { - bones: [Bone::default(); 16], + head: Bone::default(), + chest: Bone::default(), + belt: Bone::default(), + leggings: Bone::default(), + l_hand: Bone::default(), + r_hand: Bone::default(), + l_foot: Bone::default(), + r_foot: Bone::default(), + back: Bone::default(), } } - - pub fn with_bone(mut self, bone_idx: u8, bone: Bone) -> Self { - self.bones[bone_idx as usize] = bone; - self - } - - pub fn bone(&self, bone_idx: u8) -> &Bone { &self.bones[bone_idx as usize] } - pub fn bone_mut(&mut self, bone_idx: u8) -> &mut Bone { &mut self.bones[bone_idx as usize] } - - pub fn compute_matrices(&self) -> [FigureBoneData; 16] { - let mut bone_data = [FigureBoneData::default(); 16]; - for i in 0..16 { - bone_data[i] = FigureBoneData::new( - self.bones[i].compute_base_matrix() - // * - //if let Some(parent_idx) = self.bones[i].parent { - // bone_data[parent_idx as usize] - //} else { - // Mat4::identity() - //} - ); - } - bone_data - } +} + +impl Skeleton for CharacterSkeleton { + fn compute_matrices(&self) -> [FigureBoneData; 16] { + let chest_mat = self.chest.compute_base_matrix(); + + [ + FigureBoneData::new(self.head.compute_base_matrix()), + FigureBoneData::new(chest_mat), + FigureBoneData::new(self.belt.compute_base_matrix()), + FigureBoneData::new(self.leggings.compute_base_matrix()), + FigureBoneData::new(self.l_hand.compute_base_matrix()), + FigureBoneData::new(self.r_hand.compute_base_matrix()), + FigureBoneData::new(self.l_foot.compute_base_matrix()), + FigureBoneData::new(self.r_foot.compute_base_matrix()), + FigureBoneData::new(chest_mat * self.back.compute_base_matrix()), + FigureBoneData::default(), + FigureBoneData::default(), + FigureBoneData::default(), + FigureBoneData::default(), + FigureBoneData::default(), + FigureBoneData::default(), + FigureBoneData::default(), + ] + } +} + +pub trait Animation { + type Skeleton; + type Dependency; + + fn update_skeleton( + skeleton: &mut Self::Skeleton, + dependency: Self::Dependency, + ); +} + +pub struct RunAnimation; + +impl Animation for RunAnimation { + type Skeleton = CharacterSkeleton; + type Dependency = f64; + + fn update_skeleton( + skeleton: &mut Self::Skeleton, + time: f64, + ) { + let wave = (time as f32 * 10.0).sin(); + let wave_fast = (time as f32 * 5.0).sin(); + + skeleton.head.offset = Vec3::unit_z() * 13.0; + skeleton.head.ori = Quaternion::rotation_z(wave * 0.3); + + skeleton.chest.offset = Vec3::unit_z() * 9.0; + skeleton.chest.ori = Quaternion::rotation_z(wave * 0.3); + + skeleton.belt.offset = Vec3::unit_z() * 7.0; + skeleton.belt.ori = Quaternion::rotation_z(wave * 0.3); + + skeleton.leggings.offset = Vec3::unit_z() * 4.0; + skeleton.leggings.ori = Quaternion::rotation_z(wave * 0.3); + + skeleton.l_hand.offset = Vec3::new(-8.0, wave * 4.0, 9.0); + skeleton.r_hand.offset = Vec3::new(8.0, -wave * 4.0, 9.0); + + skeleton.l_foot.offset = Vec3::new(-3.0, -wave * 4.0, -(wave_fast.abs() - 0.5) * 3.0); + skeleton.r_foot.offset = Vec3::new(3.0, wave * 4.0, (wave_fast.abs() - 0.5) * 3.0); + + skeleton.back.offset = Vec3::new(-8.0, 5.0, 16.0); + skeleton.back.ori = Quaternion::rotation_y(2.5); + } } diff --git a/voxygen/src/mesh/segment.rs b/voxygen/src/mesh/segment.rs index 06a6048e05..3cd86b8b5b 100644 --- a/voxygen/src/mesh/segment.rs +++ b/voxygen/src/mesh/segment.rs @@ -29,14 +29,15 @@ fn create_quad( origin: Vec3, unit_x: Vec3, unit_y: Vec3, + norm: Vec3, col: Rgb, bone: u8, ) -> Quad { Quad::new( - FigureVertex::new(origin, col, bone), - FigureVertex::new(origin + unit_x, col, bone), - FigureVertex::new(origin + unit_x + unit_y, col, bone), - FigureVertex::new(origin + unit_y, col, bone), + FigureVertex::new(origin, norm, col, bone), + FigureVertex::new(origin + unit_x, norm, col, bone), + FigureVertex::new(origin + unit_x + unit_y, norm, col, bone), + FigureVertex::new(origin + unit_y, norm, col, bone), ) } @@ -61,6 +62,7 @@ impl Meshable for Segment { offs + pos.map(|e| e as f32) + Vec3::unit_y(), -Vec3::unit_y(), Vec3::unit_z(), + -Vec3::unit_x(), col, 0, )); @@ -69,6 +71,7 @@ impl Meshable for Segment { offs + pos.map(|e| e as f32) + Vec3::unit_x(), Vec3::unit_y(), Vec3::unit_z(), + Vec3::unit_x(), col, 0, )); @@ -77,6 +80,7 @@ impl Meshable for Segment { offs + pos.map(|e| e as f32), Vec3::unit_x(), Vec3::unit_z(), + -Vec3::unit_y(), col, 0, )); @@ -85,6 +89,7 @@ impl Meshable for Segment { offs + pos.map(|e| e as f32) + Vec3::unit_y(), Vec3::unit_z(), Vec3::unit_x(), + Vec3::unit_y(), col, 0, )); @@ -93,6 +98,7 @@ impl Meshable for Segment { offs + pos.map(|e| e as f32), Vec3::unit_y(), Vec3::unit_x(), + -Vec3::unit_z(), col, 0, )); @@ -101,6 +107,7 @@ impl Meshable for Segment { offs + pos.map(|e| e as f32) + Vec3::unit_z(), Vec3::unit_x(), Vec3::unit_y(), + Vec3::unit_z(), col, 0, )); diff --git a/voxygen/src/render/pipelines/figure.rs b/voxygen/src/render/pipelines/figure.rs index e7d14f272b..4c4d0de2be 100644 --- a/voxygen/src/render/pipelines/figure.rs +++ b/voxygen/src/render/pipelines/figure.rs @@ -25,6 +25,7 @@ use super::{ gfx_defines! { vertex Vertex { pos: [f32; 3] = "v_pos", + norm: [f32; 3] = "v_norm", col: [f32; 3] = "v_col", bone_idx: u8 = "v_bone_idx", } @@ -50,10 +51,11 @@ gfx_defines! { } impl Vertex { - pub fn new(pos: Vec3, col: Rgb, bone_idx: u8) -> Self { + pub fn new(pos: Vec3, norm: Vec3, col: Rgb, bone_idx: u8) -> Self { Self { pos: pos.into_array(), col: col.into_array(), + norm: norm.into_array(), bone_idx, } } diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 92bc610016..81b6fec25c 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -14,7 +14,7 @@ use crate::{ anim::Skeleton, }; -pub struct Figure { +pub struct Figure { // GPU data model: Model, bone_consts: Consts, @@ -22,15 +22,15 @@ pub struct Figure { // CPU data bone_meshes: [Option>; 16], - pub skeleton: Skeleton, + pub skeleton: S, } -impl Figure { +impl Figure { pub fn new( renderer: &mut Renderer, - bone_meshes: [Option>; 16] + bone_meshes: [Option>; 16], + skeleton: S, ) -> Result { - let skeleton = Skeleton::default(); let mut this = Self { model: renderer.create_model(&Mesh::new())?, bone_consts: renderer.create_consts(&skeleton.compute_matrices())?, diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 127aff17b2..d529fe9473 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -30,6 +30,11 @@ use crate::{ }, window::Event, mesh::Meshable, + anim::{ + Animation, + CharacterSkeleton, + RunAnimation, + }, }; // Local @@ -51,7 +56,7 @@ pub struct Scene { globals: Consts, skybox: Skybox, - test_figure: Figure, + test_figure: Figure, client: Client, } @@ -85,10 +90,10 @@ impl Scene { Some(load_segment("chest.vox").generate_mesh_with_offset(Vec3::new(-6.0, -3.0, 0.0))), Some(load_segment("belt.vox").generate_mesh_with_offset(Vec3::new(-5.0, -3.0, 0.0))), Some(load_segment("pants.vox").generate_mesh_with_offset(Vec3::new(-5.0, -3.0, 0.0))), - Some(load_segment("foot.vox").generate_mesh_with_offset(Vec3::new(-2.5, -3.0, 0.0))), - Some(load_segment("foot.vox").generate_mesh_with_offset(Vec3::new(-2.5, -3.0, 0.0))), Some(load_segment("hand.vox").generate_mesh_with_offset(Vec3::new(-2.0, -2.0, -1.0))), Some(load_segment("hand.vox").generate_mesh_with_offset(Vec3::new(-2.0, -2.0, -1.0))), + Some(load_segment("foot.vox").generate_mesh_with_offset(Vec3::new(-2.5, -3.0, 0.0))), + Some(load_segment("foot.vox").generate_mesh_with_offset(Vec3::new(-2.5, -3.0, 0.0))), Some(load_segment("sword.vox").generate_mesh_with_offset(Vec3::new(-6.5, -1.0, 0.0))), None, None, @@ -98,6 +103,7 @@ impl Scene { None, None, ], + CharacterSkeleton::new(), ) .unwrap(), @@ -142,26 +148,10 @@ impl Scene { .expect("Failed to update global constants"); // TODO: Don't do this here - let offs = (self.client.state().get_tick() as f32 * 10.0).sin(); - self.test_figure.skeleton.bone_mut(0).offset = Vec3::new(0.0, 0.0, 13.0); - self.test_figure.skeleton.bone_mut(0).ori = Quaternion::rotation_z(offs * 0.3); - // Chest - self.test_figure.skeleton.bone_mut(1).offset = Vec3::new(0.0, 0.0, 9.0); - self.test_figure.skeleton.bone_mut(2).offset = Vec3::new(0.0, 0.0, 7.0); - self.test_figure.skeleton.bone_mut(3).offset = Vec3::new(0.0, 0.0, 4.0); - self.test_figure.skeleton.bone_mut(1).ori = Quaternion::rotation_z(offs * 0.15); - self.test_figure.skeleton.bone_mut(2).ori = Quaternion::rotation_z(offs * 0.15); - self.test_figure.skeleton.bone_mut(3).ori = Quaternion::rotation_z(offs * 0.15); - //Feet - self.test_figure.skeleton.bone_mut(4).offset = Vec3::new(-3.0, -offs * 4.0, 0.0); - self.test_figure.skeleton.bone_mut(5).offset = Vec3::new(3.0, offs * 4.0, 0.0); - // Hands - self.test_figure.skeleton.bone_mut(6).offset = Vec3::new(-8.0, offs * 4.0, 9.0); - self.test_figure.skeleton.bone_mut(7).offset = Vec3::new(8.0, -offs * 4.0, 9.0); - // Sword - self.test_figure.skeleton.bone_mut(8).offset = Vec3::new(-8.0, 5.0, 24.0); - self.test_figure.skeleton.bone_mut(8).ori = Quaternion::rotation_y(2.5); - + RunAnimation::update_skeleton( + &mut self.test_figure.skeleton, + self.client.state().get_tick(), + ); self.test_figure.update_locals(renderer, FigureLocals::default()); self.test_figure.update_skeleton(renderer); }