mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added wheat and sprite rendering
This commit is contained in:
parent
6f35786b84
commit
b31cca4bb3
24
assets/voxygen/shaders/sprite-frag.glsl
Normal file
24
assets/voxygen/shaders/sprite-frag.glsl
Normal 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);
|
||||
}
|
32
assets/voxygen/shaders/sprite-vert.glsl
Normal file
32
assets/voxygen/shaders/sprite-vert.glsl
Normal 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
BIN
assets/voxygen/voxel/sprite/wheat.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
@ -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>;
|
||||
|
@ -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))?,
|
||||
})
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ mod util;
|
||||
// Reexports
|
||||
pub use self::{
|
||||
consts::Consts,
|
||||
instances::Instances,
|
||||
mesh::{Mesh, Quad, Tri},
|
||||
model::{DynamicModel, Model},
|
||||
pipelines::{
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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> {
|
||||
|
@ -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(),
|
||||
}
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user