mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added figures, segments, test .vox files, basic animation test
This commit is contained in:
parent
b37a6b67f9
commit
8184bc6fc0
@ -7,3 +7,4 @@ edition = "2018"
|
||||
[dependencies]
|
||||
specs = "0.14"
|
||||
vek = "0.9"
|
||||
dot_vox = "1.0"
|
||||
|
@ -1,7 +1,7 @@
|
||||
pub mod phys;
|
||||
|
||||
// External
|
||||
use specs::{World as EcsWorld, Builder};
|
||||
use specs::World as EcsWorld;
|
||||
|
||||
pub fn register_local_components(ecs_world: &mut EcsWorld) {
|
||||
ecs_world.register::<phys::Pos>();
|
||||
|
33
common/src/figure/cell.rs
Normal file
33
common/src/figure/cell.rs
Normal file
@ -0,0 +1,33 @@
|
||||
// Library
|
||||
use vek::*;
|
||||
|
||||
/// A type representing a single voxel in a figure
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Cell {
|
||||
Filled([u8; 3]),
|
||||
Empty,
|
||||
}
|
||||
|
||||
impl Cell {
|
||||
pub fn empty() -> Self {
|
||||
Cell::Empty
|
||||
}
|
||||
|
||||
pub fn new(rgb: Rgb<u8>) -> Self {
|
||||
Cell::Filled(rgb.into_array())
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
match self {
|
||||
Cell::Filled(_) => false,
|
||||
Cell::Empty => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_color(&self) -> Option<Rgb<u8>> {
|
||||
match self {
|
||||
Cell::Filled(col) => Some(Rgb::from(*col)),
|
||||
Cell::Empty => None,
|
||||
}
|
||||
}
|
||||
}
|
63
common/src/figure/mod.rs
Normal file
63
common/src/figure/mod.rs
Normal file
@ -0,0 +1,63 @@
|
||||
pub mod cell;
|
||||
|
||||
// Library
|
||||
use vek::*;
|
||||
use dot_vox::DotVoxData;
|
||||
|
||||
// Crate
|
||||
use crate::{
|
||||
vol::WriteVol,
|
||||
volumes::dyna::Dyna,
|
||||
};
|
||||
|
||||
// Local
|
||||
use self::cell::Cell;
|
||||
|
||||
/// A type representing a single figure bone (e.g: the limb of a character).
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Bone {
|
||||
origin: Vec3<f32>,
|
||||
offset: Vec3<f32>,
|
||||
ori: Vec3<f32>,
|
||||
}
|
||||
|
||||
/// A type representing a volume that may be part of an animated figure.
|
||||
///
|
||||
/// Figures are used to represent things like characters, NPCs, mobs, etc.
|
||||
pub type Segment = Dyna<Cell, ()>;
|
||||
|
||||
impl From<DotVoxData> for Segment {
|
||||
fn from(dot_vox_data: DotVoxData) -> Self {
|
||||
if let Some(model) = dot_vox_data.models.get(0) {
|
||||
let palette = dot_vox_data
|
||||
.palette
|
||||
.iter()
|
||||
.map(|col| Rgba::from(col.to_ne_bytes()).into())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut segment = Segment::filled(
|
||||
Vec3::new(
|
||||
model.size.x,
|
||||
model.size.y,
|
||||
model.size.z,
|
||||
),
|
||||
Cell::empty(),
|
||||
(),
|
||||
);
|
||||
|
||||
for voxel in &model.voxels {
|
||||
if let Some(&color) = palette.get(voxel.i as usize) {
|
||||
// TODO: Maybe don't ignore this error?
|
||||
let _ = segment.set(
|
||||
Vec3::new(voxel.x, voxel.y, voxel.z).map(|e| e as i32),
|
||||
Cell::new(color),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
segment
|
||||
} else {
|
||||
Segment::filled(Vec3::zero(), Cell::empty(), ())
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
pub mod clock;
|
||||
pub mod comp;
|
||||
pub mod figure;
|
||||
pub mod state;
|
||||
pub mod terrain;
|
||||
pub mod volumes;
|
||||
|
@ -8,7 +8,6 @@ use specs::World as EcsWorld;
|
||||
use crate::{
|
||||
comp,
|
||||
terrain::TerrainMap,
|
||||
vol::VolSize,
|
||||
};
|
||||
|
||||
/// How much faster should an in-game day be compared to a real day?
|
||||
|
@ -1,3 +1,4 @@
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Block {
|
||||
kind: u8,
|
||||
color: [u8; 3],
|
||||
|
@ -1,27 +1,76 @@
|
||||
// Library
|
||||
use vek::*;
|
||||
|
||||
/// A volume that contains voxel data.
|
||||
pub trait BaseVol {
|
||||
type Vox;
|
||||
type Err;
|
||||
}
|
||||
|
||||
pub trait SizedVol: BaseVol {
|
||||
const SIZE: Vec3<u32>;
|
||||
// Utility types
|
||||
|
||||
pub struct VoxPosIter {
|
||||
pos: Vec3<u32>,
|
||||
sz: Vec3<u32>,
|
||||
}
|
||||
|
||||
impl Iterator for VoxPosIter {
|
||||
type Item = Vec3<i32>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut old_pos = self.pos;
|
||||
|
||||
if old_pos.z == self.sz.z {
|
||||
old_pos.z = 0;
|
||||
old_pos.y += 1;
|
||||
if old_pos.y == self.sz.y {
|
||||
old_pos.y = 0;
|
||||
old_pos.x += 1;
|
||||
if old_pos.x == self.sz.x {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.pos = old_pos + Vec3::unit_z();
|
||||
|
||||
Some(old_pos.map(|e| e as i32))
|
||||
}
|
||||
}
|
||||
|
||||
/// A volume that has a finite size.
|
||||
pub trait SizedVol: BaseVol {
|
||||
/// Get the size of the volume.
|
||||
#[inline(always)]
|
||||
fn get_size(&self) -> Vec3<u32>;
|
||||
|
||||
/// Iterate through all potential voxel positions in this volume
|
||||
fn iter_positions(&self) -> VoxPosIter {
|
||||
VoxPosIter {
|
||||
pos: Vec3::zero(),
|
||||
sz: self.get_size(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A volume that provided read access to its voxel data.
|
||||
pub trait ReadVol: BaseVol {
|
||||
/// Get a reference to the voxel at the provided position in the volume.
|
||||
#[inline(always)]
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Err>;
|
||||
}
|
||||
|
||||
/// A volume that provides write access to its voxel data.
|
||||
pub trait WriteVol: BaseVol {
|
||||
/// Set the voxel at the provided position in the volume to the provided value.
|
||||
#[inline(always)]
|
||||
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), Self::Err>;
|
||||
}
|
||||
|
||||
// Utility traits
|
||||
|
||||
/// Used to specify a volume's compile-time size. This exists as a substitute until const generics
|
||||
/// are implemented.
|
||||
pub trait VolSize {
|
||||
const SIZE: Vec3<u32>;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ pub enum ChunkErr {
|
||||
OutOfBounds,
|
||||
}
|
||||
|
||||
/// A volume with dimensions known at compile-time.
|
||||
// V = Voxel
|
||||
// S = Size (replace when const generics are a thing)
|
||||
// M = Metadata
|
||||
@ -27,6 +28,8 @@ pub struct Chunk<V, S: VolSize, M> {
|
||||
}
|
||||
|
||||
impl<V, S: VolSize, M> Chunk<V, S, M> {
|
||||
/// Used to transform a voxel position in the volume into its corresponding index in the voxel
|
||||
// array.
|
||||
#[inline(always)]
|
||||
fn idx_for(pos: Vec3<i32>) -> Option<usize> {
|
||||
if
|
||||
@ -50,7 +53,8 @@ impl<V, S: VolSize, M> BaseVol for Chunk<V, S, M> {
|
||||
}
|
||||
|
||||
impl<V, S: VolSize, M> SizedVol for Chunk<V, S, M> {
|
||||
const SIZE: Vec3<u32> = Vec3 { x: 32, y: 32, z: 32 };
|
||||
#[inline(always)]
|
||||
fn get_size(&self) -> Vec3<u32> { S::SIZE }
|
||||
}
|
||||
|
||||
impl<V, S: VolSize, M> ReadVol for Chunk<V, S, M> {
|
||||
@ -73,6 +77,8 @@ impl<V, S: VolSize, M> WriteVol for Chunk<V, S, M> {
|
||||
}
|
||||
|
||||
impl<V: Clone, S: VolSize, M> Chunk<V, S, M> {
|
||||
/// Create a new `Chunk` with the provided dimensions and all voxels filled with duplicates of
|
||||
/// the provided voxel.
|
||||
pub fn filled(vox: V, meta: M) -> Self {
|
||||
Self {
|
||||
vox: vec![vox; S::SIZE.product() as usize],
|
||||
@ -81,10 +87,12 @@ impl<V: Clone, S: VolSize, M> Chunk<V, S, M> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a reference to the internal metadata.
|
||||
pub fn metadata(&self) -> &M {
|
||||
&self.meta
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the internal metadata.
|
||||
pub fn metadata_mut(&mut self) -> &mut M {
|
||||
&mut self.meta
|
||||
}
|
||||
|
95
common/src/volumes/dyna.rs
Normal file
95
common/src/volumes/dyna.rs
Normal file
@ -0,0 +1,95 @@
|
||||
// Library
|
||||
use vek::*;
|
||||
|
||||
// Local
|
||||
use crate::vol::{
|
||||
BaseVol,
|
||||
SizedVol,
|
||||
ReadVol,
|
||||
WriteVol,
|
||||
};
|
||||
|
||||
pub enum DynaErr {
|
||||
OutOfBounds,
|
||||
}
|
||||
|
||||
/// A volume with dimensions known only at the creation of the object.
|
||||
// V = Voxel
|
||||
// S = Size (replace when const generics are a thing)
|
||||
// M = Metadata
|
||||
pub struct Dyna<V, M> {
|
||||
vox: Vec<V>,
|
||||
meta: M,
|
||||
sz: Vec3<u32>,
|
||||
}
|
||||
|
||||
impl<V, M> Dyna<V, M> {
|
||||
/// Used to transform a voxel position in the volume into its corresponding index in the voxel
|
||||
// array.
|
||||
#[inline(always)]
|
||||
fn idx_for(sz: Vec3<u32>, pos: Vec3<i32>) -> Option<usize> {
|
||||
if
|
||||
pos.map(|e| e >= 0).reduce_and() &&
|
||||
pos.map2(sz, |e, lim| e < lim as i32).reduce_and()
|
||||
{
|
||||
Some((
|
||||
pos.x * sz.y as i32 * sz.z as i32 +
|
||||
pos.y * sz.z as i32 +
|
||||
pos.z
|
||||
) as usize)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, M> BaseVol for Dyna<V, M> {
|
||||
type Vox = V;
|
||||
type Err = DynaErr;
|
||||
}
|
||||
|
||||
impl<V, M> SizedVol for Dyna<V, M> {
|
||||
#[inline(always)]
|
||||
fn get_size(&self) -> Vec3<u32> { self.sz }
|
||||
}
|
||||
|
||||
impl<V, M> ReadVol for Dyna<V, M> {
|
||||
#[inline(always)]
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&V, DynaErr> {
|
||||
Self::idx_for(self.sz, pos)
|
||||
.and_then(|idx| self.vox.get(idx))
|
||||
.ok_or(DynaErr::OutOfBounds)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, M> WriteVol for Dyna<V, M> {
|
||||
#[inline(always)]
|
||||
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), DynaErr> {
|
||||
Self::idx_for(self.sz, pos)
|
||||
.and_then(|idx| self.vox.get_mut(idx))
|
||||
.map(|old_vox| *old_vox = vox)
|
||||
.ok_or(DynaErr::OutOfBounds)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: Clone, M> Dyna<V, M> {
|
||||
/// Create a new `Dyna` with the provided dimensions and all voxels filled with duplicates of
|
||||
/// the provided voxel.
|
||||
pub fn filled(sz: Vec3<u32>, vox: V, meta: M) -> Self {
|
||||
Self {
|
||||
vox: vec![vox; sz.product() as usize],
|
||||
meta,
|
||||
sz,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a reference to the internal metadata.
|
||||
pub fn metadata(&self) -> &M {
|
||||
&self.meta
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the internal metadata.
|
||||
pub fn metadata_mut(&mut self) -> &mut M {
|
||||
&mut self.meta
|
||||
}
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
pub mod dyna;
|
||||
pub mod chunk;
|
||||
pub mod vol_map;
|
||||
|
@ -7,7 +7,7 @@ edition = "2018"
|
||||
[features]
|
||||
gl = ["gfx_device_gl"]
|
||||
|
||||
default = []
|
||||
default = ["gl"]
|
||||
|
||||
[dependencies]
|
||||
common = { package = "veloren-common", path = "../common" }
|
||||
@ -28,3 +28,4 @@ failure = "0.1"
|
||||
lazy_static = "1.1"
|
||||
log = "0.4"
|
||||
pretty_env_logger = "0.3"
|
||||
dot_vox = "1.0"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#version 330 core
|
||||
|
||||
in vec3 f_pos;
|
||||
in vec3 f_col;
|
||||
|
||||
layout (std140)
|
||||
uniform u_locals {
|
||||
@ -21,5 +22,5 @@ uniform u_globals {
|
||||
out vec4 tgt_color;
|
||||
|
||||
void main() {
|
||||
tgt_color = vec4(f_pos, 1.0);
|
||||
tgt_color = vec4(f_col, 1.0);
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
in vec3 v_pos;
|
||||
in vec3 v_col;
|
||||
in uint v_bone;
|
||||
in uint v_bone_idx;
|
||||
|
||||
layout (std140)
|
||||
uniform u_locals {
|
||||
@ -20,13 +20,26 @@ uniform u_globals {
|
||||
vec4 time;
|
||||
};
|
||||
|
||||
struct BoneData {
|
||||
mat4 bone_mat;
|
||||
};
|
||||
|
||||
layout (std140)
|
||||
uniform u_bones {
|
||||
BoneData bones[16];
|
||||
};
|
||||
|
||||
out vec3 f_pos;
|
||||
out vec3 f_col;
|
||||
|
||||
void main() {
|
||||
f_pos = v_pos;
|
||||
f_col = v_col;
|
||||
|
||||
gl_Position =
|
||||
proj_mat *
|
||||
view_mat *
|
||||
vec4(0.5 * v_pos + cam_pos.xyz, 1);
|
||||
model_mat *
|
||||
bones[v_bone_idx].bone_mat *
|
||||
vec4(v_pos, 1);
|
||||
}
|
63
voxygen/src/anim/mod.rs
Normal file
63
voxygen/src/anim/mod.rs
Normal file
@ -0,0 +1,63 @@
|
||||
// Library
|
||||
use vek::*;
|
||||
|
||||
// Crate
|
||||
use crate::render::FigureBoneData;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Bone {
|
||||
parent: Option<u8>, // MUST be less than the current bone index
|
||||
pub offset: Vec3<f32>,
|
||||
pub ori: Quaternion<f32>,
|
||||
}
|
||||
|
||||
impl Bone {
|
||||
pub fn default() -> Self {
|
||||
Self {
|
||||
parent: None,
|
||||
offset: Vec3::zero(),
|
||||
ori: Quaternion::identity(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_base_matrix(&self) -> Mat4<f32> {
|
||||
Mat4::<f32>::translation_3d(self.offset) * Mat4::from(self.ori)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Skeleton {
|
||||
bones: [Bone; 16],
|
||||
}
|
||||
|
||||
impl Skeleton {
|
||||
pub fn default() -> Self {
|
||||
Self {
|
||||
bones: [Bone::default(); 16],
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
pub mod anim;
|
||||
pub mod error;
|
||||
pub mod menu;
|
||||
pub mod mesh;
|
||||
pub mod render;
|
||||
pub mod scene;
|
||||
pub mod session;
|
||||
|
20
voxygen/src/mesh/mod.rs
Normal file
20
voxygen/src/mesh/mod.rs
Normal file
@ -0,0 +1,20 @@
|
||||
pub mod segment;
|
||||
|
||||
// Library
|
||||
use vek::*;
|
||||
|
||||
// Crate
|
||||
use crate::render::{
|
||||
self,
|
||||
Mesh,
|
||||
};
|
||||
|
||||
pub trait Meshable {
|
||||
type Pipeline: render::Pipeline;
|
||||
|
||||
fn generate_mesh(&self) -> Mesh<Self::Pipeline> {
|
||||
self.generate_mesh_with_offset(Vec3::zero())
|
||||
}
|
||||
|
||||
fn generate_mesh_with_offset(&self, offs: Vec3<f32>) -> Mesh<Self::Pipeline>;
|
||||
}
|
112
voxygen/src/mesh/segment.rs
Normal file
112
voxygen/src/mesh/segment.rs
Normal file
@ -0,0 +1,112 @@
|
||||
// Project
|
||||
use common::figure::Segment;
|
||||
|
||||
// Library
|
||||
use vek::*;
|
||||
|
||||
// Project
|
||||
use common::vol::{
|
||||
SizedVol,
|
||||
ReadVol,
|
||||
};
|
||||
|
||||
// Crate
|
||||
use crate::{
|
||||
mesh::Meshable,
|
||||
render::{
|
||||
self,
|
||||
Mesh,
|
||||
Quad,
|
||||
FigurePipeline,
|
||||
},
|
||||
};
|
||||
|
||||
type FigureVertex = <FigurePipeline as render::Pipeline>::Vertex;
|
||||
|
||||
// Utility function
|
||||
// TODO: Evaluate how useful this is
|
||||
fn create_quad(
|
||||
origin: Vec3<f32>,
|
||||
unit_x: Vec3<f32>,
|
||||
unit_y: Vec3<f32>,
|
||||
col: Rgb<f32>,
|
||||
bone: u8,
|
||||
) -> Quad<FigurePipeline> {
|
||||
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),
|
||||
)
|
||||
}
|
||||
|
||||
impl Meshable for Segment {
|
||||
type Pipeline = FigurePipeline;
|
||||
|
||||
fn generate_mesh_with_offset(&self, offs: Vec3<f32>) -> Mesh<FigurePipeline> {
|
||||
let mut mesh = Mesh::new();
|
||||
|
||||
for pos in self.iter_positions() {
|
||||
if let Some(col) = self
|
||||
.get(pos)
|
||||
.ok()
|
||||
.and_then(|vox| vox.get_color())
|
||||
{
|
||||
let col = col.map(|e| e as f32 / 255.0);
|
||||
|
||||
// TODO: Face occlusion
|
||||
|
||||
// -x
|
||||
mesh.push_quad(create_quad(
|
||||
offs + pos.map(|e| e as f32) + Vec3::unit_y(),
|
||||
-Vec3::unit_y(),
|
||||
Vec3::unit_z(),
|
||||
col,
|
||||
0,
|
||||
));
|
||||
// +x
|
||||
mesh.push_quad(create_quad(
|
||||
offs + pos.map(|e| e as f32) + Vec3::unit_x(),
|
||||
Vec3::unit_y(),
|
||||
Vec3::unit_z(),
|
||||
col,
|
||||
0,
|
||||
));
|
||||
// -y
|
||||
mesh.push_quad(create_quad(
|
||||
offs + pos.map(|e| e as f32),
|
||||
Vec3::unit_x(),
|
||||
Vec3::unit_z(),
|
||||
col,
|
||||
0,
|
||||
));
|
||||
// +y
|
||||
mesh.push_quad(create_quad(
|
||||
offs + pos.map(|e| e as f32) + Vec3::unit_y(),
|
||||
Vec3::unit_z(),
|
||||
Vec3::unit_x(),
|
||||
col,
|
||||
0,
|
||||
));
|
||||
// -z
|
||||
mesh.push_quad(create_quad(
|
||||
offs + pos.map(|e| e as f32),
|
||||
Vec3::unit_y(),
|
||||
Vec3::unit_x(),
|
||||
col,
|
||||
0,
|
||||
));
|
||||
// +z
|
||||
mesh.push_quad(create_quad(
|
||||
offs + pos.map(|e| e as f32) + Vec3::unit_z(),
|
||||
Vec3::unit_x(),
|
||||
Vec3::unit_y(),
|
||||
col,
|
||||
0,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
mesh
|
||||
}
|
||||
}
|
@ -19,9 +19,9 @@ pub struct Consts<T: Copy + gfx::traits::Pod> {
|
||||
|
||||
impl<T: Copy + gfx::traits::Pod> Consts<T> {
|
||||
/// Create a new `Const<T>`
|
||||
pub fn new(factory: &mut gfx_backend::Factory) -> Self {
|
||||
pub fn new(factory: &mut gfx_backend::Factory, len: usize) -> Self {
|
||||
Self {
|
||||
buf: factory.create_constant_buffer(1),
|
||||
buf: factory.create_constant_buffer(len),
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,9 +29,9 @@ impl<T: Copy + gfx::traits::Pod> Consts<T> {
|
||||
pub fn update(
|
||||
&mut self,
|
||||
encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
||||
val: T,
|
||||
vals: &[T],
|
||||
) -> Result<(), RenderError> {
|
||||
encoder.update_buffer(&self.buf, &[val], 0)
|
||||
encoder.update_buffer(&self.buf, vals, 0)
|
||||
.map_err(|err| RenderError::UpdateError(err))
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
use super::Pipeline;
|
||||
|
||||
/// A `Vec`-based mesh structure used to store mesh data on the CPU.
|
||||
#[derive(Clone)]
|
||||
pub struct Mesh<P: Pipeline> {
|
||||
verts: Vec<P::Vertex>,
|
||||
}
|
||||
@ -43,6 +44,22 @@ impl<P: Pipeline> Mesh<P> {
|
||||
self.verts.push(quad.d);
|
||||
self.verts.push(quad.a);
|
||||
}
|
||||
|
||||
/// Push the vertices of another mesh onto the end of this mesh
|
||||
pub fn push_mesh(&mut self, other: &Mesh<P>) {
|
||||
self.verts.extend_from_slice(other.vertices());
|
||||
}
|
||||
|
||||
/// Push the vertices of another mesh onto the end of this mesh
|
||||
pub fn push_mesh_map<F: FnMut(P::Vertex) -> P::Vertex>(&mut self, other: &Mesh<P>, mut f: F) {
|
||||
// Reserve enough space in our Vec. This isn't necessary, but it tends to reduce the number
|
||||
// of required (re)allocations.
|
||||
self.verts.reserve(other.vertices().len());
|
||||
|
||||
for vert in other.vertices() {
|
||||
self.verts.push(f(vert.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a triangle stored on the CPU.
|
||||
|
@ -8,14 +8,15 @@ mod util;
|
||||
// Reexports
|
||||
pub use self::{
|
||||
consts::Consts,
|
||||
mesh::{Mesh, Quad},
|
||||
mesh::{Mesh, Tri, Quad},
|
||||
model::Model,
|
||||
renderer::{Renderer, TgtColorFmt, TgtDepthFmt},
|
||||
pipelines::{
|
||||
Globals,
|
||||
character::{
|
||||
CharacterPipeline,
|
||||
Locals as CharacterLocals,
|
||||
figure::{
|
||||
FigurePipeline,
|
||||
Locals as FigureLocals,
|
||||
BoneData as FigureBoneData,
|
||||
},
|
||||
skybox::{
|
||||
create_mesh as create_skybox_mesh,
|
||||
@ -47,7 +48,7 @@ pub enum RenderError {
|
||||
/// # Examples
|
||||
///
|
||||
/// - `SkyboxPipeline`
|
||||
/// - `CharacterPipeline`
|
||||
/// - `FigurePipeline`
|
||||
pub trait Pipeline {
|
||||
type Vertex:
|
||||
Clone +
|
||||
|
@ -1,47 +0,0 @@
|
||||
// Library
|
||||
use gfx::{
|
||||
self,
|
||||
// Macros
|
||||
gfx_defines,
|
||||
gfx_vertex_struct_meta,
|
||||
gfx_constant_struct_meta,
|
||||
gfx_impl_struct_meta,
|
||||
gfx_pipeline,
|
||||
gfx_pipeline_inner,
|
||||
};
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
Globals,
|
||||
super::{
|
||||
Pipeline,
|
||||
TgtColorFmt,
|
||||
TgtDepthFmt,
|
||||
},
|
||||
};
|
||||
|
||||
gfx_defines! {
|
||||
vertex Vertex {
|
||||
pos: [f32; 3] = "v_pos",
|
||||
col: [f32; 3] = "v_col",
|
||||
bone: u8 = "v_bone",
|
||||
}
|
||||
|
||||
constant Locals {
|
||||
model_mat: [[f32; 4]; 4] = "model_mat",
|
||||
}
|
||||
|
||||
pipeline pipe {
|
||||
vbuf: gfx::VertexBuffer<Vertex> = (),
|
||||
locals: gfx::ConstantBuffer<Locals> = "u_locals",
|
||||
globals: gfx::ConstantBuffer<Globals> = "u_globals",
|
||||
tgt_color: gfx::RenderTarget<TgtColorFmt> = "tgt_color",
|
||||
tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::LESS_EQUAL_WRITE,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CharacterPipeline;
|
||||
|
||||
impl Pipeline for CharacterPipeline {
|
||||
type Vertex = Vertex;
|
||||
}
|
93
voxygen/src/render/pipelines/figure.rs
Normal file
93
voxygen/src/render/pipelines/figure.rs
Normal file
@ -0,0 +1,93 @@
|
||||
// Library
|
||||
use gfx::{
|
||||
self,
|
||||
// Macros
|
||||
gfx_defines,
|
||||
gfx_vertex_struct_meta,
|
||||
gfx_constant_struct_meta,
|
||||
gfx_impl_struct_meta,
|
||||
gfx_pipeline,
|
||||
gfx_pipeline_inner,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
Globals,
|
||||
super::{
|
||||
Pipeline,
|
||||
TgtColorFmt,
|
||||
TgtDepthFmt,
|
||||
util::arr_to_mat,
|
||||
},
|
||||
};
|
||||
|
||||
gfx_defines! {
|
||||
vertex Vertex {
|
||||
pos: [f32; 3] = "v_pos",
|
||||
col: [f32; 3] = "v_col",
|
||||
bone_idx: u8 = "v_bone_idx",
|
||||
}
|
||||
|
||||
constant Locals {
|
||||
model_mat: [[f32; 4]; 4] = "model_mat",
|
||||
}
|
||||
|
||||
constant BoneData {
|
||||
bone_mat: [[f32; 4]; 4] = "bone_mat",
|
||||
}
|
||||
|
||||
pipeline pipe {
|
||||
vbuf: gfx::VertexBuffer<Vertex> = (),
|
||||
|
||||
locals: gfx::ConstantBuffer<Locals> = "u_locals",
|
||||
globals: gfx::ConstantBuffer<Globals> = "u_globals",
|
||||
bones: gfx::ConstantBuffer<BoneData> = "u_bones",
|
||||
|
||||
tgt_color: gfx::RenderTarget<TgtColorFmt> = "tgt_color",
|
||||
tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::LESS_EQUAL_WRITE,
|
||||
}
|
||||
}
|
||||
|
||||
impl Vertex {
|
||||
pub fn new(pos: Vec3<f32>, col: Rgb<f32>, bone_idx: u8) -> Self {
|
||||
Self {
|
||||
pos: pos.into_array(),
|
||||
col: col.into_array(),
|
||||
bone_idx,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_bone_idx(mut self, bone_idx: u8) -> Self {
|
||||
self.bone_idx = bone_idx;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Locals {
|
||||
pub fn default() -> Self {
|
||||
Self {
|
||||
model_mat: arr_to_mat(Mat4::identity().into_col_array()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BoneData {
|
||||
pub fn new(bone_mat: Mat4<f32>) -> Self {
|
||||
Self {
|
||||
bone_mat: arr_to_mat(bone_mat.into_col_array()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default() -> Self {
|
||||
Self {
|
||||
bone_mat: arr_to_mat(Mat4::identity().into_col_array()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FigurePipeline;
|
||||
|
||||
impl Pipeline for FigurePipeline {
|
||||
type Vertex = Vertex;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
pub mod character;
|
||||
pub mod figure;
|
||||
pub mod skybox;
|
||||
|
||||
// Library
|
||||
|
@ -33,8 +33,10 @@ gfx_defines! {
|
||||
|
||||
pipeline pipe {
|
||||
vbuf: gfx::VertexBuffer<Vertex> = (),
|
||||
|
||||
locals: gfx::ConstantBuffer<Locals> = "u_locals",
|
||||
globals: gfx::ConstantBuffer<Globals> = "u_globals",
|
||||
|
||||
tgt_color: gfx::RenderTarget<TgtColorFmt> = "tgt_color",
|
||||
tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::PASS_TEST,
|
||||
}
|
||||
|
@ -15,13 +15,13 @@ use super::{
|
||||
gfx_backend,
|
||||
pipelines::{
|
||||
Globals,
|
||||
character,
|
||||
figure,
|
||||
skybox,
|
||||
},
|
||||
};
|
||||
|
||||
/// Represents the format of the window's color target.
|
||||
pub type TgtColorFmt = gfx::format::Srgba8;
|
||||
pub type TgtColorFmt = gfx::format::Rgba8;
|
||||
/// Represents the format of the window's depth target.
|
||||
pub type TgtDepthFmt = gfx::format::DepthStencil;
|
||||
|
||||
@ -42,7 +42,7 @@ pub struct Renderer {
|
||||
tgt_depth_view: TgtDepthView,
|
||||
|
||||
skybox_pipeline: GfxPipeline<skybox::pipe::Init<'static>>,
|
||||
character_pipeline: GfxPipeline<character::pipe::Init<'static>>,
|
||||
figure_pipeline: GfxPipeline<figure::pipe::Init<'static>>,
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
@ -62,12 +62,12 @@ impl Renderer {
|
||||
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/skybox.frag")),
|
||||
)?;
|
||||
|
||||
// Construct a pipeline for rendering characters
|
||||
let character_pipeline = create_pipeline(
|
||||
// Construct a pipeline for rendering figures
|
||||
let figure_pipeline = create_pipeline(
|
||||
&mut factory,
|
||||
character::pipe::new(),
|
||||
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/character.vert")),
|
||||
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/character.frag")),
|
||||
figure::pipe::new(),
|
||||
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/figure.vert")),
|
||||
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/figure.frag")),
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
@ -79,7 +79,7 @@ impl Renderer {
|
||||
tgt_depth_view,
|
||||
|
||||
skybox_pipeline,
|
||||
character_pipeline,
|
||||
figure_pipeline,
|
||||
})
|
||||
}
|
||||
|
||||
@ -96,28 +96,23 @@ impl Renderer {
|
||||
self.device.cleanup();
|
||||
}
|
||||
|
||||
/// Create a new set of constants.
|
||||
pub fn create_consts<T: Copy + gfx::traits::Pod>(&mut self) -> Result<Consts<T>, RenderError> {
|
||||
Ok(Consts::new(&mut self.factory))
|
||||
}
|
||||
|
||||
/// Create a new set of constants with a value.
|
||||
pub fn create_consts_with<T: Copy + gfx::traits::Pod>(
|
||||
/// Create a new set of constants with the provided values.
|
||||
pub fn create_consts<T: Copy + gfx::traits::Pod>(
|
||||
&mut self,
|
||||
val: T
|
||||
vals: &[T],
|
||||
) -> Result<Consts<T>, RenderError> {
|
||||
let mut consts = self.create_consts()?;
|
||||
consts.update(&mut self.encoder, val)?;
|
||||
let mut consts = Consts::new(&mut self.factory, vals.len());
|
||||
consts.update(&mut self.encoder, vals)?;
|
||||
Ok(consts)
|
||||
}
|
||||
|
||||
/// Update a set of constants with a new value.
|
||||
/// Update a set of constants with the provided values.
|
||||
pub fn update_consts<T: Copy + gfx::traits::Pod>(
|
||||
&mut self,
|
||||
consts: &mut Consts<T>,
|
||||
val: T
|
||||
vals: &[T]
|
||||
) -> Result<(), RenderError> {
|
||||
consts.update(&mut self.encoder, val)
|
||||
consts.update(&mut self.encoder, vals)
|
||||
}
|
||||
|
||||
/// Create a new model from the provided mesh.
|
||||
@ -132,8 +127,8 @@ impl Renderer {
|
||||
pub fn render_skybox(
|
||||
&mut self,
|
||||
model: &Model<skybox::SkyboxPipeline>,
|
||||
locals: &Consts<skybox::Locals>,
|
||||
globals: &Consts<Globals>,
|
||||
locals: &Consts<skybox::Locals>,
|
||||
) {
|
||||
self.encoder.draw(
|
||||
&model.slice,
|
||||
@ -147,6 +142,28 @@ impl Renderer {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Queue the rendering of the provided figure model in the upcoming frame.
|
||||
pub fn render_figure(
|
||||
&mut self,
|
||||
model: &Model<figure::FigurePipeline>,
|
||||
globals: &Consts<Globals>,
|
||||
locals: &Consts<figure::Locals>,
|
||||
bones: &Consts<figure::BoneData>,
|
||||
) {
|
||||
self.encoder.draw(
|
||||
&model.slice,
|
||||
&self.figure_pipeline.pso,
|
||||
&figure::pipe::Data {
|
||||
vbuf: model.vbuf.clone(),
|
||||
locals: locals.buf.clone(),
|
||||
globals: globals.buf.clone(),
|
||||
bones: bones.buf.clone(),
|
||||
tgt_color: self.tgt_color_view.clone(),
|
||||
tgt_depth: self.tgt_depth_view.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
struct GfxPipeline<P: gfx::pso::PipelineInit> {
|
||||
|
@ -19,9 +19,9 @@ impl Camera {
|
||||
/// Create a new `Camera` with default parameters.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
focus: Vec3::zero(),
|
||||
focus: Vec3::unit_z() * 10.0,
|
||||
ori: Vec3::zero(),
|
||||
dist: 5.0,
|
||||
dist: 40.0,
|
||||
fov: 1.3,
|
||||
aspect: 1.618,
|
||||
}
|
||||
|
79
voxygen/src/scene/figure.rs
Normal file
79
voxygen/src/scene/figure.rs
Normal file
@ -0,0 +1,79 @@
|
||||
// Crate
|
||||
use crate::{
|
||||
Error,
|
||||
render::{
|
||||
Consts,
|
||||
Globals,
|
||||
Mesh,
|
||||
Model,
|
||||
Renderer,
|
||||
FigurePipeline,
|
||||
FigureBoneData,
|
||||
FigureLocals,
|
||||
},
|
||||
anim::Skeleton,
|
||||
};
|
||||
|
||||
pub struct Figure {
|
||||
// GPU data
|
||||
model: Model<FigurePipeline>,
|
||||
bone_consts: Consts<FigureBoneData>,
|
||||
locals: Consts<FigureLocals>,
|
||||
|
||||
// CPU data
|
||||
bone_meshes: [Option<Mesh<FigurePipeline>>; 16],
|
||||
pub skeleton: Skeleton,
|
||||
}
|
||||
|
||||
impl Figure {
|
||||
pub fn new(
|
||||
renderer: &mut Renderer,
|
||||
bone_meshes: [Option<Mesh<FigurePipeline>>; 16]
|
||||
) -> Result<Self, Error> {
|
||||
let skeleton = Skeleton::default();
|
||||
let mut this = Self {
|
||||
model: renderer.create_model(&Mesh::new())?,
|
||||
bone_consts: renderer.create_consts(&skeleton.compute_matrices())?,
|
||||
locals: renderer.create_consts(&[FigureLocals::default()])?,
|
||||
|
||||
bone_meshes,
|
||||
skeleton,
|
||||
};
|
||||
this.update_model(renderer)?;
|
||||
Ok(this)
|
||||
}
|
||||
|
||||
pub fn update_model(&mut self, renderer: &mut Renderer) -> Result<(), Error> {
|
||||
let mut mesh = Mesh::new();
|
||||
|
||||
self.bone_meshes
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm)))
|
||||
.for_each(|(i, bone_mesh)| {
|
||||
mesh.push_mesh_map(bone_mesh, |vert| vert.with_bone_idx(i as u8))
|
||||
});
|
||||
|
||||
self.model = renderer.create_model(&mesh)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_skeleton(&mut self, renderer: &mut Renderer) -> Result<(), Error> {
|
||||
renderer.update_consts(&mut self.bone_consts, &self.skeleton.compute_matrices())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_locals(&mut self, renderer: &mut Renderer, locals: FigureLocals) -> Result<(), Error> {
|
||||
renderer.update_consts(&mut self.locals, &[locals])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn render(&self, renderer: &mut Renderer, globals: &Consts<Globals>) {
|
||||
renderer.render_figure(
|
||||
&self.model,
|
||||
globals,
|
||||
&self.locals,
|
||||
&self.bone_consts,
|
||||
);
|
||||
}
|
||||
}
|
@ -1,16 +1,19 @@
|
||||
pub mod camera;
|
||||
pub mod figure;
|
||||
|
||||
// Standard
|
||||
use std::time::Duration;
|
||||
|
||||
// Library
|
||||
use vek::*;
|
||||
use dot_vox;
|
||||
|
||||
// Project
|
||||
use client::{
|
||||
self,
|
||||
Client,
|
||||
};
|
||||
use common::figure::Segment;
|
||||
|
||||
// Crate
|
||||
use crate::{
|
||||
@ -22,47 +25,82 @@ use crate::{
|
||||
Renderer,
|
||||
SkyboxPipeline,
|
||||
SkyboxLocals,
|
||||
FigureLocals,
|
||||
create_skybox_mesh,
|
||||
},
|
||||
window::Event,
|
||||
mesh::Meshable,
|
||||
};
|
||||
|
||||
// Local
|
||||
use self::camera::Camera;
|
||||
use self::{
|
||||
camera::Camera,
|
||||
figure::Figure,
|
||||
};
|
||||
|
||||
// TODO: Don't hard-code this
|
||||
const CURSOR_PAN_SCALE: f32 = 0.005;
|
||||
|
||||
struct Skybox {
|
||||
model: Model<SkyboxPipeline>,
|
||||
locals: Consts<SkyboxLocals>,
|
||||
}
|
||||
|
||||
// TODO: Don't hard-code this
|
||||
const CURSOR_PAN_SCALE: f32 = 0.005;
|
||||
|
||||
pub struct Scene {
|
||||
camera: Camera,
|
||||
globals: Consts<Globals>,
|
||||
skybox: Skybox,
|
||||
|
||||
test_figure: Figure,
|
||||
|
||||
client: Client,
|
||||
}
|
||||
|
||||
// TODO: Make a proper asset loading system
|
||||
fn load_segment(filename: &'static str) -> Segment {
|
||||
Segment::from(dot_vox::load(&(concat!(env!("CARGO_MANIFEST_DIR"), "/test_assets/").to_string() + filename)).unwrap())
|
||||
}
|
||||
|
||||
impl Scene {
|
||||
/// Create a new `Scene` with default parameters.
|
||||
pub fn new(renderer: &mut Renderer) -> Self {
|
||||
Self {
|
||||
camera: Camera::new(),
|
||||
globals: renderer
|
||||
.create_consts_with(Globals::default())
|
||||
.create_consts(&[Globals::default()])
|
||||
.unwrap(),
|
||||
skybox: Skybox {
|
||||
model: renderer
|
||||
.create_model(&create_skybox_mesh())
|
||||
.unwrap(),
|
||||
locals: renderer
|
||||
.create_consts_with(SkyboxLocals::default())
|
||||
.create_consts(&[SkyboxLocals::default()])
|
||||
.unwrap(),
|
||||
},
|
||||
|
||||
test_figure: Figure::new(
|
||||
renderer,
|
||||
[
|
||||
Some(load_segment("head.vox").generate_mesh_with_offset(Vec3::new(-7.0, -5.5, -1.0))),
|
||||
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("sword.vox").generate_mesh_with_offset(Vec3::new(-6.5, -1.0, 0.0))),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
],
|
||||
)
|
||||
.unwrap(),
|
||||
|
||||
client: Client::new(),
|
||||
}
|
||||
}
|
||||
@ -92,7 +130,7 @@ impl Scene {
|
||||
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents();
|
||||
|
||||
// Update global constants
|
||||
renderer.update_consts(&mut self.globals, Globals::new(
|
||||
renderer.update_consts(&mut self.globals, &[Globals::new(
|
||||
view_mat,
|
||||
proj_mat,
|
||||
cam_pos,
|
||||
@ -100,8 +138,32 @@ impl Scene {
|
||||
10.0,
|
||||
self.client.state().get_time_of_day(),
|
||||
0.0,
|
||||
))
|
||||
)])
|
||||
.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);
|
||||
|
||||
self.test_figure.update_locals(renderer, FigureLocals::default());
|
||||
self.test_figure.update_skeleton(renderer);
|
||||
}
|
||||
|
||||
/// Render the scene using the provided `Renderer`
|
||||
@ -109,8 +171,11 @@ impl Scene {
|
||||
// Render the skybox first (it appears over everything else so must be rendered first)
|
||||
renderer.render_skybox(
|
||||
&self.skybox.model,
|
||||
&self.skybox.locals,
|
||||
&self.globals,
|
||||
&self.skybox.locals,
|
||||
);
|
||||
|
||||
// Render the test figure
|
||||
self.test_figure.render(renderer, &self.globals);
|
||||
}
|
||||
}
|
||||
|
BIN
voxygen/test_assets/belt.vox
Normal file
BIN
voxygen/test_assets/belt.vox
Normal file
Binary file not shown.
BIN
voxygen/test_assets/chest.vox
Normal file
BIN
voxygen/test_assets/chest.vox
Normal file
Binary file not shown.
BIN
voxygen/test_assets/foot.vox
Normal file
BIN
voxygen/test_assets/foot.vox
Normal file
Binary file not shown.
BIN
voxygen/test_assets/hand.vox
Normal file
BIN
voxygen/test_assets/hand.vox
Normal file
Binary file not shown.
BIN
voxygen/test_assets/head.vox
Normal file
BIN
voxygen/test_assets/head.vox
Normal file
Binary file not shown.
BIN
voxygen/test_assets/knight.vox
Normal file
BIN
voxygen/test_assets/knight.vox
Normal file
Binary file not shown.
BIN
voxygen/test_assets/pants.vox
Normal file
BIN
voxygen/test_assets/pants.vox
Normal file
Binary file not shown.
BIN
voxygen/test_assets/sword.vox
Normal file
BIN
voxygen/test_assets/sword.vox
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user