Preserved light/glow maps to prevent sprites/entities being lit when they shouldn't be

This commit is contained in:
Joshua Barretto 2020-11-21 15:51:42 +00:00
parent 51d1a2ecff
commit 27e7fd0727
16 changed files with 138 additions and 29 deletions

View File

@ -49,6 +49,7 @@ layout (std140)
uniform u_locals {
mat4 model_mat;
vec4 highlight_col;
vec4 model_light;
ivec4 atlas_offs;
vec3 model_pos;
// bit 0 - is player
@ -159,6 +160,10 @@ void main() {
vec3 emitted_light, reflected_light;
// Make voxel shadows block the sun and moon
sun_info.block *= model_light.x;
moon_info.block *= model_light.x;
// vec3 light_frac = /*vec3(1.0);*//*vec3(max(dot(f_norm, -sun_dir) * 0.5 + 0.5, 0.0));*/light_reflection_factor(f_norm, view_dir, vec3(0, 0, -1.0), vec3(1.0), vec3(R_s), alpha);
// vec3 point_light = light_at(f_pos, f_norm);
// vec3 light, diffuse_light, ambient_light;
@ -176,6 +181,9 @@ 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;
float glow = model_light.y;
emitted_light += glow;
reflected_light *= ao;
emitted_light *= ao;
/* reflected_light *= cloud_shadow(f_pos); */

View File

@ -27,6 +27,7 @@ layout (std140)
uniform u_locals {
mat4 model_mat;
vec4 highlight_col;
vec4 model_light;
ivec4 atlas_offs;
vec3 model_pos;
// bit 0 - is player

View File

@ -7,6 +7,8 @@
struct DirectionalLight {
// vec3 dir;
float shadow;
// Fully blocks all light, including ambience
float block;
// vec3 color;
// float brightness;
};
@ -135,6 +137,7 @@ vec3 get_moon_color(/*vec3 moon_dir*/) {
DirectionalLight get_sun_info(vec4 _dir, float shade_frac/*, vec4 light_pos[2]*/, /*vec4 sun_pos*/vec3 f_pos) {
float shadow = shade_frac;
float block = 1.0;
#ifdef HAS_SHADOW_MAPS
#if (SHADOW_MODE == SHADOW_MODE_MAP)
if (sun_dir.z < /*0.6*/0.0) {
@ -151,15 +154,16 @@ DirectionalLight get_sun_info(vec4 _dir, float shade_frac/*, vec4 light_pos[2]*/
}
#endif
#endif
return DirectionalLight(/*dir, */shadow/*, get_sun_color(dir), get_sun_brightness(dir)*/);
return DirectionalLight(/*dir, */shadow, block/*, get_sun_color(dir), get_sun_brightness(dir)*/);
}
DirectionalLight get_moon_info(vec4 _dir, float shade_frac/*, vec4 light_pos[2]*/) {
float shadow = shade_frac;
float block = 1.0;
// #ifdef HAS_SHADOW_MAPS
// shadow = min(shade_frac, ShadowCalculationDirected(light_pos, 1u));
// #endif
return DirectionalLight(/*dir, */shadow/*, get_moon_color(dir), get_moon_brightness(dir)*/);
return DirectionalLight(/*dir, */shadow, block/*, get_moon_color(dir), get_moon_brightness(dir)*/);
}
// // Calculates extra emission and reflectance (due to sunlight / moonlight).
@ -227,8 +231,8 @@ float get_sun_diffuse2(DirectionalLight sun_info, DirectionalLight moon_info, ve
vec3 sun_dir = sun_dir.xyz;
vec3 moon_dir = moon_dir.xyz;
float sun_light = get_sun_brightness(/*sun_dir*/);//sun_info.brightness;;
float moon_light = get_moon_brightness(/*moon_dir*/);//moon_info.brightness;
float sun_light = get_sun_brightness(/*sun_dir*/) * sun_info.block;//sun_info.brightness;;
float moon_light = get_moon_brightness(/*moon_dir*/) * moon_info.block;//moon_info.brightness;
vec3 sun_color = get_sun_color(/*sun_dir*/) * SUN_COLOR_FACTOR;//sun_info.color * SUN_COLOR_FACTOR;
vec3 moon_color = get_moon_color(/*moon_dir*/);//moon_info.color;

View File

@ -39,6 +39,7 @@ layout (std140)
uniform u_locals {
mat4 model_mat;
vec4 highlight_col;
vec4 model_light;
ivec4 atlas_offs;
vec3 model_pos;
// bit 0 - is player

View File

@ -66,6 +66,13 @@ void main() {
vec3 emitted_light, reflected_light;
// This is a bit of a hack. Because we can't find the volumetric lighting of each particle (they don't talk to the
// CPU) we need to some how find an approximation of how much the sun is blocked. We do this by fading out the sun
// as the particle moves underground. This isn't perfect, but it does at least mean that particles don't look like
// they're exposed to the sun when in dungeons
const float SUN_FADEOUT_DIST = 20.0;
sun_info.block *= clamp((f_pos.z - f_alt) / SUN_FADEOUT_DIST + 1, 0, 1);
// To account for prior saturation.
float max_light = 0.0;
max_light += get_sun_diffuse2(sun_info, moon_info, f_norm, view_dir, k_a, k_d, k_s, alpha, emitted_light, reflected_light);

View File

@ -25,6 +25,7 @@ layout (std140)
uniform u_locals {
mat4 model_mat;
vec4 highlight_col;
vec4 model_light;
ivec4 atlas_offs;
vec3 model_pos;
int flags;

View File

@ -21,6 +21,7 @@ flat in vec3 f_norm;
flat in float f_light;
// flat in vec3 f_pos_norm;
in vec2 f_uv_pos;
in vec2 f_inst_light;
// flat in uint f_atlas_pos;
// in vec3 f_col;
// in float f_ao;
@ -133,6 +134,10 @@ void main() {
vec3 emitted_light, reflected_light;
// Make voxel shadows block the sun and moon
sun_info.block = f_inst_light.x;
moon_info.block = f_inst_light.x;
// To account for prior saturation.
// float vert_light = pow(f_light, 1.5);
// vec3 light_frac = light_reflection_factor(f_norm/*vec3(0, 0, 1.0)*/, view_dir, vec3(0, 0, -1.0), vec3(1.0), vec3(R_s), alpha);
@ -169,6 +174,9 @@ void main() {
reflected_light += point_light; */
// float ao = /*pow(f_ao, 0.5)*/f_ao * 0.85 + 0.15;
float glow = f_inst_light.y;
emitted_light += glow;
float ao = f_ao;
emitted_light *= ao;
reflected_light *= ao;

View File

@ -25,7 +25,7 @@ in vec4 inst_mat0;
in vec4 inst_mat1;
in vec4 inst_mat2;
in vec4 inst_mat3;
// in vec3 inst_col;
in vec4 inst_light;
in float inst_wind_sway;
struct SpriteLocals {
@ -77,6 +77,7 @@ flat out float f_light;
// out vec3 f_col;
// out float f_ao;
out vec2 f_uv_pos;
out vec2 f_inst_light;
// flat out uint f_atlas_pos;
// out vec3 light_pos[2];
// out float f_light;
@ -117,6 +118,8 @@ void main() {
// float inst_wind_sway = wind_sway.w;
// vec3 inst_offs = model_offs - focus_off.xyz;
f_inst_light = inst_light.xy;
// vec3 sprite_pos = floor(inst_mat3.xyz * SCALE) + inst_offs;
// f_pos_norm = v_pos;

View File

@ -261,12 +261,15 @@ void main() {
// emitted_light *= f_light * point_shadow * max(shade_frac, MIN_SHADOW);
// reflected_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;
reflected_light *= f_light;
max_light *= f_light;
// TODO: Apply AO after this
float l = pow(f_glow, 6) * 8 + pow(f_glow, 2) * 0.5;
emitted_light += l;
reflected_light += l;
max_light += lights_at(f_pos, f_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light);
// float f_ao = 1.0;

View File

@ -35,10 +35,12 @@ const MAX_LIGHT_DIST: i32 = SUNLIGHT as i32;
fn calc_light<V: RectRasterableVol<Vox = Block> + ReadVol + Debug>(
is_sunlight: bool,
// When above bounds
default_light: f32,
bounds: Aabb<i32>,
vol: &VolGrid2d<V>,
lit_blocks: impl Iterator<Item = (Vec3<i32>, u8)>,
) -> impl FnMut(Vec3<i32>) -> f32 + '_ {
) -> impl Fn(Vec3<i32>) -> f32 + 'static + Send + Sync {
span!(_guard, "calc_light");
const UNKNOWN: u8 = 255;
const OPAQUE: u8 = 254;
@ -210,17 +212,25 @@ fn calc_light<V: RectRasterableVol<Vox = Block> + ReadVol + Debug>(
let pos = wpos - outer.min;
light_map
.get(lm_idx(pos.x, pos.y, pos.z))
.filter(|l| **l != OPAQUE && **l != UNKNOWN)
.map(|l| *l as f32 / SUNLIGHT as f32)
.unwrap_or(0.0)
.map(|l| if *l != OPAQUE && *l != UNKNOWN {
*l as f32 / SUNLIGHT as f32
} else {
0.0
})
.unwrap_or(default_light)
}
}
impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug>
impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug + 'static>
Meshable<TerrainPipeline, FluidPipeline> for &'a VolGrid2d<V>
{
type Pipeline = TerrainPipeline;
type Result = (Aabb<f32>, ColLightInfo);
type Result = (
Aabb<f32>,
ColLightInfo,
Box<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
Box<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
);
type ShadowPipeline = ShadowPipeline;
type Supplement = (Aabb<i32>, Vec2<u16>, &'a BlocksOfInterest);
type TranslucentPipeline = FluidPipeline;
@ -266,9 +276,9 @@ impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug>
}
}
// Calculate chunk lighting
let mut light = calc_light(true, range, self, core::iter::empty());
let mut glow = calc_light(false, range, self, glow_blocks.into_iter());
// Calculate chunk lighting (sunlight defaults to 1.0, glow to 0.0)
let mut light = calc_light(true, 1.0, range, self, core::iter::empty());
let mut glow = calc_light(false, 0.0, range, self, glow_blocks.into_iter());
let mut opaque_limits = None::<Limits>;
let mut fluid_limits = None::<Limits>;
@ -433,7 +443,7 @@ impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug>
opaque_mesh,
fluid_mesh,
Mesh::new(),
(bounds, (col_lights, col_lights_size)),
(bounds, (col_lights, col_lights_size), Box::new(light), Box::new(glow)),
)
}
}

View File

@ -13,6 +13,7 @@ gfx_defines! {
constant Locals {
model_mat: [[f32; 4]; 4] = "model_mat",
highlight_col: [f32; 4] = "highlight_col",
model_light: [f32; 4] = "model_light",
atlas_offs: [i32; 4] = "atlas_offs",
model_pos: [f32; 3] = "model_pos",
flags: u32 = "flags",
@ -54,19 +55,22 @@ gfx_defines! {
impl Locals {
pub fn new(
model_mat: anim::vek::Mat4<f32>,
col: Rgba<f32>,
col: Rgb<f32>,
pos: anim::vek::Vec3<f32>,
atlas_offs: Vec2<i32>,
is_player: bool,
light: f32,
glow: f32,
) -> Self {
let mut flags = 0;
flags |= is_player as u32;
Self {
model_mat: model_mat.into_col_arrays(),
highlight_col: col.into_array(),
highlight_col: [col.r, col.g, col.b, glow],
model_pos: pos.into_array(),
atlas_offs: Vec4::from(atlas_offs).into_array(),
model_light: [light, glow, 1.0, 1.0],
flags,
}
}
@ -76,10 +80,12 @@ impl Default for Locals {
fn default() -> Self {
Self::new(
anim::vek::Mat4::identity(),
Rgba::broadcast(1.0),
Rgb::broadcast(1.0),
anim::vek::Vec3::default(),
Vec2::default(),
false,
1.0,
0.0,
)
}
}

View File

@ -39,6 +39,7 @@ gfx_defines! {
inst_mat1: [f32; 4] = "inst_mat1",
inst_mat2: [f32; 4] = "inst_mat2",
inst_mat3: [f32; 4] = "inst_mat3",
inst_light: [f32; 4] = "inst_light",
inst_wind_sway: f32 = "inst_wind_sway",
}
@ -114,7 +115,7 @@ impl Vertex {
}
impl Instance {
pub fn new(mat: Mat4<f32>, wind_sway: f32, pos: Vec3<i32>, ori_bits: u8) -> Self {
pub fn new(mat: Mat4<f32>, wind_sway: f32, pos: Vec3<i32>, ori_bits: u8, light: f32, glow: f32) -> Self {
const EXTRA_NEG_Z: i32 = 32768;
let mat_arr = mat.into_col_arrays();
@ -127,13 +128,14 @@ impl Instance {
inst_mat1: mat_arr[1],
inst_mat2: mat_arr[2],
inst_mat3: mat_arr[3],
inst_light: [light, glow, 1.0, 1.0],
inst_wind_sway: wind_sway,
}
}
}
impl Default for Instance {
fn default() -> Self { Self::new(Mat4::identity(), 0.0, Vec3::zero(), 0) }
fn default() -> Self { Self::new(Mat4::identity(), 0.0, Vec3::zero(), 0, 1.0, 0.0) }
}
impl Default for Locals {

View File

@ -13,6 +13,7 @@ use crate::{
scene::{
camera::{Camera, CameraMode, Dependents},
math, LodData, SceneData,
terrain::Terrain,
},
};
use anim::{
@ -455,6 +456,7 @@ impl FigureMgr {
// Visible chunk data.
visible_psr_bounds: math::Aabr<f32>,
camera: &Camera,
terrain: Option<&Terrain>,
) -> anim::vek::Aabb<f32> {
span!(_guard, "maintain", "FigureManager::maintain");
let state = scene_data.state;
@ -1329,6 +1331,7 @@ impl FigureMgr {
is_player,
camera,
&mut update_buf,
terrain,
);
},
Body::QuadrupedSmall(body) => {
@ -1439,6 +1442,7 @@ impl FigureMgr {
is_player,
camera,
&mut update_buf,
terrain,
);
},
Body::QuadrupedMedium(body) => {
@ -1560,6 +1564,7 @@ impl FigureMgr {
is_player,
camera,
&mut update_buf,
terrain,
);
},
Body::QuadrupedLow(body) => {
@ -1668,6 +1673,7 @@ impl FigureMgr {
is_player,
camera,
&mut update_buf,
terrain,
);
},
Body::BirdMedium(body) => {
@ -1773,6 +1779,7 @@ impl FigureMgr {
is_player,
camera,
&mut update_buf,
terrain,
);
},
Body::FishMedium(body) => {
@ -1859,6 +1866,7 @@ impl FigureMgr {
is_player,
camera,
&mut update_buf,
terrain,
);
},
Body::Dragon(body) => {
@ -1941,6 +1949,7 @@ impl FigureMgr {
is_player,
camera,
&mut update_buf,
terrain,
);
},
Body::Theropod(body) => {
@ -2025,6 +2034,7 @@ impl FigureMgr {
is_player,
camera,
&mut update_buf,
terrain,
);
},
Body::BirdSmall(body) => {
@ -2111,6 +2121,7 @@ impl FigureMgr {
is_player,
camera,
&mut update_buf,
terrain,
);
},
Body::FishSmall(body) => {
@ -2197,6 +2208,7 @@ impl FigureMgr {
is_player,
camera,
&mut update_buf,
terrain,
);
},
Body::BipedLarge(body) => {
@ -2603,6 +2615,7 @@ impl FigureMgr {
is_player,
camera,
&mut update_buf,
terrain,
);
},
Body::Golem(body) => {
@ -2707,6 +2720,7 @@ impl FigureMgr {
is_player,
camera,
&mut update_buf,
terrain,
);
},
Body::Object(body) => {
@ -2740,6 +2754,7 @@ impl FigureMgr {
is_player,
camera,
&mut update_buf,
terrain,
);
},
}
@ -3393,6 +3408,7 @@ impl<S: Skeleton> FigureState<S> {
is_player: bool,
_camera: &Camera,
buf: &mut [anim::FigureBoneData; anim::MAX_BONE_COUNT],
terrain: Option<&Terrain>,
) {
// NOTE: As long as update() always gets called after get_or_create_model(), and
// visibility is not set again until after the model is rendered, we
@ -3429,12 +3445,23 @@ impl<S: Skeleton> FigureState<S> {
* anim::vek::Mat4::scaling_3d(anim::vek::Vec3::from(0.8 * scale));
let atlas_offs = model.allocation.rectangle.min;
let (light, glow) = terrain
.map(|t| {
// Sample the location a little above to avoid clipping into terrain
let wpos = (Vec3::from(pos.into_array()) + Vec3::unit_z() * 0.5).map(|e: f32| e.floor() as i32);
(t.light_at_wpos(wpos), t.glow_at_wpos(wpos))
})
.unwrap_or((1.0, 0.0));
let locals = FigureLocals::new(
mat,
col,
col.rgb(),
pos,
vek::Vec2::new(atlas_offs.x, atlas_offs.y),
is_player,
light,
glow,
);
renderer.update_consts(&mut self.locals, &[locals]).unwrap();

View File

@ -698,9 +698,13 @@ impl Scene {
);
// Maintain the figures.
let _figure_bounds =
self.figure_mgr
.maintain(renderer, scene_data, visible_psr_bounds, &self.camera);
let _figure_bounds = self.figure_mgr.maintain(
renderer,
scene_data,
visible_psr_bounds,
&self.camera,
Some(&self.terrain),
);
let sun_dir = scene_data.get_sun_dir();
let is_daylight = sun_dir.z < 0.0;

View File

@ -187,6 +187,7 @@ impl Scene {
false,
&camera,
&mut buf,
None,
);
(model, state)
}),
@ -353,6 +354,7 @@ impl Scene {
false,
&self.camera,
&mut buf,
None,
);
}
}

View File

@ -61,6 +61,8 @@ pub struct TerrainChunkData {
opaque_model: Model<TerrainPipeline>,
fluid_model: Option<Model<FluidPipeline>>,
col_lights: guillotiere::AllocId,
light_map: Box<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
glow_map: Box<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
sprite_instances: HashMap<(SpriteKind, usize), Instances<SpriteInstance>>,
locals: Consts<TerrainLocals>,
pub blocks_of_interest: BlocksOfInterest,
@ -87,6 +89,8 @@ struct MeshWorkerResponse {
opaque_mesh: Mesh<TerrainPipeline>,
fluid_mesh: Mesh<FluidPipeline>,
col_lights_info: ColLightInfo,
light_map: Box<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
glow_map: Box<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
sprite_instances: HashMap<(SpriteKind, usize), Vec<SpriteInstance>>,
started_tick: u64,
blocks_of_interest: BlocksOfInterest,
@ -126,7 +130,7 @@ type SpriteSpec = sprite::sprite_kind::PureCases<Option<SpriteConfig<String>>>;
/// Function executed by worker threads dedicated to chunk meshing.
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587
fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug>(
fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug + 'static>(
pos: Vec2<i32>,
z_bounds: (f32, f32),
started_tick: u64,
@ -139,7 +143,7 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug>(
) -> MeshWorkerResponse {
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, light_map, glow_map)) =
volume.generate_mesh((range, Vec2::new(max_texture_size, max_texture_size), &blocks_of_interest));
MeshWorkerResponse {
pos,
@ -190,6 +194,8 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug>(
cfg.wind_sway,
rel_pos,
ori,
light_map(wpos),
glow_map(wpos),
);
instances.entry(key).or_insert(Vec::new()).push(instance);
@ -200,6 +206,8 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug>(
instances
},
light_map,
glow_map,
blocks_of_interest,
started_tick,
}
@ -213,7 +221,7 @@ struct SpriteData {
offset: Vec3<f32>,
}
pub struct Terrain<V: RectRasterableVol> {
pub struct Terrain<V: RectRasterableVol = TerrainChunk> {
atlas: AtlasAllocator,
sprite_config: Arc<SpriteSpec>,
chunks: HashMap<Vec2<i32>, TerrainChunkData>,
@ -462,6 +470,18 @@ impl<V: RectRasterableVol> Terrain<V> {
}
}
/// Find the light level (sunlight) at the given world position.
pub fn light_at_wpos(&self, wpos: Vec3<i32>) -> f32 {
let chunk_pos = Vec2::from(wpos).map2(TerrainChunk::RECT_SIZE, |e: i32, sz| e.div_euclid(sz as i32));
self.chunks.get(&chunk_pos).map(|c| (c.light_map)(wpos)).unwrap_or(1.0)
}
/// Find the glow level (light from lamps) at the given world position.
pub fn glow_at_wpos(&self, wpos: Vec3<i32>) -> f32 {
let chunk_pos = Vec2::from(wpos).map2(TerrainChunk::RECT_SIZE, |e: i32, sz| e.div_euclid(sz as i32));
self.chunks.get(&chunk_pos).map(|c| (c.glow_map)(wpos)).unwrap_or(0.0)
}
/// Maintain terrain data. To be called once per tick.
#[allow(clippy::for_loops_over_fallibles)] // TODO: Pending review in #587
#[allow(clippy::len_zero)] // TODO: Pending review in #587
@ -732,6 +752,8 @@ impl<V: RectRasterableVol> Terrain<V> {
None
},
col_lights: allocation.id,
light_map: response.light_map,
glow_map: response.glow_map,
sprite_instances: response
.sprite_instances
.into_iter()