Added wheat and sprite rendering

This commit is contained in:
Joshua Barretto 2019-08-19 21:09:35 +01:00
parent 6f35786b84
commit b31cca4bb3
15 changed files with 192 additions and 18 deletions

View File

@ -0,0 +1,24 @@
#version 330 core
#include <globals.glsl>
in vec3 f_pos;
flat in vec3 f_norm;
in vec3 f_col;
in float f_light;
out vec4 tgt_color;
#include <sky.glsl>
#include <light.glsl>
void main() {
vec3 light = get_sun_diffuse(f_norm, time_of_day.x) * f_light + light_at(f_pos, f_norm);
vec3 surf_color = f_col * light;
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x);
vec3 color = mix(surf_color, fog_color, fog_level);
tgt_color = vec4(color, 1.0);
}

View File

@ -0,0 +1,32 @@
#version 330 core
#include <globals.glsl>
#include <srgb.glsl>
in vec3 v_pos;
in vec3 v_norm;
in vec3 v_col;
in vec3 inst_pos;
in vec3 inst_col;
out vec3 f_pos;
flat out vec3 f_norm;
out vec3 f_col;
out float f_light;
const float SCALE = 1.0 / 11.0;
void main() {
f_pos = inst_pos + v_pos * SCALE;
f_norm = v_norm;
f_col = v_col * inst_col;
f_light = 1.0;
gl_Position =
proj_mat *
view_mat *
vec4(f_pos, 1);
}

BIN
assets/voxygen/voxel/sprite/wheat.vox (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -10,12 +10,14 @@ pub enum BlockKind {
Normal,
Dense,
Water,
Wheat,
}
impl BlockKind {
pub fn is_air(&self) -> bool {
match self {
BlockKind::Air => true,
BlockKind::Wheat => true,
_ => false,
}
}
@ -31,6 +33,7 @@ impl BlockKind {
match self {
BlockKind::Air => false,
BlockKind::Water => false,
BlockKind::Wheat => false,
_ => true,
}
}
@ -39,6 +42,7 @@ impl BlockKind {
match self {
BlockKind::Air => false,
BlockKind::Water => false,
BlockKind::Wheat => false,
_ => true,
}
}

View File

@ -4,7 +4,7 @@ mod vol;
use crate::render::{self, Mesh};
pub trait Meshable {
pub trait Meshable<P: render::Pipeline, T: render::Pipeline> {
type Pipeline: render::Pipeline;
type TranslucentPipeline: render::Pipeline;
type Supplement;

View File

@ -1,6 +1,6 @@
use crate::{
mesh::{vol, Meshable},
render::{self, FigurePipeline, Mesh},
render::{self, FigurePipeline, Mesh, SpritePipeline},
};
use common::{
figure::Segment,
@ -10,8 +10,9 @@ use common::{
use vek::*;
type FigureVertex = <FigurePipeline as render::Pipeline>::Vertex;
type SpriteVertex = <SpritePipeline as render::Pipeline>::Vertex;
impl Meshable for Segment {
impl Meshable<FigurePipeline, FigurePipeline> for Segment {
type Pipeline = FigurePipeline;
type TranslucentPipeline = FigurePipeline;
type Supplement = Vec3<f32>;
@ -51,3 +52,43 @@ impl Meshable for Segment {
(mesh, Mesh::new())
}
}
impl Meshable<SpritePipeline, SpritePipeline> for Segment {
type Pipeline = SpritePipeline;
type TranslucentPipeline = SpritePipeline;
type Supplement = Vec3<f32>;
fn generate_mesh(
&self,
offs: Self::Supplement,
) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>) {
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);
vol::push_vox_verts(
&mut mesh,
self,
pos,
offs + pos.map(|e| e as f32),
col,
|origin, norm, col, ao, light| {
SpriteVertex::new(
origin,
norm,
linear_to_srgb(srgb_to_linear(col) * ao * light),
)
},
true,
&[[[1.0; 3]; 3]; 3],
|vox| vox.is_empty(),
|vox| !vox.is_empty(),
);
}
}
(mesh, Mesh::new())
}
}

View File

@ -14,15 +14,19 @@ type TerrainVertex = <TerrainPipeline as render::Pipeline>::Vertex;
type FluidVertex = <FluidPipeline as render::Pipeline>::Vertex;
fn block_shadow_density(kind: BlockKind) -> (f32, f32) {
// (density, cap)
match kind {
BlockKind::Air => (0.0, 0.0),
BlockKind::Normal => (0.085, 0.3),
BlockKind::Dense => (0.3, 0.0),
BlockKind::Water => (0.15, 0.0),
kind if kind.is_air() => (0.0, 0.0),
_ => (1.0, 0.0),
}
}
impl<V: BaseVol<Vox = Block> + ReadVol + Debug, S: VolSize + Clone> Meshable for VolMap2d<V, S> {
impl<V: BaseVol<Vox = Block> + ReadVol + Debug, S: VolSize + Clone>
Meshable<TerrainPipeline, FluidPipeline> for VolMap2d<V, S>
{
type Pipeline = TerrainPipeline;
type TranslucentPipeline = FluidPipeline;
type Supplement = Aabb<i32>;

View File

@ -15,7 +15,7 @@ impl<T: Copy + gfx::traits::Pod> Instances<T> {
pub fn new(factory: &mut gfx_backend::Factory, len: usize) -> Result<Self, RenderError> {
Ok(Self {
ibuf: factory
.create_buffer(len, Role::Vertex, Usage::Data, Bind::TRANSFER_DST)
.create_buffer(len, Role::Vertex, Usage::Dynamic, Bind::TRANSFER_DST)
.map_err(|err| RenderError::BufferCreationError(err))?,
})
}

View File

@ -10,6 +10,7 @@ mod util;
// Reexports
pub use self::{
consts::Consts,
instances::Instances,
mesh::{Mesh, Quad, Tri},
model::{DynamicModel, Model},
pipelines::{

View File

@ -22,7 +22,7 @@ gfx_defines! {
vertex Instance {
inst_pos: [f32; 3] = "inst_pos",
inst_col: [f32; 4] = "inst_col",
inst_col: [f32; 3] = "inst_col",
}
pipeline pipe {
@ -48,7 +48,7 @@ impl Vertex {
}
impl Instance {
pub fn new(inst_pos: Vec3<f32>, col: Rgba<f32>) -> Self {
pub fn new(inst_pos: Vec3<f32>, col: Rgb<f32>) -> Self {
Self {
inst_pos: inst_pos.into_array(),
inst_col: col.into_array(),
@ -58,7 +58,7 @@ impl Instance {
impl Default for Instance {
fn default() -> Self {
Self::new(Vec3::zero(), Rgba::broadcast(1.0))
Self::new(Vec3::zero(), Rgb::broadcast(1.0))
}
}

View File

@ -244,6 +244,16 @@ impl Renderer {
consts.update(&mut self.encoder, vals)
}
/// Create a new set of instances with the provided values.
pub fn create_instances<T: Copy + gfx::traits::Pod>(
&mut self,
vals: &[T],
) -> Result<Instances<T>, RenderError> {
let mut instances = Instances::new(&mut self.factory, vals.len())?;
instances.update(&mut self.encoder, vals)?;
Ok(instances)
}
/// Create a new model from the provided mesh.
pub fn create_model<P: Pipeline>(&mut self, mesh: &Mesh<P>) -> Result<Model<P>, RenderError> {
Ok(Model::new(&mut self.factory, mesh))

View File

@ -163,9 +163,11 @@ impl FigureModelCache {
// TODO: Don't make this public.
pub fn load_mesh(mesh_name: &str, position: Vec3<f32>) -> Mesh<FigurePipeline> {
let full_specifier: String = ["voxygen.voxel.", mesh_name].concat();
Segment::from(assets::load_expect::<DotVoxData>(full_specifier.as_str()).as_ref())
.generate_mesh(position)
.0
Meshable::<FigurePipeline, FigurePipeline>::generate_mesh(
&Segment::from(assets::load_expect::<DotVoxData>(full_specifier.as_str()).as_ref()),
position,
)
.0
}
fn load_head(race: humanoid::Race, body_type: humanoid::BodyType) -> Mesh<FigurePipeline> {

View File

@ -68,7 +68,7 @@ impl Scene {
.create_consts(&[PostProcessLocals::default()])
.unwrap(),
},
terrain: Terrain::new(),
terrain: Terrain::new(renderer),
loaded_distance: 0.0,
figure_mgr: FigureMgr::new(),
}

View File

@ -1,17 +1,20 @@
use crate::{
mesh::Meshable,
render::{
Consts, FluidPipeline, Globals, Light, Mesh, Model, Renderer, TerrainLocals,
TerrainPipeline,
Consts, FluidPipeline, Globals, Instances, Light, Mesh, Model, Renderer, SpriteInstance,
SpritePipeline, TerrainLocals, TerrainPipeline,
},
};
use client::Client;
use common::{
terrain::{TerrainChunkSize, TerrainMap},
vol::{SampleVol, VolSize},
assets,
figure::Segment,
terrain::{Block, BlockKind, TerrainChunkSize, TerrainMap},
vol::{ReadVol, SampleVol, VolSize, Vox},
volumes::vol_map_2d::VolMap2dErr,
};
use crossbeam::channel;
use dot_vox::DotVoxData;
use frustum_query::frustum::Frustum;
use hashbrown::HashMap;
use std::{i32, ops::Mul, time::Duration};
@ -21,7 +24,9 @@ struct TerrainChunk {
// GPU data
opaque_model: Model<TerrainPipeline>,
fluid_model: Model<FluidPipeline>,
sprite_instances: Instances<SpriteInstance>,
locals: Consts<TerrainLocals>,
visible: bool,
z_bounds: (f32, f32),
}
@ -38,6 +43,7 @@ struct MeshWorkerResponse {
z_bounds: (f32, f32),
opaque_mesh: Mesh<TerrainPipeline>,
fluid_mesh: Mesh<FluidPipeline>,
sprite_instances: Vec<SpriteInstance>,
started_tick: u64,
}
@ -55,6 +61,30 @@ fn mesh_worker(
z_bounds,
opaque_mesh,
fluid_mesh,
// Extract sprite locations from volume
sprite_instances: {
let mut instances = Vec::new();
for x in 0..TerrainChunkSize::SIZE.x as i32 {
for y in 0..TerrainChunkSize::SIZE.y as i32 {
for z in z_bounds.0 as i32..z_bounds.1 as i32 + 1 {
let wpos = Vec3::from(
pos * Vec2::from(TerrainChunkSize::SIZE).map(|e: u32| e as i32),
) + Vec3::new(x, y, z);
match volume.get(wpos).unwrap_or(&Block::empty()).kind() {
BlockKind::Wheat => instances.push(SpriteInstance::new(
wpos.map(|e| e as f32),
Rgb::broadcast(1.0),
)),
_ => {}
}
}
}
}
instances
},
started_tick,
}
}
@ -67,19 +97,31 @@ pub struct Terrain {
mesh_send_tmp: channel::Sender<MeshWorkerResponse>,
mesh_recv: channel::Receiver<MeshWorkerResponse>,
mesh_todo: HashMap<Vec2<i32>, ChunkMeshState>,
// GPU data
wheat_model: Model<SpritePipeline>,
}
impl Terrain {
pub fn new() -> Self {
pub fn new(renderer: &mut Renderer) -> Self {
// Create a new mpsc (Multiple Produced, Single Consumer) pair for communicating with
// worker threads that are meshing chunks.
let (send, recv) = channel::unbounded();
let wheat_mesh = Meshable::<SpritePipeline, SpritePipeline>::generate_mesh(
&Segment::from(
assets::load_expect::<DotVoxData>("voxygen.voxel.sprite.wheat").as_ref(),
),
Vec3::new(6.0, 6.0, 0.0),
)
.0;
Self {
chunks: HashMap::default(),
mesh_send_tmp: send,
mesh_recv: recv,
mesh_todo: HashMap::default(),
wheat_model: renderer.create_model(&wheat_mesh).unwrap(),
}
}
@ -275,6 +317,9 @@ impl Terrain {
fluid_model: renderer
.create_model(&response.fluid_mesh)
.expect("Failed to upload chunk mesh to the GPU!"),
sprite_instances: renderer
.create_instances(&response.sprite_instances)
.expect("Failed to upload chunk sprite instances to the GPU!"),
locals: renderer
.create_consts(&[TerrainLocals {
model_offs: Vec3::from(
@ -348,6 +393,12 @@ impl Terrain {
for (_pos, chunk) in &self.chunks {
if chunk.visible {
renderer.render_terrain_chunk(&chunk.opaque_model, globals, &chunk.locals, lights);
renderer.render_sprites(
&self.wheat_model,
globals,
&chunk.sprite_instances,
lights,
);
}
}

View File

@ -254,6 +254,8 @@ impl<'a> BlockGen<'a> {
BlockKind::Normal,
saturate_srgb(col, 0.45).map(|e| (e * 255.0) as u8),
))
} else if (wposf.z as f32) < height + 0.02 {
Some(Block::new(BlockKind::Wheat, Rgb::broadcast(0)))
} else {
None
};