Merge branch 'glowy-shiny-pretty' into 'master'

Glowy shiny pretty

See merge request veloren/veloren!1874
This commit is contained in:
Joshua Barretto 2021-03-11 17:37:33 +00:00
commit f479231b15
11 changed files with 165 additions and 28 deletions

View File

@ -70,7 +70,7 @@ uniform u_bones {
BoneData bones[16];
};
#include <sky.glsl>
#include <cloud.glsl>
#include <light.glsl>
#include <lod.glsl>
@ -87,7 +87,9 @@ void main() {
// float f_ao = f_col_light.a;
float f_ao, f_glow;
vec3 f_col = greedy_extract_col_light_glow(t_col_light, f_uv_pos, f_ao, f_glow);
uint material = 0xFFu;
vec3 f_col = greedy_extract_col_light_attr(t_col_light, f_uv_pos, f_ao, f_glow, material);
// float /*f_light*/f_ao = textureProj(t_col_light, vec3(f_uv_pos, texSize)).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
// vec3 my_chunk_pos = (vec3((uvec3(f_pos_norm) >> uvec3(0, 9, 18)) & uvec3(0x1FFu)) - 256.0) / 2.0;
@ -161,6 +163,14 @@ void main() {
vec3 k_d = vec3(1.0);
vec3 k_s = vec3(R_s);
// This is a silly hack. It's not true reflectance (see below for that), but gives the desired
// effect without breaking the entire lighting model until we come up with a better way of doing
// reflectivity that accounts for physical surroundings like the ground
if ((material & (1u << 1u)) > 0u) {
vec3 reflect_ray_dir = reflect(cam_to_frag, f_norm);
surf_color *= dot(vec3(1.0) - abs(fract(reflect_ray_dir * 3.5) * 2.0 - 1.0) * 0.85, vec3(1));
}
vec3 emitted_light, reflected_light;
// Make voxel shadows block the sun and moon
@ -184,10 +194,17 @@ void main() {
float ao = f_ao * sqrt(f_ao);//0.25 + f_ao * 0.75; ///*pow(f_ao, 0.5)*/f_ao * 0.85 + 0.15;
// For now, just make glowing material light be the same colour as the surface
// TODO: Add a way to control this better outside the shaders
if ((material & (1u << 0u)) > 0u) {
emitted_light += 1000 * surf_color;
}
float glow_mag = length(model_glow.xyz);
vec3 glow = pow(model_glow.w, 2) * 4
* glow_light(f_pos)
* (max(dot(f_norm, model_glow.xyz / glow_mag) * 0.5 + 0.5, 0.0) + max(1.0 - glow_mag, 0.0));
emitted_light += glow;
reflected_light *= ao;
@ -206,7 +223,20 @@ void main() {
// diffuse_light += point_light;
// reflected_light += point_light;
// vec3 surf_color = illuminate(srgb_to_linear(highlight_col.rgb * f_col), light, diffuse_light, ambient_light);
surf_color = illuminate(max_light, view_dir, surf_color * emitted_light, surf_color * reflected_light) * highlight_col.rgb;
float reflectance = 0.0;
// TODO: Do reflectance properly like this later
vec3 reflect_color = vec3(0);
/*
if ((material & (1u << 1u)) > 0u && false) {
vec3 reflect_ray_dir = reflect(cam_to_frag, f_norm);
reflect_color = get_sky_color(reflect_ray_dir, time_of_day.x, f_pos, vec3(-100000), 0.125, true);
reflect_color = get_cloud_color(reflect_color, reflect_ray_dir, cam_pos.xyz, time_of_day.x, 100000.0, 0.25);
reflectance = 1.0;
}
*/
surf_color = illuminate(max_light, view_dir, mix(surf_color * emitted_light, reflect_color, reflectance), mix(surf_color * reflected_light, reflect_color, reflectance)) * highlight_col.rgb;
// if ((flags & 1) == 1 && int(cam_mode) == 1) {
// float distance = distance(vec3(cam_pos), focus_pos.xyz) - 2;

View File

@ -618,7 +618,7 @@ vec3 compute_attenuation_point(vec3 wpos, vec3 ray_dir, vec3 mu, float surface_a
//}
//#endif
vec3 greedy_extract_col_light_glow(sampler2D t_col_light, vec2 f_uv_pos, out float f_light, out float f_glow) {
vec3 greedy_extract_col_light_attr(sampler2D t_col_light, vec2 f_uv_pos, out float f_light, out float f_glow, out uint f_attr) {
uvec4 f_col_light = uvec4(texelFetch(t_col_light, ivec2(f_uv_pos), 0) * 255);
vec3 f_col = vec3(
float(((f_col_light.r & 0x7u) << 1u) | (f_col_light.b & 0xF0u)),
@ -640,5 +640,11 @@ vec3 greedy_extract_col_light_glow(sampler2D t_col_light, vec2 f_uv_pos, out flo
f_light = light.x / 31.0;
f_glow = light.y / 31.0;
f_attr = f_col_light.g >> 3u;
return srgb_to_linear(f_col);
}
vec3 greedy_extract_col_light_glow(sampler2D t_col_light, vec2 f_uv_pos, out float f_light, out float f_glow) {
uint f_attr;
return greedy_extract_col_light_attr(t_col_light, f_uv_pos, f_light, f_glow, f_attr);
}

Binary file not shown.

View File

@ -1,22 +1,60 @@
use crate::vol::Vox;
use vek::*;
pub(super) const GLOWY: u8 = 1 << 0;
pub(super) const SHINY: u8 = 1 << 1;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(packed)]
pub struct CellData {
pub col: Rgb<u8>,
pub attr: u8, // 0 = glowy, 1 = shiny
}
impl Default for CellData {
fn default() -> Self {
Self {
col: Rgb::broadcast(255),
attr: 0,
}
}
}
/// A type representing a single voxel in a figure.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Cell {
Filled([u8; 3]),
Filled(CellData),
Empty,
}
impl Cell {
pub fn new(rgb: Rgb<u8>) -> Self { Cell::Filled(rgb.into_array()) }
pub fn new(col: Rgb<u8>, glowy: bool, shiny: bool) -> Self {
Cell::Filled(CellData {
col,
attr: glowy as u8 * GLOWY + shiny as u8 * SHINY,
})
}
pub fn get_color(&self) -> Option<Rgb<u8>> {
match self {
Cell::Filled(col) => Some(Rgb::from(*col)),
Cell::Filled(data) => Some(data.col),
Cell::Empty => None,
}
}
pub fn is_glowy(&self) -> bool {
match self {
Cell::Filled(data) => data.attr & GLOWY != 0,
Cell::Empty => false,
}
}
pub fn is_shiny(&self) -> bool {
match self {
Cell::Filled(data) => data.attr & SHINY != 0,
Cell::Empty => false,
}
}
}
impl Vox for Cell {

View File

@ -1,5 +1,5 @@
use super::cell::CellData;
use crate::vol::Vox;
use vek::*;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Material {
@ -19,7 +19,7 @@ pub enum Material {
pub enum MatCell {
None,
Mat(Material),
Normal(Rgb<u8>),
Normal(CellData),
}
impl Vox for MatCell {

View File

@ -3,8 +3,12 @@ pub mod mat_cell;
pub use mat_cell::Material;
// Reexport
pub use self::{cell::Cell, mat_cell::MatCell};
pub use self::{
cell::{Cell, CellData},
mat_cell::MatCell,
};
use self::cell::{GLOWY, SHINY};
use crate::{
vol::{IntoFullPosIterator, IntoFullVolIterator, ReadVol, SizedVol, Vox, WriteVol},
volumes::dyna::Dyna,
@ -60,7 +64,11 @@ impl Segment {
voxel.z,
)
.map(i32::from),
Cell::new(color),
Cell::new(
color,
(13..16).contains(&voxel.i), // Glowy
(8..13).contains(&voxel.i), // Shiny
),
)
.unwrap();
};
@ -85,7 +93,10 @@ impl Segment {
/// Transform cell colors
pub fn map_rgb(self, transform: impl Fn(Rgb<u8>) -> Rgb<u8>) -> Self {
self.map(|cell| cell.get_color().map(|rgb| Cell::new(transform(rgb))))
self.map(|cell| {
cell.get_color()
.map(|rgb| Cell::new(transform(rgb), cell.is_glowy(), cell.is_shiny()))
})
}
}
@ -146,12 +157,15 @@ impl MatSegment {
pub fn to_segment(&self, map: impl Fn(Material) -> Rgb<u8>) -> Segment {
let mut vol = Dyna::filled(self.size(), Cell::empty(), ());
for (pos, vox) in self.full_vol_iter() {
let rgb = match vox {
let data = match vox {
MatCell::None => continue,
MatCell::Mat(mat) => map(*mat),
MatCell::Normal(rgb) => *rgb,
MatCell::Mat(mat) => CellData {
col: map(*mat),
attr: 0,
},
MatCell::Normal(data) => *data,
};
vol.set(pos, Cell::new(rgb)).unwrap();
vol.set(pos, Cell::Filled(data)).unwrap();
}
vol
}
@ -170,11 +184,15 @@ impl MatSegment {
/// Transform cell colors
pub fn map_rgb(self, transform: impl Fn(Rgb<u8>) -> Rgb<u8>) -> Self {
self.map(|cell| match cell {
MatCell::Normal(rgb) => Some(MatCell::Normal(transform(rgb))),
MatCell::Normal(data) => Some(MatCell::Normal(CellData {
col: transform(data.col),
..data
})),
_ => None,
})
}
#[allow(clippy::identity_op)]
pub fn from_vox(dot_vox_data: &DotVoxData, flipped: bool) -> Self {
if let Some(model) = dot_vox_data.models.get(0) {
let palette = dot_vox_data
@ -204,7 +222,12 @@ impl MatSegment {
.get(index as usize)
.copied()
.unwrap_or_else(|| Rgb::broadcast(0));
MatCell::Normal(color)
MatCell::Normal(CellData {
col: color,
attr: 0
| ((13..16).contains(&index) as u8 * GLOWY)
| ((8..13).contains(&index) as u8 * SHINY),
})
},
};

View File

@ -214,6 +214,6 @@ fn graceful_load_segment_no_skin(specifier: &str) -> Arc<Segment> {
MatCell::Mat(_) => Some(MatCell::None),
MatCell::Normal(_) => None,
})
.to_segment(|_| Rgb::broadcast(255));
.to_segment(|_| Default::default());
Arc::new(seg)
}

View File

@ -11,7 +11,7 @@ type TodoRect = (
Vec3<i32>,
);
pub struct GreedyConfig<D, FL, FG, FC, FO, FS, FP> {
pub struct GreedyConfig<D, FL, FG, FC, FO, FS, FP, FT> {
pub data: D,
/// The minimum position to mesh, in the coordinate system used
/// for queries against the volume.
@ -63,6 +63,9 @@ pub struct GreedyConfig<D, FL, FG, FC, FO, FS, FP> {
/// world space, the normal facing out frmo the rectangle in world
/// space, and meta information common to every voxel in this rectangle.
pub push_quad: FP,
/// Create a texel (in the texture atlas) that corresponds to a face with
/// the given properties.
pub make_face_texel: FT,
}
/// A suspended greedy mesh, with enough information to recover color data.
@ -143,9 +146,9 @@ impl<'a> GreedyMesh<'a> {
/// Returns an estimate of the bounds of the current meshed model.
///
/// For more information on the config parameter, see [GreedyConfig].
pub fn push<M: PartialEq, D: 'a, FL, FG, FC, FO, FS, FP>(
pub fn push<M: PartialEq, D: 'a, FL, FG, FC, FO, FS, FP, FT>(
&mut self,
config: GreedyConfig<D, FL, FG, FC, FO, FS, FP>,
config: GreedyConfig<D, FL, FG, FC, FO, FS, FP, FT>,
) where
FL: for<'r> FnMut(&'r mut D, Vec3<i32>) -> f32 + 'a,
FG: for<'r> FnMut(&'r mut D, Vec3<i32>) -> f32 + 'a,
@ -153,6 +156,7 @@ impl<'a> GreedyMesh<'a> {
FO: for<'r> FnMut(&'r mut D, Vec3<i32>) -> bool + 'a,
FS: for<'r> FnMut(&'r mut D, Vec3<i32>, Vec3<i32>, Vec2<Vec3<i32>>) -> Option<(bool, M)>,
FP: FnMut(Vec2<u16>, Vec2<Vec2<u16>>, Vec3<f32>, Vec2<Vec3<f32>>, Vec3<f32>, &M),
FT: for<'r> FnMut(&'r mut D, Vec3<i32>, u8, u8, Rgb<u8>) -> <<ColLightFmt as gfx::format::Formatted>::Surface as gfx::format::SurfaceTyped>::DataType + 'a,
{
span!(_guard, "push", "GreedyMesh::push");
let cont = greedy_mesh(
@ -190,7 +194,7 @@ impl<'a> GreedyMesh<'a> {
pub fn max_size(&self) -> guillotiere::Size { self.max_size }
}
fn greedy_mesh<'a, M: PartialEq, D: 'a, FL, FG, FC, FO, FS, FP>(
fn greedy_mesh<'a, M: PartialEq, D: 'a, FL, FG, FC, FO, FS, FP, FT>(
atlas: &mut guillotiere::SimpleAtlasAllocator,
col_lights_size: &mut Vec2<u16>,
max_size: guillotiere::Size,
@ -205,7 +209,8 @@ fn greedy_mesh<'a, M: PartialEq, D: 'a, FL, FG, FC, FO, FS, FP>(
get_opacity,
mut should_draw,
mut push_quad,
}: GreedyConfig<D, FL, FG, FC, FO, FS, FP>,
make_face_texel,
}: GreedyConfig<D, FL, FG, FC, FO, FS, FP, FT>,
) -> Box<SuspendedMesh<'a>>
where
FL: for<'r> FnMut(&'r mut D, Vec3<i32>) -> f32 + 'a,
@ -214,6 +219,7 @@ where
FO: for<'r> FnMut(&'r mut D, Vec3<i32>) -> bool + 'a,
FS: for<'r> FnMut(&'r mut D, Vec3<i32>, Vec3<i32>, Vec2<Vec3<i32>>) -> Option<(bool, M)>,
FP: FnMut(Vec2<u16>, Vec2<Vec2<u16>>, Vec3<f32>, Vec2<Vec3<f32>>, Vec3<f32>, &M),
FT: for<'r> FnMut(&'r mut D, Vec3<i32>, u8, u8, Rgb<u8>) -> <<ColLightFmt as gfx::format::Formatted>::Surface as gfx::format::SurfaceTyped>::DataType + 'a,
{
span!(_guard, "greedy_mesh");
// TODO: Collect information to see if we can choose a good value here.
@ -353,7 +359,7 @@ where
get_glow,
get_color,
get_opacity,
TerrainVertex::make_col_light,
make_face_texel,
);
})
}
@ -509,7 +515,7 @@ fn draw_col_lights<D>(
mut get_glow: impl FnMut(&mut D, Vec3<i32>) -> f32,
mut get_color: impl FnMut(&mut D, Vec3<i32>) -> Rgb<u8>,
mut get_opacity: impl FnMut(&mut D, Vec3<i32>) -> bool,
mut make_col_light: impl FnMut(u8, u8, Rgb<u8>) -> <<ColLightFmt as gfx::format::Formatted>::Surface as gfx::format::SurfaceTyped>::DataType,
mut make_face_texel: impl FnMut(&mut D, Vec3<i32>, u8, u8, Rgb<u8>) -> <<ColLightFmt as gfx::format::Formatted>::Surface as gfx::format::SurfaceTyped>::DataType,
) {
todo_rects.into_iter().for_each(|(pos, uv, rect, delta)| {
// NOTE: Conversions are safe because width, height, and offset must be
@ -586,7 +592,7 @@ fn draw_col_lights<D>(
let col = get_color(data, pos);
let light = (darkness * 31.5) as u8;
let glow = (glowiness * 31.5) as u8;
*col_light = make_col_light(light, glow, col);
*col_light = make_face_texel(data, pos, light, glow, col);
});
});
});

View File

@ -116,6 +116,13 @@ where
|atlas_pos, pos, norm, &_meta| create_opaque(atlas_pos, pos, norm),
));
},
make_face_texel: |vol: &mut V, pos, light, _, col| {
let (glowy, shiny) = vol
.get(pos)
.map(|c| (c.is_glowy(), c.is_shiny()))
.unwrap_or_default();
TerrainVertex::make_col_light_figure(light, glowy, shiny, col)
},
});
let bounds = math::Aabb {
// NOTE: Casts are safe since lower_bound and upper_bound both fit in a i16.
@ -219,6 +226,9 @@ where
|atlas_pos, pos, norm, &meta| create_opaque(atlas_pos, pos, norm, meta),
));
},
make_face_texel: |_: &mut V, _, light, glow, col| {
TerrainVertex::make_col_light(light, glow, col)
},
});
(Mesh::new(), Mesh::new(), Mesh::new(), ())
@ -315,6 +325,9 @@ where
|atlas_pos, pos, norm, &_meta| create_opaque(atlas_pos, pos, norm),
));
},
make_face_texel: |_: &mut V, _, light, glow, col| {
TerrainVertex::make_col_light(light, glow, col)
},
});
(opaque_mesh, Mesh::new(), Mesh::new(), ())

View File

@ -439,6 +439,9 @@ impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug + 'static>
));
},
},
make_face_texel: |_: &mut (), _, light, glow, col| {
TerrainVertex::make_col_light(light, glow, col)
},
});
let min_bounds = mesh_delta;

View File

@ -133,6 +133,24 @@ impl Vertex {
col.g, // Green is lucky, it remains unscathed
]
}
#[allow(clippy::identity_op)]
pub fn make_col_light_figure(
// 0 to 31
light: u8,
glowy: bool,
shiny: bool,
col: Rgb<u8>,
) -> <<ColLightFmt as gfx::format::Formatted>::Surface as gfx::format::SurfaceTyped>::DataType
{
let attr = 0 | ((glowy as u8) << 0) | ((shiny as u8) << 1);
[
(light.min(31) << 3) | ((col.r >> 1) & 0b111),
(attr.min(31) << 3) | ((col.b >> 1) & 0b111),
(col.r & 0b11110000) | (col.b >> 4),
col.g, // Green is lucky, it remains unscathed
]
}
}
impl Locals {