Fix light animations so they are removed when the light turns off.

This commit is contained in:
Joshua Yanovski 2020-07-30 13:22:42 +02:00
parent 7e0f4bcbf0
commit ba54307540
5 changed files with 51 additions and 14 deletions

View File

@ -170,6 +170,7 @@ widget_ids! {
time, time,
entity_count, entity_count,
num_chunks, num_chunks,
num_lights,
num_figures, num_figures,
// Game Version // Game Version
@ -235,6 +236,7 @@ pub struct DebugInfo {
pub velocity: Option<comp::Vel>, pub velocity: Option<comp::Vel>,
pub ori: Option<comp::Ori>, pub ori: Option<comp::Ori>,
pub num_chunks: u32, pub num_chunks: u32,
pub num_lights: u32,
pub num_visible_chunks: u32, pub num_visible_chunks: u32,
pub num_shadow_chunks: u32, pub num_shadow_chunks: u32,
pub num_figures: u32, pub num_figures: u32,
@ -1404,13 +1406,21 @@ impl Hud {
.font_size(self.fonts.cyri.scale(14)) .font_size(self.fonts.cyri.scale(14))
.set(self.ids.num_chunks, ui_widgets); .set(self.ids.num_chunks, ui_widgets);
// Number of lights
Text::new(&format!("Lights: {}", debug_info.num_lights,))
.color(TEXT_COLOR)
.down_from(self.ids.num_chunks, 5.0)
.font_id(self.fonts.cyri.conrod_id)
.font_size(self.fonts.cyri.scale(14))
.set(self.ids.num_lights, ui_widgets);
// Number of figures // Number of figures
Text::new(&format!( Text::new(&format!(
"Figures: {} ({} visible)", "Figures: {} ({} visible)",
debug_info.num_figures, debug_info.num_figures_visible, debug_info.num_figures, debug_info.num_figures_visible,
)) ))
.color(TEXT_COLOR) .color(TEXT_COLOR)
.down_from(self.ids.num_chunks, 5.0) .down_from(self.ids.num_lights, 5.0)
.font_id(self.fonts.cyri.conrod_id) .font_id(self.fonts.cyri.conrod_id)
.font_size(self.fonts.cyri.scale(14)) .font_size(self.fonts.cyri.scale(14))
.set(self.ids.num_figures, ui_widgets); .set(self.ids.num_figures, ui_widgets);

View File

@ -34,8 +34,12 @@ impl<T: Copy + gfx::traits::Pod> Consts<T> {
vals: &[T], vals: &[T],
offset: usize, offset: usize,
) -> Result<(), RenderError> { ) -> Result<(), RenderError> {
encoder if vals.len() > 0 {
.update_buffer(&self.buf, vals, offset) encoder
.map_err(RenderError::UpdateError) .update_buffer(&self.buf, vals, offset)
.map_err(RenderError::UpdateError)
} else {
Ok(())
}
} }
} }

View File

@ -41,7 +41,7 @@ use core::{
}; };
use guillotiere::AtlasAllocator; use guillotiere::AtlasAllocator;
use hashbrown::HashMap; use hashbrown::HashMap;
use specs::{Entity as EcsEntity, Join, WorldExt}; use specs::{Entity as EcsEntity, Join, LazyUpdate, WorldExt};
use treeculler::{BVol, BoundingSphere}; use treeculler::{BVol, BoundingSphere};
use vek::*; use vek::*;
@ -365,6 +365,7 @@ impl FigureMgr {
} }
} }
let dt = ecs.fetch::<DeltaTime>().0; let dt = ecs.fetch::<DeltaTime>().0;
let updater = ecs.read_resource::<LazyUpdate>();
for (entity, waypoint, light_emitter_opt, light_anim) in ( for (entity, waypoint, light_emitter_opt, light_anim) in (
&ecs.entities(), &ecs.entities(),
ecs.read_storage::<common::comp::Waypoint>().maybe(), ecs.read_storage::<common::comp::Waypoint>().maybe(),
@ -377,7 +378,7 @@ impl FigureMgr {
if let Some(emitter) = light_emitter_opt { if let Some(emitter) = light_emitter_opt {
( (
emitter.col, emitter.col,
if emitter.strength.is_finite() { if emitter.strength.is_normal() {
emitter.strength emitter.strength
} else { } else {
0.0 0.0
@ -394,7 +395,7 @@ impl FigureMgr {
if let Some(state) = self.states.character_states.get(&entity) { if let Some(state) = self.states.character_states.get(&entity) {
light_anim.offset = state.lantern_offset; light_anim.offset = state.lantern_offset;
} }
if !light_anim.strength.is_finite() { if !light_anim.strength.is_normal() {
light_anim.strength = 0.0; light_anim.strength = 0.0;
} }
if animated { if animated {
@ -408,6 +409,18 @@ impl FigureMgr {
light_anim.strength = target_strength; light_anim.strength = target_strength;
light_anim.col = target_col; light_anim.col = target_col;
} }
// NOTE: We add `LIGHT_EPSILON` because if we wait for numbers to become
// equal to target (or even within a subnormal), it will take a minimum
// of 30 seconds for a light to fully turn off (for initial
// strength ≥ 1), which prevents optimizations (particularly those that
// can kick in with zero lights).
const LIGHT_EPSILON: f32 = 0.0001;
if (light_anim.strength - target_strength).abs() < LIGHT_EPSILON {
light_anim.strength = target_strength;
if light_anim.strength == 0.0 {
updater.remove::<LightAnimation>(entity);
}
}
} }
} }

View File

@ -304,6 +304,9 @@ impl Scene {
/// Get a reference to the scene's terrain. /// Get a reference to the scene's terrain.
pub fn terrain(&self) -> &Terrain<TerrainChunk> { &self.terrain } pub fn terrain(&self) -> &Terrain<TerrainChunk> { &self.terrain }
/// Get a reference to the scene's lights.
pub fn lights(&self) -> &Vec<Light> { &self.light_data }
/// Get a reference to the scene's figure manager. /// Get a reference to the scene's figure manager.
pub fn figure_mgr(&self) -> &FigureMgr { &self.figure_mgr } pub fn figure_mgr(&self) -> &FigureMgr { &self.figure_mgr }
@ -466,9 +469,11 @@ impl Scene {
.read_storage::<comp::LightAnimation>(), .read_storage::<comp::LightAnimation>(),
) )
.join() .join()
.filter(|(pos, _, _, _)| { .filter(|(pos, _, _, light_anim)| {
(pos.0.distance_squared(player_pos) as f32) light_anim.col != Rgb::zero()
< loaded_distance.powf(2.0) + LIGHT_DIST_RADIUS && light_anim.strength > 0.0
&& (pos.0.distance_squared(player_pos) as f32)
< loaded_distance.powf(2.0) + LIGHT_DIST_RADIUS
}) })
.map(|(pos, ori, interpolated, light_anim)| { .map(|(pos, ori, interpolated, light_anim)| {
// Use interpolated values if they are available // Use interpolated values if they are available
@ -1435,8 +1440,10 @@ impl Scene {
// would instead have this as an extension. // would instead have this as an extension.
if renderer.render_mode().shadow.is_map() && (is_daylight || self.light_data.len() > 0) { if renderer.render_mode().shadow.is_map() && (is_daylight || self.light_data.len() > 0) {
// Set up shadow mapping. if is_daylight {
renderer.start_shadows(); // Set up shadow mapping.
renderer.start_shadows();
}
// Render terrain shadows. // Render terrain shadows.
self.terrain.render_shadows( self.terrain.render_shadows(
@ -1462,8 +1469,10 @@ impl Scene {
scene_data.figure_lod_render_distance, scene_data.figure_lod_render_distance,
); );
// Flush shadows. if is_daylight {
renderer.flush_shadows(); // Flush shadows.
renderer.flush_shadows();
}
} }
let lod = self.lod.get_data(); let lod = self.lod.get_data();

View File

@ -697,6 +697,7 @@ impl PlayState for SessionState {
.get(self.client.borrow().entity()) .get(self.client.borrow().entity())
.cloned(), .cloned(),
num_chunks: self.scene.terrain().chunk_count() as u32, num_chunks: self.scene.terrain().chunk_count() as u32,
num_lights: self.scene.lights().len() as u32,
num_visible_chunks: self.scene.terrain().visible_chunk_count() as u32, num_visible_chunks: self.scene.terrain().visible_chunk_count() as u32,
num_shadow_chunks: self.scene.terrain().shadow_chunk_count() as u32, num_shadow_chunks: self.scene.terrain().shadow_chunk_count() as u32,
num_figures: self.scene.figure_mgr().figure_count() as u32, num_figures: self.scene.figure_mgr().figure_count() as u32,