1
0
mirror of https://github.com/beestat/app.git synced 2026-02-26 05:00:21 -05:00
This commit is contained in:
Jon Ziebell 2026-02-22 14:13:53 -05:00
parent 2351447e9b
commit 6e8fc47a15
6 changed files with 326 additions and 18 deletions

View File

@ -9,6 +9,8 @@ beestat.weather = {};
* `icon_color`: UI accent color for the weather icon.
* `cloud_density`: Controls cloud particle count/intensity in the scene.
* `cloud_darkness`: Controls cloud shading/dimming (0 clear -> 2 very dark).
* `fog_density`: Controls low-altitude volumetric fog cloud density.
* `fog_color`: Hex color used to tint low-altitude fog volumes.
* `rain_density`: Controls rain particle count/intensity.
* `snow_density`: Controls snow particle count/intensity and snow-cover blend.
* `lightning_frequency`: Controls frequency/intensity of lightning effects.
@ -221,6 +223,8 @@ beestat.weather.settings_ = {
'icon_color': beestat.style.color.gray.base,
'cloud_density': 0.6,
'cloud_darkness': 0.2,
'fog_density': 1.2,
'fog_color': '#d6dde8',
'rain_density': 0,
'snow_density': 0,
'lightning_frequency': 0,
@ -232,6 +236,8 @@ beestat.weather.settings_ = {
'icon_color': beestat.style.color.gray.base,
'cloud_density': 0.45,
'cloud_darkness': 0.35,
'fog_density': 0.8,
'fog_color': '#d9d4c8',
'rain_density': 0,
'snow_density': 0,
'lightning_frequency': 0,
@ -243,6 +249,8 @@ beestat.weather.settings_ = {
'icon_color': beestat.style.color.gray.base,
'cloud_density': 0.45,
'cloud_darkness': 0.35,
'fog_density': 1.05,
'fog_color': '#cbc7c3',
'rain_density': 0,
'snow_density': 0,
'lightning_frequency': 0,
@ -254,6 +262,8 @@ beestat.weather.settings_ = {
'icon_color': beestat.style.color.gray.base,
'cloud_density': 0.45,
'cloud_darkness': 0.35,
'fog_density': 0.95,
'fog_color': '#d9c7a8',
'rain_density': 0,
'snow_density': 0,
'lightning_frequency': 0,
@ -271,6 +281,8 @@ beestat.weather.default_settings_ = {
'icon_color': beestat.style.color.gray.base,
'cloud_density': 0.03,
'cloud_darkness': 0,
'fog_density': 0,
'fog_color': '#d6dde8',
'rain_density': 0,
'snow_density': 0,
'lightning_frequency': 0,
@ -337,6 +349,37 @@ beestat.weather.get_cloud_darkness = function(condition) {
return beestat.weather.get_settings_(condition).cloud_darkness;
};
/**
* Get fog density for a condition.
* Higher values increase low-altitude volumetric fog presence.
*
* @param {string} condition
*
* @return {number}
*/
beestat.weather.get_fog_density = function(condition) {
const fog_density = beestat.weather.get_settings_(condition).fog_density;
if (fog_density !== undefined) {
return fog_density;
}
return beestat.weather.default_settings_.fog_density;
};
/**
* Get fog color tint for a condition.
*
* @param {string} condition
*
* @return {string}
*/
beestat.weather.get_fog_color = function(condition) {
const fog_color = beestat.weather.get_settings_(condition).fog_color;
if (typeof fog_color === 'string' && fog_color.length > 0) {
return fog_color;
}
return beestat.weather.default_settings_.fog_color;
};
/**
* Get rain density for a condition.
* Higher values increase rain particle count and rainfall intensity.

View File

@ -76,7 +76,7 @@ beestat.component.card.three_d = function() {
if (self.get_weather_() !== 'auto') {
return;
}
self.apply_weather_setting_to_scene_();
self.apply_weather_setting_to_scene_(false);
self.decorate_toolbar_();
};
beestat.dispatcher.addEventListener('cache.thermostat', this.handle_thermostat_cache_change_);
@ -112,6 +112,15 @@ beestat.component.card.three_d.rerender_delay_scene_setting_ms = 1000;
*/
beestat.component.card.three_d.rerender_loading_min_visible_ms = 350;
/**
* Debug-only weather override.
* Set to `null` to use the scene-selected weather mode.
* Set to a weather condition string (e.g. `fog`, `rain`) to force it.
*
* @type {?string}
*/
beestat.component.card.three_d.debug_weather_override = null;
/**
* Scene setting keys that require a full rerender.
*
@ -666,6 +675,26 @@ beestat.component.card.three_d.prototype.get_auto_weather_from_thermostat_ = fun
return beestat.weather.get_settings_(thermostat?.weather?.condition).condition;
};
/**
* Get a normalized debug weather override condition.
*
* @return {?string}
*/
beestat.component.card.three_d.prototype.get_debug_weather_override_condition_ = function() {
const override = beestat.component.card.three_d.debug_weather_override;
if (typeof override !== 'string') {
return null;
}
const normalized_override = override.trim().toLowerCase();
if (normalized_override.length === 0) {
return null;
}
if (normalized_override === 'auto') {
return this.get_auto_weather_from_thermostat_();
}
return beestat.weather.get_settings_(normalized_override).condition;
};
/**
* Resolve selected weather mode into a weather condition.
*
@ -674,6 +703,10 @@ beestat.component.card.three_d.prototype.get_auto_weather_from_thermostat_ = fun
* @return {string}
*/
beestat.component.card.three_d.prototype.get_weather_condition_from_mode_ = function(weather) {
const debug_override_condition = this.get_debug_weather_override_condition_();
if (debug_override_condition !== null) {
return debug_override_condition;
}
if (weather === 'auto') {
return this.get_auto_weather_from_thermostat_();
}
@ -798,6 +831,8 @@ beestat.component.card.three_d.prototype.set_show_group_ = function(group_id, vi
* @return {{
* cloud_density: number,
* cloud_darkness: number,
* fog_density: number,
* fog_color: string,
* rain_density: number,
* snow_density: number,
* lightning_frequency: number,
@ -809,6 +844,8 @@ beestat.component.card.three_d.prototype.get_weather_settings_from_weather_ = fu
return {
'cloud_density': beestat.weather.get_cloud_density(condition),
'cloud_darkness': beestat.weather.get_cloud_darkness(condition),
'fog_density': beestat.weather.get_fog_density(condition),
'fog_color': beestat.weather.get_fog_color(condition),
'rain_density': beestat.weather.get_rain_density(condition),
'snow_density': beestat.weather.get_snow_density(condition),
'lightning_frequency': beestat.weather.get_lightning_frequency(condition),
@ -818,8 +855,10 @@ beestat.component.card.three_d.prototype.get_weather_settings_from_weather_ = fu
/**
* Apply current weather settings to the scene.
*
* @param {boolean=} opt_persist Persist weather settings to floor-plan scene data.
*/
beestat.component.card.three_d.prototype.apply_weather_setting_to_scene_ = function() {
beestat.component.card.three_d.prototype.apply_weather_setting_to_scene_ = function(opt_persist) {
if (this.scene_ === undefined) {
return;
}
@ -827,6 +866,18 @@ beestat.component.card.three_d.prototype.apply_weather_setting_to_scene_ = funct
this.ensure_scene_settings_values_();
const weather_settings = this.get_weather_settings_from_weather_(this.get_weather_());
Object.assign(this.scene_settings_values_, weather_settings);
const persist = opt_persist === true;
if (persist === true) {
const scene_visualize = this.get_scene_visualize_state_();
if (scene_visualize !== null) {
const previous_settings_json = JSON.stringify(scene_visualize.settings || {});
Object.assign(scene_visualize.settings, weather_settings);
const next_settings_json = JSON.stringify(scene_visualize.settings);
if (previous_settings_json !== next_settings_json) {
this.save_scene_visualize_state_();
}
}
}
this.scene_.set_scene_settings(weather_settings, {
'rerender': false
});
@ -871,10 +922,6 @@ beestat.component.card.three_d.prototype.ensure_scene_settings_values_ = functio
this.save_scene_visualize_state_();
}
}
Object.assign(
this.scene_settings_values_,
this.get_weather_settings_from_weather_(this.get_weather_())
);
};
/**
@ -1205,6 +1252,7 @@ beestat.component.card.three_d.prototype.decorate_scene_settings_panel_ = functi
add_section_title('Weather');
add_number_setting(get_title_case_label('cloud_density'), 'cloud_density', 0, 2, 0.1);
add_number_setting(get_title_case_label('cloud_darkness'), 'cloud_darkness', 0, 2, 0.1);
add_number_setting(get_title_case_label('fog_density'), 'fog_density', 0, 2, 0.1);
add_number_setting(get_title_case_label('rain_density'), 'rain_density', 0, 2, 0.1);
add_number_setting(get_title_case_label('snow_density'), 'snow_density', 0, 2, 0.1);
add_number_setting(get_title_case_label('lightning_frequency'), 'lightning_frequency', 0, 2, 0.1);
@ -1960,7 +2008,7 @@ beestat.component.card.three_d.prototype.decorate_toolbar_ = function(parent) {
tile.addEventListener('click', (e) => {
e.stopPropagation();
this.set_weather_(mode.value);
this.apply_weather_setting_to_scene_();
this.apply_weather_setting_to_scene_(true);
this.weather_menu_open_ = false;
this.decorate_toolbar_();
});
@ -1981,7 +2029,7 @@ beestat.component.card.three_d.prototype.decorate_toolbar_ = function(parent) {
auto_tile.addEventListener('click', (e) => {
e.stopPropagation();
this.set_weather_('auto');
this.apply_weather_setting_to_scene_();
this.apply_weather_setting_to_scene_(true);
this.weather_menu_open_ = false;
this.decorate_toolbar_();
});

View File

@ -90,6 +90,13 @@ beestat.component.scene.weather_snow_max_count = 1500;
*/
beestat.component.scene.weather_cloud_max_count = 140;
/**
* Maximum low-altitude fog volume sprite count at full fog intensity.
*
* @type {number}
*/
beestat.component.scene.weather_fog_max_count = 18;
/**
* Time in seconds for weather effects to fully transition to a new mode.
*
@ -222,16 +229,18 @@ beestat.component.scene.sidereal_day_seconds = 86164.0905;
beestat.component.scene.star_drift_visual_factor = 0.12;
/**
* Runtime scene settings exposed through the scene settings panel.
* Runtime scene settings used by environment rendering.
*
* @type {{
* cloud_density: number,
* cloud_darkness: number,
* fog_density: number,
* rain_density: number,
* snow_density: number,
* lightning_frequency: number,
* wind_speed: number,
* wind_direction: number,
* fog_color: string,
* tree_wobble: boolean,
* tree_enabled: boolean,
* star_density: number,
@ -243,11 +252,13 @@ beestat.component.scene.star_drift_visual_factor = 0.12;
beestat.component.scene.default_settings = {
'cloud_density': 1,
'cloud_darkness': 0,
'fog_density': 0,
'rain_density': 1,
'snow_density': 1,
'lightning_frequency': 0,
'wind_speed': 0.4,
'wind_direction': 0,
'fog_color': '#d6dde8',
'tree_wobble': true,
'tree_enabled': true,
'star_density': 1,
@ -465,6 +476,11 @@ beestat.component.scene.prototype.reset_runtime_scene_references_for_rerender_ =
delete this.snow_particles_;
delete this.cloud_sprites_;
delete this.cloud_motion_;
delete this.fog_sprites_;
delete this.fog_motion_;
delete this.fog_bounds_;
delete this.current_fog_count_;
delete this.current_fog_density_;
delete this.weather_profile_target_;
delete this.weather_transition_start_profile_;
delete this.lightning_flash_light_;
@ -1346,6 +1362,9 @@ beestat.component.scene.prototype.dispose = function() {
if (this.cloud_texture_ !== undefined) {
this.cloud_texture_.dispose();
}
if (this.fog_volume_texture_ !== undefined) {
this.fog_volume_texture_.dispose();
}
if (this.moon_phase_texture_ !== undefined) {
this.moon_phase_texture_.dispose();
}

View File

@ -210,7 +210,8 @@ beestat.component.scene.prototype.add_environment_ = function() {
if (index === 0) {
mesh.userData.is_ground = true;
}
mesh.receiveShadow = true;
mesh.castShadow = true;
mesh.receiveShadow = index === 0;
this.environment_group_.add(mesh);
current_z += stratum.thickness;

View File

@ -251,6 +251,49 @@ beestat.component.scene.prototype.create_cloud_texture_ = function() {
};
/**
* Create a broad soft texture used for low-altitude fog volume sprites.
*
* @return {THREE.Texture}
*/
beestat.component.scene.prototype.create_fog_volume_texture_ = function() {
const size = 320;
const canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
const context = canvas.getContext('2d');
const lobes = [
{'x': 0.26, 'y': 0.56, 'r': 0.27, 'alpha': 0.5},
{'x': 0.46, 'y': 0.5, 'r': 0.3, 'alpha': 0.6},
{'x': 0.66, 'y': 0.57, 'r': 0.28, 'alpha': 0.54},
{'x': 0.52, 'y': 0.67, 'r': 0.31, 'alpha': 0.42}
];
lobes.forEach(function(lobe) {
const gradient = context.createRadialGradient(
size * lobe.x,
size * lobe.y,
0,
size * lobe.x,
size * lobe.y,
size * lobe.r
);
gradient.addColorStop(0.0, `rgba(255,255,255,${lobe.alpha})`);
gradient.addColorStop(0.55, `rgba(245,249,255,${lobe.alpha * 0.5})`);
gradient.addColorStop(1.0, 'rgba(245,249,255,0.0)');
context.fillStyle = gradient;
context.beginPath();
context.arc(size * lobe.x, size * lobe.y, size * lobe.r, 0, Math.PI * 2);
context.fill();
});
const texture = new THREE.CanvasTexture(canvas);
texture.needsUpdate = true;
return texture;
};
/**
* Draw the moon phase into the reusable moon canvas texture.
*

View File

@ -18,6 +18,8 @@ beestat.component.scene.prototype.get_weather_design_count_ = function(density_k
return Math.max(1, Number(beestat.component.scene.weather_rain_max_count || 1));
case 'snow_density':
return Math.max(1, Number(beestat.component.scene.weather_snow_max_count || 1));
case 'fog_density':
return Math.max(1, Number(beestat.component.scene.weather_fog_max_count || 1));
default:
return 1;
}
@ -69,6 +71,9 @@ beestat.component.scene.prototype.get_weather_count_from_density_ = function(den
beestat.component.scene.prototype.get_weather_profile_ = function() {
return {
'cloud_count': this.get_weather_count_from_density_('cloud_density'),
// Fog uses fixed sprite population; density controls opacity.
'fog_count': this.get_weather_design_capacity_count_('fog_density'),
'fog_density': Math.max(0, Math.min(2, Number(this.get_scene_setting_('fog_density') || 0))),
'rain_count': this.get_weather_count_from_density_('rain_density'),
'snow_count': this.get_weather_count_from_density_('snow_density')
};
@ -113,6 +118,22 @@ beestat.component.scene.prototype.get_cloud_color_ = function() {
return base_color.lerp(dark_gray_color, blend);
};
/**
* Get low-altitude fog volume sprite tint color.
*
* @return {THREE.Color}
*/
beestat.component.scene.prototype.get_fog_color_ = function() {
const fog_color = this.get_scene_setting_('fog_color');
if (
typeof fog_color === 'string' ||
typeof fog_color === 'number'
) {
return new THREE.Color(fog_color);
}
return new THREE.Color(beestat.component.scene.default_settings.fog_color);
};
/**
* Update weather transition targets based on appearance weather.
@ -122,6 +143,8 @@ beestat.component.scene.prototype.update_weather_targets_ = function() {
this.weather_transition_start_profile_ = {
'cloud_count': this.current_cloud_count_ === undefined ? 0 : this.current_cloud_count_,
'fog_count': this.current_fog_count_ === undefined ? 0 : this.current_fog_count_,
'fog_density': this.current_fog_density_ === undefined ? 0 : this.current_fog_density_,
'rain_count': this.current_rain_count_ === undefined ? 0 : this.current_rain_count_,
'snow_count': this.current_snow_count_ === undefined ? 0 : this.current_snow_count_
};
@ -130,7 +153,7 @@ beestat.component.scene.prototype.update_weather_targets_ = function() {
/**
* Get current snow cover blend amount (0-1) from precipitation transition.
* Get current snow cover blend amount (0-2) from precipitation transition.
*
* @return {number}
*/
@ -146,7 +169,7 @@ beestat.component.scene.prototype.get_snow_cover_blend_ = function() {
return Math.max(
0,
Math.min(
1,
2,
this.current_snow_count_ / configured_snow_count
)
);
@ -165,14 +188,16 @@ beestat.component.scene.prototype.update_snow_surface_colors_ = function(snow_bl
// Keep a small amount of base color visible at peak snow for definition.
const normalized_blend = Math.max(0, Math.min(1, snow_blend));
const grass_normalized_blend = Math.max(0, Math.min(1, snow_blend * 0.5));
const blend = normalized_blend * 0.9;
const grass_blend = grass_normalized_blend * 0.9;
const foliage_blend = normalized_blend * 0.75;
const snow_color = new THREE.Color(beestat.component.scene.snow_surface_color);
const base_roof_color = new THREE.Color(this.get_appearance_value_('roof_color'));
const base_ground_color = new THREE.Color(this.get_appearance_value_('ground_color'));
const roof_color = base_roof_color.clone().lerp(snow_color, blend);
const ground_color = base_ground_color.clone().lerp(snow_color, blend);
const ground_color = base_ground_color.clone().lerp(snow_color, grass_blend);
if (this.layers_.roof !== undefined) {
this.layers_.roof.traverse(function(object) {
@ -287,7 +312,8 @@ beestat.component.scene.prototype.create_precipitation_system_ = function(bounds
'static_opacity': config.static_opacity === true,
'max_wind_angle': config.max_wind_angle || 0,
'max_wind_speed_scale': config.max_wind_speed_scale || 2,
'wind_motion_multiplier': config.wind_motion_multiplier || 1
'wind_motion_multiplier': config.wind_motion_multiplier || 1,
'wind_speed_curve': config.wind_speed_curve || 'linear'
};
};
@ -357,13 +383,21 @@ beestat.component.scene.prototype.update_precipitation_system_ = function(
);
const wind_speed_scale = 1 + ((clamped_wind_speed / 2) * (max_wind_speed_scale - 1));
const wind_motion_multiplier = Math.max(0, Number(precipitation.wind_motion_multiplier || 1));
const wind_speed_curve_scale = precipitation.wind_speed_curve === 'half_same_double'
? Math.pow(2, clamped_wind_speed - 1)
: 1;
const direction_velocity_x = horizontal_scale * wind_x;
const direction_velocity_y = horizontal_scale * wind_y;
const direction_velocity_z = vertical_scale;
for (let i = 0; i < clamped_count; i++) {
const offset = i * 3;
const speed = precipitation.speeds[i] * delta_seconds * wind_speed_scale * wind_motion_multiplier;
const speed =
precipitation.speeds[i] *
delta_seconds *
wind_speed_scale *
wind_motion_multiplier *
wind_speed_curve_scale;
positions[offset + 2] += speed * direction_velocity_z;
positions[offset] += speed * direction_velocity_x;
positions[offset + 1] += speed * direction_velocity_y;
@ -688,6 +722,9 @@ beestat.component.scene.prototype.add_weather_ = function(center_x, center_y, pl
if (this.cloud_texture_ === undefined) {
this.cloud_texture_ = this.create_cloud_texture_();
}
if (this.fog_volume_texture_ === undefined) {
this.fog_volume_texture_ = this.create_fog_volume_texture_();
}
if (this.snow_particle_texture_ === undefined) {
this.snow_particle_texture_ = this.create_snow_particle_texture_();
@ -761,6 +798,65 @@ beestat.component.scene.prototype.add_weather_ = function(center_x, center_y, pl
});
}
const fog_capacity = this.get_weather_design_capacity_count_('fog_density', this.weather_area_);
const fog_bounds = {
'min_x': bounds.min_x - 140,
'max_x': bounds.max_x + 140,
'min_y': bounds.min_y - 140,
'max_y': bounds.max_y + 140,
// Keep fog cards well above the ground plane to avoid seam artifacts.
'min_z': -420,
'max_z': -120
};
this.fog_bounds_ = fog_bounds;
this.fog_sprites_ = [];
this.fog_motion_ = [];
// Pre-build low-altitude volumetric fog sprites.
for (let i = 0; i < fog_capacity; i++) {
const fog_material = new THREE.SpriteMaterial({
'map': this.fog_volume_texture_,
'color': 0xd6dde8,
'transparent': true,
'opacity': 0,
'depthWrite': false,
'depthTest': true
});
const fog = new THREE.Sprite(fog_material);
fog.position.set(
fog_bounds.min_x + Math.random() * (fog_bounds.max_x - fog_bounds.min_x),
fog_bounds.min_y + Math.random() * (fog_bounds.max_y - fog_bounds.min_y),
fog_bounds.min_z + Math.random() * (fog_bounds.max_z - fog_bounds.min_z)
);
const fog_size = 680 + Math.random() * 980;
fog.scale.set(fog_size * 1.7, fog_size * 0.45, 1);
fog.layers.set(beestat.component.scene.layer_visible);
fog.userData.is_environment = true;
this.weather_group_.add(fog);
this.fog_sprites_.push(fog);
this.fog_motion_.push({
'base_x': fog.position.x,
'base_y': fog.position.y,
'base_z': fog.position.z,
'base_scale_x': fog.scale.x,
'base_scale_y': fog.scale.y,
'base_opacity': 0.34 + (Math.random() * 0.12),
'phase': Math.random() * Math.PI * 2,
'pulse_speed': 0.12 + (Math.random() * 0.1),
'scale_wobble_x': 0.03 + (Math.random() * 0.02),
'scale_wobble_y': 0.02 + (Math.random() * 0.02),
'opacity_wobble': 0.04 + (Math.random() * 0.03),
'wiggle_x': 18 + (Math.random() * 26),
'wiggle_y': 16 + (Math.random() * 24),
'wiggle_z': 4 + (Math.random() * 8),
'wiggle_freq_x': 0.55 + (Math.random() * 0.4),
'wiggle_freq_y': 0.45 + (Math.random() * 0.35),
'wiggle_freq_z': 0.35 + (Math.random() * 0.3)
});
}
// Build precipitation systems (rain and snow) at design-capacity scale.
this.rain_particles_ = this.create_precipitation_system_(
bounds,
@ -773,8 +869,8 @@ beestat.component.scene.prototype.add_weather_ = function(center_x, center_y, pl
'color': 0xa8c7ff,
'opacity': 0.5,
'static_opacity': true,
'speed_min': 280,
'speed_max': 430,
'speed_min': 560,
'speed_max': 860,
'drift': 28,
'texture': this.rain_particle_texture_,
'max_wind_angle': 45,
@ -799,7 +895,8 @@ beestat.component.scene.prototype.add_weather_ = function(center_x, center_y, pl
'texture': this.snow_particle_texture_,
'max_wind_angle': 75,
'max_wind_speed_scale': 3,
'wind_motion_multiplier': 2.5
'wind_motion_multiplier': 2.5,
'wind_speed_curve': 'half_same_double'
}
);
this.weather_group_.add(this.snow_particles_.points);
@ -816,6 +913,8 @@ beestat.component.scene.prototype.add_weather_ = function(center_x, center_y, pl
const initial_weather_profile = this.get_weather_profile_();
this.weather_profile_target_ = initial_weather_profile;
this.current_cloud_count_ = initial_weather_profile.cloud_count;
this.current_fog_count_ = initial_weather_profile.fog_count;
this.current_fog_density_ = initial_weather_profile.fog_density;
this.current_rain_count_ = initial_weather_profile.rain_count;
this.current_snow_count_ = initial_weather_profile.snow_count;
this.update_weather_targets_();
@ -852,6 +951,8 @@ beestat.component.scene.prototype.update_weather_ = function() {
if (this.weather_transition_start_profile_ === undefined) {
this.weather_transition_start_profile_ = {
'cloud_count': this.current_cloud_count_ === undefined ? 0 : this.current_cloud_count_,
'fog_count': this.current_fog_count_ === undefined ? 0 : this.current_fog_count_,
'fog_density': this.current_fog_density_ === undefined ? 0 : this.current_fog_density_,
'rain_count': this.current_rain_count_ === undefined ? 0 : this.current_rain_count_,
'snow_count': this.current_snow_count_ === undefined ? 0 : this.current_snow_count_
};
@ -880,6 +981,14 @@ beestat.component.scene.prototype.update_weather_ = function() {
this.weather_transition_start_profile_.cloud_count,
this.weather_profile_target_.cloud_count
);
this.current_fog_count_ = transition(
this.weather_transition_start_profile_.fog_count,
this.weather_profile_target_.fog_count
);
this.current_fog_density_ = transition(
this.weather_transition_start_profile_.fog_density,
this.weather_profile_target_.fog_density
);
this.current_rain_count_ = transition(
this.weather_transition_start_profile_.rain_count,
this.weather_profile_target_.rain_count
@ -940,6 +1049,51 @@ beestat.component.scene.prototype.update_weather_ = function() {
}
}
// Update low-altitude volumetric fog sprites.
if (this.fog_sprites_ !== undefined && this.fog_motion_ !== undefined) {
const now_seconds = now_ms / 1000;
const fog_color = this.get_fog_color_();
const fog_density = Math.max(
0,
Math.min(
1,
(this.current_fog_density_ === undefined ? 0 : this.current_fog_density_) / 2
)
);
for (let i = 0; i < this.fog_sprites_.length; i++) {
const sprite = this.fog_sprites_[i];
const motion = this.fog_motion_[i];
const phase = now_seconds * motion.pulse_speed + motion.phase;
const scale_x_wobble = 1 + (Math.sin(phase) * motion.scale_wobble_x);
const scale_y_wobble = 1 + (Math.cos(phase * 0.88) * motion.scale_wobble_y);
const fog_scale_transition = 0.62 + (0.38 * fog_density);
sprite.scale.set(
motion.base_scale_x * scale_x_wobble * fog_scale_transition,
motion.base_scale_y * scale_y_wobble * fog_scale_transition,
1
);
sprite.position.x = motion.base_x + Math.sin(phase * motion.wiggle_freq_x) * motion.wiggle_x;
sprite.position.y = motion.base_y + Math.cos(phase * motion.wiggle_freq_y) * motion.wiggle_y;
sprite.position.z = motion.base_z + Math.sin(phase * motion.wiggle_freq_z) * motion.wiggle_z;
if (sprite.material !== undefined) {
if (sprite.material.color !== undefined) {
sprite.material.color.copy(fog_color);
}
sprite.material.opacity = Math.max(
0,
Math.min(
1,
(motion.base_opacity + Math.sin(phase * 0.61) * motion.opacity_wobble) * fog_density
)
);
}
}
}
// Update precipitation + lightning systems, then re-apply snow cover tinting.
this.update_precipitation_system_(
this.rain_particles_,