Added glow

This commit is contained in:
Joshua Barretto 2020-11-21 03:05:09 +00:00
parent 3bcffe1bf7
commit 51d1a2ecff
12 changed files with 157 additions and 77 deletions

View File

@ -82,13 +82,8 @@ void main() {
// vec3 f_col = f_col_light.rgb; // vec3 f_col = f_col_light.rgb;
// float f_ao = f_col_light.a; // float f_ao = f_col_light.a;
// vec2 f_uv_pos = f_uv_pos + atlas_offs.xy; float f_ao, f_glow;
vec4 f_col_light = texelFetch(t_col_light, ivec2(f_uv_pos)/* + uv_delta*//* - f_norm * 0.00001*/, 0); vec3 f_col = greedy_extract_col_light_glow(t_col_light, f_uv_pos, f_ao, f_glow);
// vec4 f_col_light = texelFetch(t_col_light, ivec2(int(f_uv_pos.x), int(f_uv_pos.y)/* + uv_delta*//* - f_norm * 0.00001*/), 0);
vec3 f_col = /*linear_to_srgb*//*srgb_to_linear*/(f_col_light.rgb);
// vec3 f_col = vec3(1.0);
// vec2 texSize = textureSize(t_col_light, 0);
float f_ao = texture(t_col_light, (f_uv_pos + 0.5) / textureSize(t_col_light, 0)).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
// 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; // 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; // vec3 my_chunk_pos = (vec3((uvec3(f_pos_norm) >> uvec3(0, 9, 18)) & uvec3(0x1FFu)) - 256.0) / 2.0;

View File

@ -617,3 +617,22 @@ vec3 compute_attenuation_point(vec3 wpos, vec3 ray_dir, vec3 mu, float surface_a
// return 1.0; // return 1.0;
//} //}
//#endif //#endif
vec3 greedy_extract_col_light_glow(sampler2D t_col_light, vec2 f_uv_pos, out float f_light, out float f_glow) {
uvec4 f_col_light = uvec4(texelFetch(t_col_light, ivec2(f_uv_pos), 0) * 255);
vec3 f_col = vec3(
float(((f_col_light.r >> 4u) & 0xEu) | (((f_col_light.b >> 4u) & 0xFu) << 4u)),
float(f_col_light.a),
float(((f_col_light.g >> 4u) & 0xEu) | (((f_col_light.b >> 0u) & 0xFu) << 4u))
) / 255.0;
vec2 light_00 = vec2(uvec2(f_col_light.rg) & uvec2(0x1Fu));
vec2 light_10 = vec2(uvec2(texelFetch(t_col_light, ivec2(f_uv_pos) + ivec2(1, 0), 0).rg * 255.0) & uvec2(0x1Fu));
vec2 light_01 = vec2(uvec2(texelFetch(t_col_light, ivec2(f_uv_pos) + ivec2(0, 1), 0).rg * 255.0) & uvec2(0x1Fu));
vec2 light_11 = vec2(uvec2(texelFetch(t_col_light, ivec2(f_uv_pos) + ivec2(1, 1), 0).rg * 255.0) & uvec2(0x1Fu));
vec2 light_0 = mix(light_00, light_01, fract(f_uv_pos.y));
vec2 light_1 = mix(light_10, light_11, fract(f_uv_pos.y));
vec2 light = mix(light_0, light_1, fract(f_uv_pos.x));
f_light = light.x / 31.0;
f_glow = light.y / 31.0;
return srgb_to_linear(f_col);
}

View File

@ -61,17 +61,8 @@ void main() {
// vec3 dv = dFdy(f_pos); // vec3 dv = dFdy(f_pos);
// vec3 f_norm = normalize(cross(du, dv)); // vec3 f_norm = normalize(cross(du, dv));
// vec4 f_col_light = texture(t_col_light, (f_uv_pos + 0.5) / textureSize(t_col_light, 0)/* + uv_delta*//* - f_norm * 0.00001*/); float f_ao, f_glow;
// vec4 f_col_light = textureGrad(t_col_light, (f_uv_pos + 0.5) / textureSize(t_col_light, 0), vec2(0.5), vec2(0.5)); vec3 f_col = greedy_extract_col_light_glow(t_col_light, f_uv_pos, f_ao, f_glow);
vec4 f_col_light = texelFetch(t_col_light, ivec2(f_uv_pos)/* + uv_delta*//* - f_norm * 0.00001*/, 0);
vec3 f_col = /*linear_to_srgb*//*srgb_to_linear*/(f_col_light.rgb);
// vec3 f_col = vec3(1.0);
// vec2 texSize = textureSize(t_col_light, 0);
// float f_ao = f_col_light.a;
// float f_ao = f_col_light.a + length(vec2(dFdx(f_col_light.a), dFdy(f_col_light.a)));
float f_ao = texture(t_col_light, (f_uv_pos + 0.5) / textureSize(t_col_light, 0)).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
// float f_ao = 1.0;
// 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 = f_pos_norm; // vec3 my_chunk_pos = f_pos_norm;
// tgt_color = vec4(hash(floor(vec4(my_chunk_pos.x, 0, 0, 0))), hash(floor(vec4(0, my_chunk_pos.y, 0, 1))), hash(floor(vec4(0, 0, my_chunk_pos.z, 2))), 1.0); // tgt_color = vec4(hash(floor(vec4(my_chunk_pos.x, 0, 0, 0))), hash(floor(vec4(0, my_chunk_pos.y, 0, 1))), hash(floor(vec4(0, 0, my_chunk_pos.z, 2))), 1.0);

View File

@ -81,12 +81,9 @@ void main() {
vec2 f_uv_pos = f_uv_pos + atlas_offs.xy; vec2 f_uv_pos = f_uv_pos + atlas_offs.xy;
// vec4 f_col_light = textureProj(t_col_light, vec3(f_uv_pos + 0.5, textureSize(t_col_light, 0)));//(f_uv_pos/* + 0.5*/) / texSize); // vec4 f_col_light = textureProj(t_col_light, vec3(f_uv_pos + 0.5, textureSize(t_col_light, 0)));//(f_uv_pos/* + 0.5*/) / texSize);
// float f_light = textureProj(t_col_light, vec3(f_uv_pos + 0.5, textureSize(t_col_light, 0))).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0; // float f_light = textureProj(t_col_light, vec3(f_uv_pos + 0.5, textureSize(t_col_light, 0))).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
vec4 f_col_light = texelFetch(t_col_light, ivec2(f_uv_pos)/* + uv_delta*//* - f_norm * 0.00001*/, 0); float f_light, f_glow;
// float f_light = f_col_light.a; vec3 f_col = greedy_extract_col_light_glow(t_col_light, f_uv_pos, f_light, f_glow);
// vec4 f_col_light = texelFetch(t_col_light, ivec2(int(f_uv_pos.x), int(f_uv_pos.y)/* + uv_delta*//* - f_norm * 0.00001*/), 0); //float f_light = (uint(texture(t_col_light, (f_uv_pos + 0.5) / textureSize(t_col_light, 0)).r * 255.0) & 0x1Fu) / 31.0;
vec3 f_col = /*linear_to_srgb*//*srgb_to_linear*/(f_col_light.rgb);
// vec3 f_col = vec3(1.0);
float f_light = texture(t_col_light, (f_uv_pos + 0.5) / textureSize(t_col_light, 0)).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
// vec2 texSize = textureSize(t_col_light, 0); // vec2 texSize = textureSize(t_col_light, 0);
// float f_light = texture(t_col_light, f_uv_pos/* + vec2(atlas_offs.xy)*/).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0; // float f_light = texture(t_col_light, f_uv_pos/* + vec2(atlas_offs.xy)*/).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
// float f_light = textureProj(t_col_light, vec3(f_uv_pos/* + vec2(atlas_offs.xy)*/, texSize.x)).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0; // float f_light = textureProj(t_col_light, vec3(f_uv_pos/* + vec2(atlas_offs.xy)*/, texSize.x)).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
@ -264,6 +261,8 @@ void main() {
// emitted_light *= f_light * point_shadow * max(shade_frac, MIN_SHADOW); // emitted_light *= f_light * point_shadow * max(shade_frac, MIN_SHADOW);
// reflected_light *= f_light * point_shadow * shade_frac; // reflected_light *= f_light * point_shadow * shade_frac;
// max_light *= f_light * point_shadow * shade_frac; // max_light *= f_light * point_shadow * shade_frac;
emitted_light += pow(f_glow, 5) * 16;
reflected_light += pow(f_glow, 5) * 16;
emitted_light *= f_light; emitted_light *= f_light;
reflected_light *= f_light; reflected_light *= f_light;
max_light *= f_light; max_light *= f_light;

View File

@ -167,13 +167,11 @@ impl Block {
#[inline] #[inline]
pub fn get_glow(&self) -> Option<u8> { pub fn get_glow(&self) -> Option<u8> {
// TODO: When we have proper volumetric lighting match self.get_sprite()? {
// match self.get_sprite()? { SpriteKind::StreetLamp | SpriteKind::StreetLampTall => Some(20),
// SpriteKind::StreetLamp | SpriteKind::StreetLampTall => Some(20), SpriteKind::Velorite | SpriteKind::VeloriteFrag => Some(3),
// SpriteKind::Velorite | SpriteKind::VeloriteFrag => Some(10), _ => None,
// _ => None, }
// }
None
} }
#[inline] #[inline]

View File

@ -11,7 +11,7 @@ type TodoRect = (
Vec3<i32>, Vec3<i32>,
); );
pub struct GreedyConfig<D, FL, FC, FO, FS, FP> { pub struct GreedyConfig<D, FL, FG, FC, FO, FS, FP> {
pub data: D, pub data: D,
/// The minimum position to mesh, in the coordinate system used /// The minimum position to mesh, in the coordinate system used
/// for queries against the volume. /// for queries against the volume.
@ -36,6 +36,9 @@ pub struct GreedyConfig<D, FL, FC, FO, FS, FP> {
/// Given a position, return the lighting information for the voxel at that /// Given a position, return the lighting information for the voxel at that
/// position. /// position.
pub get_light: FL, pub get_light: FL,
/// Given a position, return the glow information for the voxel at that
/// position (i.e: additional non-sun light).
pub get_glow: FG,
/// Given a position, return the color information for the voxel at that /// Given a position, return the color information for the voxel at that
/// position. /// position.
pub get_color: FC, pub get_color: FC,
@ -140,11 +143,12 @@ impl<'a> GreedyMesh<'a> {
/// Returns an estimate of the bounds of the current meshed model. /// Returns an estimate of the bounds of the current meshed model.
/// ///
/// For more information on the config parameter, see [GreedyConfig]. /// For more information on the config parameter, see [GreedyConfig].
pub fn push<M: PartialEq, D: 'a, FL, FC, FO, FS, FP>( pub fn push<M: PartialEq, D: 'a, FL, FG, FC, FO, FS, FP>(
&mut self, &mut self,
config: GreedyConfig<D, FL, FC, FO, FS, FP>, config: GreedyConfig<D, FL, FG, FC, FO, FS, FP>,
) where ) where
FL: for<'r> FnMut(&'r mut D, Vec3<i32>) -> f32 + 'a, FL: for<'r> FnMut(&'r mut D, Vec3<i32>) -> f32 + 'a,
FG: for<'r> FnMut(&'r mut D, Vec3<i32>) -> f32 + 'a,
FC: for<'r> FnMut(&'r mut D, Vec3<i32>) -> Rgb<u8> + 'a, FC: for<'r> FnMut(&'r mut D, Vec3<i32>) -> Rgb<u8> + 'a,
FO: for<'r> FnMut(&'r mut D, Vec3<i32>) -> bool + '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)>, FS: for<'r> FnMut(&'r mut D, Vec3<i32>, Vec3<i32>, Vec2<Vec3<i32>>) -> Option<(bool, M)>,
@ -173,7 +177,7 @@ impl<'a> GreedyMesh<'a> {
span!(_guard, "finalize", "GreedyMesh::finalize"); span!(_guard, "finalize", "GreedyMesh::finalize");
let cur_size = self.col_lights_size; let cur_size = self.col_lights_size;
let col_lights = vec![ let col_lights = vec![
TerrainVertex::make_col_light(254, Rgb::broadcast(254)); TerrainVertex::make_col_light(254, 0, Rgb::broadcast(254));
usize::from(cur_size.x) * usize::from(cur_size.y) usize::from(cur_size.x) * usize::from(cur_size.y)
]; ];
let mut col_lights_info = (col_lights, cur_size); let mut col_lights_info = (col_lights, cur_size);
@ -186,7 +190,7 @@ impl<'a> GreedyMesh<'a> {
pub fn max_size(&self) -> guillotiere::Size { self.max_size } pub fn max_size(&self) -> guillotiere::Size { self.max_size }
} }
fn greedy_mesh<'a, M: PartialEq, D: 'a, FL, FC, FO, FS, FP>( fn greedy_mesh<'a, M: PartialEq, D: 'a, FL, FG, FC, FO, FS, FP>(
atlas: &mut guillotiere::SimpleAtlasAllocator, atlas: &mut guillotiere::SimpleAtlasAllocator,
col_lights_size: &mut Vec2<u16>, col_lights_size: &mut Vec2<u16>,
max_size: guillotiere::Size, max_size: guillotiere::Size,
@ -196,14 +200,16 @@ fn greedy_mesh<'a, M: PartialEq, D: 'a, FL, FC, FO, FS, FP>(
greedy_size, greedy_size,
greedy_size_cross, greedy_size_cross,
get_light, get_light,
get_glow,
get_color, get_color,
get_opacity, get_opacity,
mut should_draw, mut should_draw,
mut push_quad, mut push_quad,
}: GreedyConfig<D, FL, FC, FO, FS, FP>, }: GreedyConfig<D, FL, FG, FC, FO, FS, FP>,
) -> Box<SuspendedMesh<'a>> ) -> Box<SuspendedMesh<'a>>
where where
FL: for<'r> FnMut(&'r mut D, Vec3<i32>) -> f32 + 'a, FL: for<'r> FnMut(&'r mut D, Vec3<i32>) -> f32 + 'a,
FG: for<'r> FnMut(&'r mut D, Vec3<i32>) -> f32 + 'a,
FC: for<'r> FnMut(&'r mut D, Vec3<i32>) -> Rgb<u8> + 'a, FC: for<'r> FnMut(&'r mut D, Vec3<i32>) -> Rgb<u8> + 'a,
FO: for<'r> FnMut(&'r mut D, Vec3<i32>) -> bool + '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)>, FS: for<'r> FnMut(&'r mut D, Vec3<i32>, Vec3<i32>, Vec2<Vec3<i32>>) -> Option<(bool, M)>,
@ -356,6 +362,7 @@ where
todo_rects, todo_rects,
draw_delta, draw_delta,
get_light, get_light,
get_glow,
get_color, get_color,
get_opacity, get_opacity,
TerrainVertex::make_col_light, TerrainVertex::make_col_light,
@ -511,9 +518,10 @@ fn draw_col_lights<D>(
todo_rects: Vec<TodoRect>, todo_rects: Vec<TodoRect>,
draw_delta: Vec3<i32>, draw_delta: Vec3<i32>,
mut get_light: impl FnMut(&mut D, Vec3<i32>) -> f32, mut get_light: impl FnMut(&mut D, Vec3<i32>) -> f32,
mut get_glow: impl FnMut(&mut D, Vec3<i32>) -> f32,
mut get_color: impl FnMut(&mut D, Vec3<i32>) -> Rgb<u8>, mut get_color: impl FnMut(&mut D, Vec3<i32>) -> Rgb<u8>,
mut get_opacity: impl FnMut(&mut D, Vec3<i32>) -> bool, mut get_opacity: impl FnMut(&mut D, Vec3<i32>) -> bool,
mut make_col_light: impl FnMut(u8, Rgb<u8>) -> <<ColLightFmt as gfx::format::Formatted>::Surface as gfx::format::SurfaceTyped>::DataType, mut make_col_light: impl FnMut(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)| { todo_rects.into_iter().for_each(|(pos, uv, rect, delta)| {
// NOTE: Conversions are safe because width, height, and offset must be // NOTE: Conversions are safe because width, height, and offset must be
@ -579,8 +587,9 @@ fn draw_col_lights<D>(
} }
) / 4.0; ) / 4.0;
let col = get_color(data, pos); let col = get_color(data, pos);
let light = (darkness * 255.0) as u8; let light = (darkness * 31.5) as u8;
*col_light = make_col_light(light, col); let glow = (get_glow(data, light_pos) * 31.5) as u8;
*col_light = make_col_light(light, glow, col);
}); });
}); });
}); });

View File

@ -77,6 +77,7 @@ where
0.0 0.0
} }
}; };
let get_glow = |vol: &mut V, pos: Vec3<i32>| 0.0;
let get_color = |vol: &mut V, pos: Vec3<i32>| { let get_color = |vol: &mut V, pos: Vec3<i32>| {
vol.get(pos) vol.get(pos)
.ok() .ok()
@ -100,6 +101,7 @@ where
greedy_size, greedy_size,
greedy_size_cross, greedy_size_cross,
get_light, get_light,
get_glow,
get_color, get_color,
get_opacity, get_opacity,
should_draw, should_draw,
@ -179,6 +181,7 @@ where
0.0 0.0
} }
}; };
let get_glow = |vol: &mut V, pos: Vec3<i32>| 0.0;
let get_color = |vol: &mut V, pos: Vec3<i32>| { let get_color = |vol: &mut V, pos: Vec3<i32>| {
vol.get(pos) vol.get(pos)
.ok() .ok()
@ -201,6 +204,7 @@ where
greedy_size, greedy_size,
greedy_size_cross, greedy_size_cross,
get_light, get_light,
get_glow,
get_color, get_color,
get_opacity, get_opacity,
should_draw, should_draw,
@ -273,6 +277,7 @@ where
0.0 0.0
} }
}; };
let get_glow = |vol: &mut V, pos: Vec3<i32>| 0.0;
let get_color = |vol: &mut V, pos: Vec3<i32>| { let get_color = |vol: &mut V, pos: Vec3<i32>| {
vol.get(pos) vol.get(pos)
.ok() .ok()
@ -295,6 +300,7 @@ where
greedy_size, greedy_size,
greedy_size_cross, greedy_size_cross,
get_light, get_light,
get_glow,
get_color, get_color,
get_opacity, get_opacity,
should_draw, should_draw,

View File

@ -4,6 +4,7 @@ use crate::{
MeshGen, Meshable, MeshGen, Meshable,
}, },
render::{self, ColLightInfo, FluidPipeline, Mesh, ShadowPipeline, TerrainPipeline}, render::{self, ColLightInfo, FluidPipeline, Mesh, ShadowPipeline, TerrainPipeline},
scene::terrain::BlocksOfInterest,
}; };
use common::{ use common::{
span, span,
@ -30,9 +31,10 @@ enum FaceKind {
} }
const SUNLIGHT: u8 = 24; const SUNLIGHT: u8 = 24;
const _MAX_LIGHT_DIST: i32 = SUNLIGHT as i32; const MAX_LIGHT_DIST: i32 = SUNLIGHT as i32;
fn calc_light<V: RectRasterableVol<Vox = Block> + ReadVol + Debug>( fn calc_light<V: RectRasterableVol<Vox = Block> + ReadVol + Debug>(
is_sunlight: bool,
bounds: Aabb<i32>, bounds: Aabb<i32>,
vol: &VolGrid2d<V>, vol: &VolGrid2d<V>,
lit_blocks: impl Iterator<Item = (Vec3<i32>, u8)>, lit_blocks: impl Iterator<Item = (Vec3<i32>, u8)>,
@ -57,32 +59,34 @@ fn calc_light<V: RectRasterableVol<Vox = Block> + ReadVol + Debug>(
let mut prop_que = lit_blocks let mut prop_que = lit_blocks
.map(|(pos, light)| { .map(|(pos, light)| {
let rpos = pos - outer.min; let rpos = pos - outer.min;
light_map[lm_idx(rpos.x, rpos.y, rpos.z)] = light; light_map[lm_idx(rpos.x, rpos.y, rpos.z)] = light.min(SUNLIGHT); // Brightest light
(rpos.x as u8, rpos.y as u8, rpos.z as u16) (rpos.x as u8, rpos.y as u8, rpos.z as u16)
}) })
.collect::<VecDeque<_>>(); .collect::<VecDeque<_>>();
// Start sun rays // Start sun rays
for x in 0..outer.size().w { if is_sunlight {
for y in 0..outer.size().h { for x in 0..outer.size().w {
let z = outer.size().d - 1; for y in 0..outer.size().h {
let is_air = vol_cached let z = outer.size().d - 1;
.get(outer.min + Vec3::new(x, y, z)) let is_air = vol_cached
.ok() .get(outer.min + Vec3::new(x, y, z))
.map_or(false, |b| b.is_air());
light_map[lm_idx(x, y, z)] = if is_air {
if vol_cached
.get(outer.min + Vec3::new(x, y, z - 1))
.ok() .ok()
.map_or(false, |b| b.is_air()) .map_or(false, |b| b.is_air());
{
light_map[lm_idx(x, y, z - 1)] = SUNLIGHT; light_map[lm_idx(x, y, z)] = if is_air {
prop_que.push_back((x as u8, y as u8, z as u16)); if vol_cached
} .get(outer.min + Vec3::new(x, y, z - 1))
SUNLIGHT .ok()
} else { .map_or(false, |b| b.is_air())
OPAQUE {
}; light_map[lm_idx(x, y, z - 1)] = SUNLIGHT;
prop_que.push_back((x as u8, y as u8, z as u16));
}
SUNLIGHT
} else {
OPAQUE
};
}
} }
} }
@ -123,7 +127,7 @@ fn calc_light<V: RectRasterableVol<Vox = Block> + ReadVol + Debug>(
let light = light_map[lm_idx(pos.x, pos.y, pos.z)]; let light = light_map[lm_idx(pos.x, pos.y, pos.z)];
// If ray propagate downwards at full strength // If ray propagate downwards at full strength
if light == SUNLIGHT { if is_sunlight && light == SUNLIGHT {
// Down is special cased and we know up is a ray // Down is special cased and we know up is a ray
// Special cased ray propagation // Special cased ray propagation
let pos = Vec3::new(pos.x, pos.y, pos.z - 1); let pos = Vec3::new(pos.x, pos.y, pos.z - 1);
@ -218,7 +222,7 @@ impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug>
type Pipeline = TerrainPipeline; type Pipeline = TerrainPipeline;
type Result = (Aabb<f32>, ColLightInfo); type Result = (Aabb<f32>, ColLightInfo);
type ShadowPipeline = ShadowPipeline; type ShadowPipeline = ShadowPipeline;
type Supplement = (Aabb<i32>, Vec2<u16>); type Supplement = (Aabb<i32>, Vec2<u16>, &'a BlocksOfInterest);
type TranslucentPipeline = FluidPipeline; type TranslucentPipeline = FluidPipeline;
#[allow(clippy::collapsible_if)] #[allow(clippy::collapsible_if)]
@ -229,21 +233,42 @@ impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug>
fn generate_mesh( fn generate_mesh(
self, self,
(range, max_texture_size): Self::Supplement, (range, max_texture_size, boi): Self::Supplement,
) -> MeshGen<TerrainPipeline, FluidPipeline, Self> { ) -> MeshGen<TerrainPipeline, FluidPipeline, Self> {
span!( span!(
_guard, _guard,
"generate_mesh", "generate_mesh",
"<&VolGrid2d as Meshable<_, _>>::generate_mesh" "<&VolGrid2d as Meshable<_, _>>::generate_mesh"
); );
// Find blocks that should glow // Find blocks that should glow
// FIXME: Replace with real lit blocks when we actually have blocks that glow. // TODO: Search neighbouring chunks too!
let lit_blocks = core::iter::empty(); // let glow_blocks = boi.lights
// .iter()
// .map(|(pos, glow)| (*pos + range.min.xy(), *glow));
/* DefaultVolIterator::new(self, range.min - MAX_LIGHT_DIST, range.max + MAX_LIGHT_DIST) /* DefaultVolIterator::new(self, range.min - MAX_LIGHT_DIST, range.max + MAX_LIGHT_DIST)
.filter_map(|(pos, block)| block.get_glow().map(|glow| (pos, glow))); */ .filter_map(|(pos, block)| block.get_glow().map(|glow| (pos, glow))); */
let mut glow_blocks = Vec::new();
// TODO: This expensive, use BlocksOfInterest instead
let mut volume = self.cached();
for x in -MAX_LIGHT_DIST..range.size().w + MAX_LIGHT_DIST {
for y in -MAX_LIGHT_DIST..range.size().h + MAX_LIGHT_DIST {
for z in -1..range.size().d + 1 {
let wpos = range.min + Vec3::new(x, y, z);
volume
.get(wpos)
.ok()
.and_then(|b| b.get_glow())
.map(|glow| glow_blocks.push((wpos, glow)));
}
}
}
// Calculate chunk lighting // Calculate chunk lighting
let mut light = calc_light(range, self, lit_blocks); let mut light = calc_light(true, range, self, core::iter::empty());
let mut glow = calc_light(false, range, self, glow_blocks.into_iter());
let mut opaque_limits = None::<Limits>; let mut opaque_limits = None::<Limits>;
let mut fluid_limits = None::<Limits>; let mut fluid_limits = None::<Limits>;
@ -265,8 +290,9 @@ impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug>
for x in 0..range.size().w { for x in 0..range.size().w {
for y in 0..range.size().h { for y in 0..range.size().h {
for z in -1..range.size().d + 1 { for z in -1..range.size().d + 1 {
let wpos = range.min + Vec3::new(x, y, z);
let block = volume let block = volume
.get(range.min + Vec3::new(x, y, z)) .get(wpos)
.map(|b| *b) .map(|b| *b)
// TODO: Replace with None or some other more reasonable value, // TODO: Replace with None or some other more reasonable value,
// since it's not clear this will work properly with liquid. // since it's not clear this will work properly with liquid.
@ -342,6 +368,7 @@ impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug>
let draw_delta = Vec3::new(1, 1, z_start); let draw_delta = Vec3::new(1, 1, z_start);
let get_light = |_: &mut (), pos: Vec3<i32>| light(pos + range.min); let get_light = |_: &mut (), pos: Vec3<i32>| light(pos + range.min);
let get_glow = |_: &mut (), pos: Vec3<i32>| glow(pos + range.min);
let get_color = let get_color =
|_: &mut (), pos: Vec3<i32>| flat_get(pos).get_color().unwrap_or(Rgb::zero()); |_: &mut (), pos: Vec3<i32>| flat_get(pos).get_color().unwrap_or(Rgb::zero());
let get_opacity = |_: &mut (), pos: Vec3<i32>| !flat_get(pos).is_opaque(); let get_opacity = |_: &mut (), pos: Vec3<i32>| !flat_get(pos).is_opaque();
@ -365,6 +392,7 @@ impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug>
greedy_size, greedy_size,
greedy_size_cross, greedy_size_cross,
get_light, get_light,
get_glow,
get_color, get_color,
get_opacity, get_opacity,
should_draw, should_draw,

View File

@ -99,11 +99,34 @@ impl Vertex {
} }
pub fn make_col_light( pub fn make_col_light(
// 0 to 31
light: u8, light: u8,
// 0 to 31
glow: u8,
col: Rgb<u8>, col: Rgb<u8>,
) -> <<ColLightFmt as gfx::format::Formatted>::Surface as gfx::format::SurfaceTyped>::DataType ) -> <<ColLightFmt as gfx::format::Formatted>::Surface as gfx::format::SurfaceTyped>::DataType
{ {
[col.r, col.g, col.b, light] //[col.r, col.g, col.b, light]
// It would be nice for this to be cleaner, but we want to squeeze 5 fields into 4.
// We can do this because both `light` and `glow` go from 0 to 31, meaning that they
// can both fit into 5 bits. If we steal a bit from red and blue each (not green,
// human eyes are more sensitive to changes in green) then we get just enough to
// expand the nibbles of the alpha field enough to fit both `light` and `glow`.
//
// However, we now have a problem. In the shader code with use hardware filtering to
// get at the `light` and `glow` attributes (but not colour, that remains constant
// across a block). How to we resolve this if we're twiddling bits? The answer is to
// very carefully manipulate the bit pattern such that the fields we want to filter
// (`light` and `glow`) always sit as the lower bits of the fields. Then, we can do
// some modulation magic to extract them from the filtering unharmed and use
// unfiltered texture access (i.e: `texelFetch`) to access the colours, plus a little
// bit-fiddling.
[
((col.r & 0b1110) << 4) | light.min(31),
((col.b & 0b1110) << 4) | glow.min(31),
(col.r & 0b11110000) | (col.b >> 4),
col.g, // Green is lucky, it remains unscathed
]
} }
} }

View File

@ -67,7 +67,7 @@ pub type LodAltFmt = (gfx::format::R16_G16, gfx::format::Unorm);
pub type LodColorFmt = (gfx::format::R8_G8_B8_A8, gfx::format::Srgb); pub type LodColorFmt = (gfx::format::R8_G8_B8_A8, gfx::format::Srgb);
/// Represents the format of greedy meshed color-light textures. /// Represents the format of greedy meshed color-light textures.
pub type ColLightFmt = (gfx::format::R8_G8_B8_A8, gfx::format::Srgb); pub type ColLightFmt = (gfx::format::R8_G8_B8_A8, gfx::format::Unorm);
/// A handle to a shadow depth target. /// A handle to a shadow depth target.
pub type ShadowDepthStencilView = pub type ShadowDepthStencilView =
@ -994,13 +994,18 @@ impl Renderer {
} }
/// Update a texture with the provided offset, size, and data. /// Update a texture with the provided offset, size, and data.
pub fn update_texture( pub fn update_texture<T: gfx::format::Formatted>(
&mut self, &mut self,
texture: &Texture, texture: &Texture<T>,
offset: [u16; 2], offset: [u16; 2],
size: [u16; 2], size: [u16; 2],
data: &[[u8; 4]], data: &[<<T as gfx::format::Formatted>::Surface as gfx::format::SurfaceTyped>::DataType],
) -> Result<(), RenderError> { ) -> Result<(), RenderError>
where
<T as gfx::format::Formatted>::Surface: gfx::format::TextureSurface,
<T as gfx::format::Formatted>::Channel: gfx::format::TextureChannel,
<<T as gfx::format::Formatted>::Surface as gfx::format::SurfaceTyped>::DataType: Copy,
{
texture.update(&mut self.encoder, offset, size, data) texture.update(&mut self.encoder, offset, size, data)
} }

View File

@ -138,8 +138,9 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug>(
sprite_config: &SpriteSpec, sprite_config: &SpriteSpec,
) -> MeshWorkerResponse { ) -> MeshWorkerResponse {
span!(_guard, "mesh_worker"); span!(_guard, "mesh_worker");
let blocks_of_interest = BlocksOfInterest::from_chunk(&chunk);
let (opaque_mesh, fluid_mesh, _shadow_mesh, (bounds, col_lights_info)) = let (opaque_mesh, fluid_mesh, _shadow_mesh, (bounds, col_lights_info)) =
volume.generate_mesh((range, Vec2::new(max_texture_size, max_texture_size))); volume.generate_mesh((range, Vec2::new(max_texture_size, max_texture_size), &blocks_of_interest));
MeshWorkerResponse { MeshWorkerResponse {
pos, pos,
z_bounds: (bounds.min.z, bounds.max.z), z_bounds: (bounds.min.z, bounds.max.z),
@ -199,7 +200,7 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug>(
instances instances
}, },
blocks_of_interest: BlocksOfInterest::from_chunk(&chunk), blocks_of_interest,
started_tick, started_tick,
} }
} }

View File

@ -17,6 +17,7 @@ pub struct BlocksOfInterest {
// Note: these are only needed for chunks within the iteraction range so this is a potential // Note: these are only needed for chunks within the iteraction range so this is a potential
// area for optimization // area for optimization
pub interactables: Vec<Vec3<i32>>, pub interactables: Vec<Vec3<i32>>,
pub lights: Vec<(Vec3<i32>, u8)>,
} }
impl BlocksOfInterest { impl BlocksOfInterest {
@ -30,6 +31,7 @@ impl BlocksOfInterest {
let mut reeds = Vec::new(); let mut reeds = Vec::new();
let mut flowers = Vec::new(); let mut flowers = Vec::new();
let mut interactables = Vec::new(); let mut interactables = Vec::new();
let mut lights = Vec::new();
chunk chunk
.vol_iter( .vol_iter(
@ -73,6 +75,9 @@ impl BlocksOfInterest {
if block.is_collectible() { if block.is_collectible() {
interactables.push(pos); interactables.push(pos);
} }
if let Some(glow) = block.get_glow() {
lights.push((pos, glow));
}
}); });
Self { Self {
@ -84,6 +89,7 @@ impl BlocksOfInterest {
reeds, reeds,
flowers, flowers,
interactables, interactables,
lights,
} }
} }
} }