mirror of
https://github.com/beestat/app.git
synced 2026-02-26 05:00:21 -05:00
Cleanup
This commit is contained in:
parent
2351447e9b
commit
6e8fc47a15
@ -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.
|
||||
|
||||
@ -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_();
|
||||
});
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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.
|
||||
*
|
||||
|
||||
@ -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_,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user