mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'zesterer/better-rain' into 'master'
Better rain See merge request veloren/veloren!3464
This commit is contained in:
commit
1e3b5383cf
@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Slider for ambience volume
|
||||
- Weather generated on server is sent to clients, and seen on clients as rain/clouds.
|
||||
- Updated Brazilian Portuguese Translation
|
||||
- Lightning storms
|
||||
|
||||
### Changed
|
||||
|
||||
@ -52,7 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Changed module component modifier costs to the following scheme, based on base material: 1 -> 2 -> 5 -> 10 -> 15 -> 25
|
||||
- Damage from the same source dealt in the same tick will now be grouped up.
|
||||
- Critical hits are now shown differently in the damage numbers.
|
||||
- Fall damage and some (extra) buffs/debuffs now show up in the damage numbers.
|
||||
- Fall damage and some (extra) buffs/debuffs now show up in the damage numbers.
|
||||
- Optimized sprite processing decreasing the startup time of voxygen (and long freezes when trying
|
||||
to enter the world when this hasn't finished).
|
||||
- Metadata added to music files. Listen to the soundtrack more easily!
|
||||
@ -70,7 +71,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Fixed an error where '{amount} Exp' floater did not use existing localizations
|
||||
- Fix villagers seeing cultists and familiar enemies through objects.
|
||||
- Menacing agents are now less spammy with their menacing messages
|
||||
- Fixed the title screen FPS cap not applying when the background FPS limit was set higher than 60 FPS
|
||||
- Fixed the title screen FPS cap not applying when the background FPS limit was set higher than 60 FPS
|
||||
- Fixed an issue where the hurt animation would "jump" whenever you lost/gained health.
|
||||
- Fixed a bug where multiple damage sources in the same tick would show up as a singular attack.
|
||||
- Fixed an issue where, if the same amount of healing and damage was received in the same tick, nothing would be shown.
|
||||
|
@ -1169,5 +1169,11 @@
|
||||
],
|
||||
threshold: 1.0,
|
||||
),
|
||||
Lightning: (
|
||||
files: [
|
||||
"voxygen.audio.sfx.ambient.lightning_1",
|
||||
],
|
||||
threshold: 1.0,
|
||||
),
|
||||
}
|
||||
)
|
||||
|
BIN
assets/voxygen/audio/sfx/ambient/lightning_1.ogg
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/ambient/lightning_1.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -82,6 +82,47 @@ void main() {
|
||||
|
||||
#if (CLOUD_MODE == CLOUD_MODE_NONE)
|
||||
color.rgb = apply_point_glow(cam_pos.xyz + focus_off.xyz, dir, dist, color.rgb);
|
||||
#elif (0 == 0)
|
||||
if (medium.x == MEDIUM_AIR && rain_density > 0.001) {
|
||||
vec3 cam_wpos = cam_pos.xyz + focus_off.xyz;
|
||||
|
||||
vec3 adjusted_dir = (vec4(dir, 0) * rain_dir_mat).xyz;
|
||||
|
||||
vec2 dir2d = adjusted_dir.xy;
|
||||
vec3 rorigin = cam_pos.xyz + focus_off.xyz + 0.5;
|
||||
vec3 rpos = vec3(0.0);
|
||||
float t = 0.0;
|
||||
const float PLANCK = 0.01;
|
||||
while (true) {
|
||||
float scale = min(pow(2, ceil(t / 2.0)), 32);
|
||||
vec2 deltas = (step(vec2(0), dir2d) - fract(rpos.xy / scale + 100.0)) / dir2d;
|
||||
float jump = max(min(deltas.x, deltas.y) * scale, PLANCK);
|
||||
t += jump;
|
||||
|
||||
if (t >= 64.0) { break; }
|
||||
|
||||
rpos = rorigin + adjusted_dir * t;
|
||||
|
||||
vec2 diff = abs(round(rpos.xy) - rpos.xy);
|
||||
vec3 wall_pos = vec3((diff.x > diff.y) ? rpos.xy : rpos.yx, rpos.z + integrated_rain_vel);
|
||||
wall_pos.xz *= vec2(4, 0.3);
|
||||
wall_pos.z += hash_two(uvec2(wall_pos.xy + vec2(0, 0.5)));
|
||||
|
||||
float depth_adjust = fract(hash_two(uvec2(wall_pos.xz) + 500u));
|
||||
float wpos_dist = t - jump * depth_adjust;
|
||||
vec3 wpos = cam_pos.xyz + dir * wpos_dist;
|
||||
|
||||
if (wpos_dist > dist) { break; }
|
||||
if (length((fract(wall_pos.xz) - 0.5)) < 0.1 + pow(max(0.0, wpos_dist - (dist - 0.25)) / 0.25, 4.0) * 0.2) {
|
||||
float density = rain_density * rain_occlusion_at(wpos);
|
||||
if (fract(hash_two(uvec2(wall_pos.xz) + 1000u)) >= density) { continue; }
|
||||
|
||||
float alpha = 0.5 * clamp((wpos_dist - 1.0) * 0.5, 0.0, 1.0);
|
||||
float light = dot(color.rgb, vec3(1)) + 0.05 + (get_sun_brightness() + get_moon_brightness()) * 0.2;
|
||||
color.rgb = mix(color.rgb, vec3(0.3, 0.35, 0.5) * light, alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
vec3 old_color = color.rgb;
|
||||
|
||||
@ -92,17 +133,17 @@ void main() {
|
||||
float z = (-1 / (abs(adjusted_dir.z) - 1) - 1) * sign(adjusted_dir.z);
|
||||
// normalize xy to get a 2d direction
|
||||
vec2 dir_2d = normalize(adjusted_dir.xy);
|
||||
// sort of map cylinder around the camera to 2d grid
|
||||
// sort of map cylinder around the camera to 2d grid
|
||||
vec2 view_pos = vec2(atan2(dir_2d.x, dir_2d.y), z);
|
||||
|
||||
// compute camera position in the world
|
||||
vec3 cam_wpos = cam_pos.xyz + focus_off.xyz;
|
||||
|
||||
// Rain density is now only based on the cameras current position.
|
||||
|
||||
// Rain density is now only based on the cameras current position.
|
||||
// This could be affected by a setting where rain_density_at is instead
|
||||
// called each iteration of the loop. With the current implementation
|
||||
// of rain_dir this has issues with being in a place where it doesn't rain
|
||||
// and seeing rain.
|
||||
// and seeing rain.
|
||||
float rain_density = rain_density * 1.0;
|
||||
if (medium.x == MEDIUM_AIR && rain_density > 0.0) {
|
||||
float rain_dist = 50.0;
|
||||
@ -130,7 +171,7 @@ void main() {
|
||||
);
|
||||
|
||||
float dist_to_rain = drop_depth / length(dir.xy);
|
||||
vec3 rpos = dir * dist_to_rain;
|
||||
vec3 rpos = dir * dist_to_rain;
|
||||
if (dist < dist_to_rain || cam_wpos.z + rpos.z > CLOUD_AVG_ALT) {
|
||||
continue;
|
||||
}
|
||||
|
@ -164,6 +164,17 @@ void main() {
|
||||
vec3 surf_color = /*srgb_to_linear*/f_col;
|
||||
float alpha = 1.0;
|
||||
const float n2 = 1.5;
|
||||
|
||||
|
||||
// This is a silly hack. It's not true reflectance (see below for that), but gives the desired
|
||||
// effect without breaking the entire lighting model until we come up with a better way of doing
|
||||
// reflectivity that accounts for physical surroundings like the ground
|
||||
if ((material & (1u << 1u)) > 0u) {
|
||||
vec3 reflect_ray_dir = reflect(cam_to_frag, f_norm);
|
||||
surf_color *= dot(vec3(1.0) - abs(fract(reflect_ray_dir * 1.5) * 2.0 - 1.0) * 0.85, vec3(1));
|
||||
alpha = 0.1;
|
||||
}
|
||||
|
||||
const float R_s2s0 = pow((1.0 - n2) / (1.0 + n2), 2);
|
||||
const float R_s1s0 = pow((1.3325 - n2) / (1.3325 + n2), 2);
|
||||
const float R_s2s1 = pow((1.0 - 1.3325) / (1.0 + 1.3325), 2);
|
||||
@ -174,14 +185,6 @@ void main() {
|
||||
vec3 k_d = vec3(1.0);
|
||||
vec3 k_s = vec3(R_s);
|
||||
|
||||
// This is a silly hack. It's not true reflectance (see below for that), but gives the desired
|
||||
// effect without breaking the entire lighting model until we come up with a better way of doing
|
||||
// reflectivity that accounts for physical surroundings like the ground
|
||||
if ((material & (1u << 1u)) > 0u) {
|
||||
vec3 reflect_ray_dir = reflect(cam_to_frag, f_norm);
|
||||
surf_color *= dot(vec3(1.0) - abs(fract(reflect_ray_dir * 1.5) * 2.0 - 1.0) * 0.85, vec3(1));
|
||||
}
|
||||
|
||||
vec3 emitted_light, reflected_light;
|
||||
|
||||
// Make voxel shadows block the sun and moon
|
||||
|
@ -242,7 +242,7 @@ vec3 get_cloud_color(vec3 surf_color, vec3 dir, vec3 origin, const float time_of
|
||||
int i;
|
||||
|
||||
#if (CLOUD_MODE >= CLOUD_MODE_MEDIUM)
|
||||
#ifdef EXPERIMENTAL_RAINBOWS
|
||||
#ifndef EXPERIMENTAL_NORAINBOWS
|
||||
// TODO: Make it a double rainbow
|
||||
float rainbow_t = (0.7 - dot(sun_dir.xyz, dir)) * 8 / 0.05;
|
||||
int rainbow_c = int(floor(rainbow_t));
|
||||
@ -285,7 +285,7 @@ vec3 get_cloud_color(vec3 surf_color, vec3 dir, vec3 origin, const float time_of
|
||||
|
||||
// Rainbow
|
||||
#if (CLOUD_MODE >= CLOUD_MODE_MEDIUM)
|
||||
#ifdef EXPERIMENTAL_RAINBOWS
|
||||
#ifndef EXPERIMENTAL_NORAINBOWS
|
||||
if (rainbow_c >= 0 && rainbow_c < 8) {
|
||||
vec3 colors[9] = {
|
||||
surf_color,
|
||||
@ -300,7 +300,7 @@ vec3 get_cloud_color(vec3 surf_color, vec3 dir, vec3 origin, const float time_of
|
||||
};
|
||||
float h = max(0.0, min(pos.z, 900.0 - pos.z) / 450.0);
|
||||
float rain = rain_density_at(pos.xy) * pow(h, 0.1);
|
||||
|
||||
|
||||
float sun = sun_access * get_sun_brightness();
|
||||
float energy = pow(rain * sun * min(cdist / 500.0, 1.0), 2.0) * 0.4;
|
||||
|
||||
|
@ -19,6 +19,7 @@ layout(std140, set = 0, binding = 0) uniform u_globals {
|
||||
uvec4 medium;
|
||||
ivec4 select_pos;
|
||||
vec4 gamma_exposure;
|
||||
vec4 last_lightning;
|
||||
float ambiance;
|
||||
// 0 - FirstPerson
|
||||
// 1 - ThirdPerson
|
||||
|
@ -1,6 +1,49 @@
|
||||
#ifndef POINT_GLOW_GLSL
|
||||
#define POINT_GLOW_GLSL
|
||||
|
||||
#include "sky.glsl"
|
||||
|
||||
#ifdef POINT_GLOW_FACTOR
|
||||
void apply_point_glow_light(Light L, vec3 wpos, vec3 dir, float max_dist, inout vec3 color) {
|
||||
vec3 light_pos = L.light_pos.xyz;
|
||||
// Project light_pos to dir line
|
||||
float t = max(dot(light_pos - wpos, dir), 0);
|
||||
vec3 nearest = wpos + dir * min(t, max_dist);
|
||||
|
||||
vec3 difference = light_pos - nearest;
|
||||
float distance_2 = dot(difference, difference);
|
||||
//if (distance_2 > 100000.0) {
|
||||
// return;
|
||||
//}
|
||||
|
||||
#if (CLOUD_MODE >= CLOUD_MODE_HIGH)
|
||||
vec3 _unused;
|
||||
float unused2;
|
||||
float spread = 1.0 / (1.0 + cloud_at(nearest, 0.0, _unused, unused2).z * 0.005);
|
||||
#else
|
||||
const float spread = 1.0;
|
||||
#endif
|
||||
|
||||
float strength = pow(attenuation_strength_real(difference), spread);
|
||||
|
||||
#ifdef EXPERIMENTAL_LOWGLOWNEARCAMERA
|
||||
vec3 cam_wpos = cam_pos.xyz + focus_pos.xyz + focus_off.xyz;
|
||||
vec3 cam_diff = light_pos - cam_wpos;
|
||||
float cam_dist_2 = dot(cam_diff, cam_diff);
|
||||
// 3 meters away glow returns to the maximum strength.
|
||||
strength *= clamp(cam_dist_2 / 9.0, 0.25, 1.0);
|
||||
#endif
|
||||
|
||||
vec3 light_color = srgb_to_linear(L.light_col.rgb) * strength;
|
||||
|
||||
const float LIGHT_AMBIANCE = 0.025;
|
||||
color += light_color
|
||||
* 0.002
|
||||
// Constant, *should* const fold
|
||||
* POINT_GLOW_FACTOR;
|
||||
}
|
||||
#endif
|
||||
|
||||
vec3 apply_point_glow(vec3 wpos, vec3 dir, float max_dist, vec3 color) {
|
||||
#ifndef POINT_GLOW_FACTOR
|
||||
return color;
|
||||
@ -9,44 +52,14 @@ vec3 apply_point_glow(vec3 wpos, vec3 dir, float max_dist, vec3 color) {
|
||||
// Only access the array once
|
||||
Light L = lights[i];
|
||||
|
||||
vec3 light_pos = L.light_pos.xyz;
|
||||
// Project light_pos to dir line
|
||||
float t = max(dot(light_pos - wpos, dir), 0);
|
||||
vec3 nearest = wpos + dir * min(t, max_dist);
|
||||
|
||||
vec3 difference = light_pos - nearest;
|
||||
float distance_2 = dot(difference, difference);
|
||||
if (distance_2 > 100000.0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#if (CLOUD_MODE >= CLOUD_MODE_HIGH)
|
||||
vec3 _unused;
|
||||
float unused2;
|
||||
float spread = 1.0 / (1.0 + cloud_at(nearest, 0.0, _unused, unused2).z * 0.005);
|
||||
#else
|
||||
const float spread = 1.0;
|
||||
#endif
|
||||
|
||||
float strength = pow(attenuation_strength_real(difference), spread);
|
||||
|
||||
#ifdef EXPERIMENTAL_LOWGLOWNEARCAMERA
|
||||
vec3 cam_wpos = cam_pos.xyz + focus_pos.xyz + focus_off.xyz;
|
||||
vec3 cam_diff = light_pos - cam_wpos;
|
||||
float cam_dist_2 = dot(cam_diff, cam_diff);
|
||||
// 3 meters away glow returns to the maximum strength.
|
||||
strength *= clamp(cam_dist_2 / 9.0, 0.25, 1.0);
|
||||
#endif
|
||||
|
||||
vec3 light_color = srgb_to_linear(L.light_col.rgb) * strength;
|
||||
|
||||
const float LIGHT_AMBIANCE = 0.025;
|
||||
color += light_color
|
||||
* 0.002
|
||||
// Constant, *should* const fold
|
||||
* POINT_GLOW_FACTOR;
|
||||
apply_point_glow_light(L, wpos, dir, max_dist, color);
|
||||
}
|
||||
#endif
|
||||
float time_since_lightning = tick.x - last_lightning.w;
|
||||
if (time_since_lightning < MAX_LIGHTNING_PERIOD) {
|
||||
// Apply lightning
|
||||
apply_point_glow_light(Light(last_lightning.xyzw + vec4(0, 0, LIGHTNING_HEIGHT, 0), vec4(vec3(0.2, 0.4, 1) * lightning_intensity() * 0.003, 1)), wpos, dir, max_dist, color);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
|
@ -20,9 +20,7 @@ uniform u_rain_occlusion {
|
||||
|
||||
float rain_occlusion_at(in vec3 fragPos)
|
||||
{
|
||||
float bias = -0.2;
|
||||
|
||||
vec4 rain_pos = rain_occlusion_texture_mat * vec4(fragPos, 1.0) - vec4(0, 0, bias, 0);
|
||||
vec4 rain_pos = rain_occlusion_texture_mat * vec4(fragPos, 1.0);
|
||||
|
||||
float visibility = textureProj(sampler2DShadow(t_directed_occlusion_maps, s_directed_occlusion_maps), rain_pos);
|
||||
|
||||
|
@ -232,6 +232,34 @@ DirectionalLight get_moon_info(vec4 _dir, float shade_frac/*, vec4 light_pos[2]*
|
||||
return DirectionalLight(/*dir, */shadow, block/*, get_moon_color(dir), get_moon_brightness(dir)*/);
|
||||
}
|
||||
|
||||
const float LIGHTNING_HEIGHT = 25.0;
|
||||
const float MAX_LIGHTNING_PERIOD = 5.0;
|
||||
|
||||
float lightning_intensity() {
|
||||
float time_since_lightning = tick.x - last_lightning.w;
|
||||
return
|
||||
// Strength
|
||||
1000000
|
||||
// Flash
|
||||
* max(0.0, 1.0 - time_since_lightning * 1.0)
|
||||
// Reverb
|
||||
* max(sin(time_of_day.x * 0.4), 0.0);
|
||||
}
|
||||
|
||||
vec3 lightning_at(vec3 wpos) {
|
||||
float time_since_lightning = tick.x - last_lightning.w;
|
||||
if (time_since_lightning < MAX_LIGHTNING_PERIOD) {
|
||||
vec3 diff = wpos + focus_off.xyz - (last_lightning.xyz + vec3(0, 0, LIGHTNING_HEIGHT));
|
||||
float dist = length(diff);
|
||||
return vec3(0.5, 0.8, 1.0)
|
||||
* lightning_intensity()
|
||||
// Attenuation
|
||||
/ pow(50.0 + dist, 2);
|
||||
} else {
|
||||
return vec3(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
// // Calculates extra emission and reflectance (due to sunlight / moonlight).
|
||||
// //
|
||||
// // reflectence = k_a * i_a + i_a,persistent
|
||||
@ -437,7 +465,7 @@ float get_sun_diffuse2(DirectionalLight sun_info, DirectionalLight moon_info, ve
|
||||
light_reflection_factor(norm, dir, normalize(sun_dir - vec3(0.0, 0.1, 0.0)), k_d, k_s, alpha)*/) +
|
||||
(1.0 - MOON_AMBIANCE) * moon_chroma * moon_shadow * 1.0 * /*4.0 * */light_reflection_factor(norm, dir, moon_dir, k_d, k_s, alpha, voxel_norm, voxel_lighting) +
|
||||
emission
|
||||
);
|
||||
) + lightning_at(wpos);
|
||||
|
||||
/* light = sun_chroma + moon_chroma + PERSISTENT_AMBIANCE;
|
||||
diffuse_light =
|
||||
|
@ -41,7 +41,6 @@ const int SMOKE = 0;
|
||||
const int FIRE = 1;
|
||||
const int GUN_POWDER_SPARK = 2;
|
||||
const int SHRAPNEL = 3;
|
||||
|
||||
const int FIREWORK_BLUE = 4;
|
||||
const int FIREWORK_GREEN = 5;
|
||||
const int FIREWORK_PURPLE = 6;
|
||||
@ -76,6 +75,7 @@ const int DEATH = 34;
|
||||
const int ENERGY_BUFFING = 35;
|
||||
const int WEB_STRAND = 36;
|
||||
const int BLACK_SMOKE = 37;
|
||||
const int LIGHTNING = 38;
|
||||
|
||||
// meters per second squared (acceleration)
|
||||
const float earth_gravity = 9.807;
|
||||
@ -602,6 +602,18 @@ void main() {
|
||||
spin_in_axis(perp_axis, asin(inst_dir.z / length(inst_dir)) + PI / 2.0)
|
||||
);
|
||||
break;
|
||||
case LIGHTNING:
|
||||
f_reflect = 0.0;
|
||||
perp_axis = normalize(cross(inst_dir, vec3(0.0, 0.0, 1.0)));
|
||||
float z = inst_dir.z * (percent() - 1.0);
|
||||
vec3 start_off = vec3(abs(fract(vec3(vec2(z) * vec2(0.015, 0.01), 0)) - 0.5) * z * 0.4);
|
||||
attr = Attr(
|
||||
inst_dir * percent() + start_off,
|
||||
vec3(max(3.0, 0.05 * length(start_pos + inst_dir * percent()))),
|
||||
vec4(10.0, 20.0, 50.0, 1.0),// * (1.0 - length(inst_dir) * 0.1),
|
||||
identity()//spin_in_axis(perp_axis, asin(inst_dir.z / length(inst_dir)) + PI / 2.0)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
|
@ -244,22 +244,50 @@ void main() {
|
||||
drop_pos.z *= 0.5 + hash_fast(uvec3(cell2d, 0));
|
||||
vec3 cell = vec3(cell2d, floor(drop_pos.z * drop_density.z));
|
||||
|
||||
if (fract(hash(fract(vec4(cell, 0) * 0.01))) < rain_density * rain_occlusion_at(f_pos.xyz) * 50.0) {
|
||||
vec3 off = vec3(hash_fast(uvec3(cell * 13)), hash_fast(uvec3(cell * 5)), 0);
|
||||
vec3 near_cell = (cell + 0.5 + (off - 0.5) * 0.5) / drop_density;
|
||||
if (rain_occlusion_at(f_pos.xyz + vec3(0, 0, 0.25)) > 0.5) {
|
||||
#ifdef EXPERIMENTAL_WETNESS
|
||||
float puddle = clamp((noise_2d((f_pos.xy + focus_off.xy + vec2(0.1, 0)) * 0.03) - 0.5) * 20.0, 0.0, 1.0) * min(rain_density * 10.0, 1.0);
|
||||
#else
|
||||
const float puddle = 1.0;
|
||||
#endif
|
||||
|
||||
float dist = length((drop_pos - near_cell) / vec3(1, 1, 2));
|
||||
float drop_rad = 0.1;
|
||||
float distort = max(1.0 - abs(dist - drop_rad) * 100, 0) * 1.5 * max(drop_pos.z - near_cell.z, 0);
|
||||
k_a += distort;
|
||||
k_d += distort;
|
||||
k_s += distort;
|
||||
f_norm.xy += (drop_pos - near_cell).xy
|
||||
* max(1.0 - abs(dist - drop_rad) * 30, 0)
|
||||
* 500.0
|
||||
* max(drop_pos.z - near_cell.z, 0)
|
||||
* sign(dist - drop_rad)
|
||||
* max(drop_pos.z - near_cell.z, 0);
|
||||
if (fract(hash(fract(vec4(cell, 0) * 0.01))) < rain_density * 2.0 && puddle > 0.3) {
|
||||
vec3 off = vec3(hash_fast(uvec3(cell * 13)), hash_fast(uvec3(cell * 5)), 0);
|
||||
vec3 near_cell = (cell + 0.5 + (off - 0.5) * 0.5) / drop_density;
|
||||
|
||||
float dist = length((drop_pos - near_cell) / vec3(1, 1, 2));
|
||||
float drop_rad = 0.1;
|
||||
float distort = max(1.0 - abs(dist - drop_rad) * 100, 0) * 1.5 * max(drop_pos.z - near_cell.z, 0);
|
||||
k_a += distort;
|
||||
k_d += distort;
|
||||
k_s += distort;
|
||||
|
||||
#ifdef EXPERIMENTAL_WETNESS
|
||||
/* puddle = mix(puddle, 1.0, distort * 10); */
|
||||
#endif
|
||||
|
||||
f_norm.xy += (drop_pos - near_cell).xy
|
||||
* max(1.0 - abs(dist - drop_rad) * 30, 0)
|
||||
* 500.0
|
||||
* max(drop_pos.z - near_cell.z, 0)
|
||||
* sign(dist - drop_rad)
|
||||
* max(drop_pos.z - near_cell.z, 0);
|
||||
}
|
||||
|
||||
#ifdef EXPERIMENTAL_WETNESS
|
||||
if (puddle > 0.0) {
|
||||
float h = (noise_2d((f_pos.xy + focus_off.xy) * 0.3) - 0.5) * sin(tick.x * 8.0 + f_pos.x * 3)
|
||||
+ (noise_2d((f_pos.xy + focus_off.xy) * 0.6) - 0.5) * sin(tick.x * 3.5 - f_pos.y * 6);
|
||||
float hx = (noise_2d((f_pos.xy + focus_off.xy + vec2(0.1, 0)) * 0.3) - 0.5) * sin(tick.x * 8.0 + f_pos.x * 3)
|
||||
+ (noise_2d((f_pos.xy + focus_off.xy + vec2(0.1, 0)) * 0.6) - 0.5) * sin(tick.x * 3.5 - f_pos.y * 6);
|
||||
float hy = (noise_2d((f_pos.xy + focus_off.xy + vec2(0, 0.1)) * 0.3) - 0.5) * sin(tick.x * 8.0 + f_pos.x * 3)
|
||||
+ (noise_2d((f_pos.xy + focus_off.xy + vec2(0, 0.1)) * 0.6) - 0.5) * sin(tick.x * 3.5 - f_pos.y * 6);
|
||||
f_norm.xy += mix(vec2(0), vec2(h - hx, h - hy) / 0.1 * 0.03, puddle);
|
||||
alpha = mix(1.0, 0.2, puddle);
|
||||
f_col.rgb *= mix(1.0, 0.7, puddle);
|
||||
k_s = mix(k_s, vec3(0.7, 0.7, 1.0), puddle);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -300,7 +328,7 @@ void main() {
|
||||
vec3 two_down = f_pos - offset_two;
|
||||
|
||||
// Adjust this to change the size of the grid cells relative to the
|
||||
// number of shadow texels
|
||||
// number of shadow texels
|
||||
float grid_cell_to_texel_ratio = 32.0;
|
||||
|
||||
vec2 shadowTexSize = textureSize(sampler2D(t_directed_shadow_maps, s_directed_shadow_maps), 0) / grid_cell_to_texel_ratio;
|
||||
@ -320,7 +348,7 @@ void main() {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
float max_light = 0.0;
|
||||
|
||||
// After shadows are computed, we use a refracted sun and moon direction.
|
||||
|
@ -305,6 +305,7 @@ pub enum ServerChatCommand {
|
||||
CreateLocation,
|
||||
DeleteLocation,
|
||||
WeatherZone,
|
||||
Lightning,
|
||||
}
|
||||
|
||||
impl ServerChatCommand {
|
||||
@ -703,6 +704,9 @@ impl ServerChatCommand {
|
||||
"Create a weather zone",
|
||||
Some(Admin),
|
||||
),
|
||||
ServerChatCommand::Lightning => {
|
||||
cmd(vec![], "Lightning strike at current position", Some(Admin))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -781,6 +785,7 @@ impl ServerChatCommand {
|
||||
ServerChatCommand::CreateLocation => "create_location",
|
||||
ServerChatCommand::DeleteLocation => "delete_location",
|
||||
ServerChatCommand::WeatherZone => "weather_zone",
|
||||
ServerChatCommand::Lightning => "lightning",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,9 @@ pub enum Outcome {
|
||||
is_attack: bool,
|
||||
reagent: Option<Reagent>, // How can we better define this?
|
||||
},
|
||||
Lightning {
|
||||
pos: Vec3<f32>,
|
||||
},
|
||||
ProjectileShot {
|
||||
pos: Vec3<f32>,
|
||||
body: comp::Body,
|
||||
@ -100,6 +103,8 @@ impl Outcome {
|
||||
pub fn get_pos(&self) -> Option<Vec3<f32>> {
|
||||
match self {
|
||||
Outcome::Explosion { pos, .. }
|
||||
// TODO: Include this, but allow it to be sent to clients when outside of the VD
|
||||
// | Outcome::Lightning { pos }
|
||||
| Outcome::ProjectileShot { pos, .. }
|
||||
| Outcome::ProjectileHit { pos, .. }
|
||||
| Outcome::Beam { pos, .. }
|
||||
@ -114,6 +119,7 @@ impl Outcome {
|
||||
Outcome::BreakBlock { pos, .. } => Some(pos.map(|e| e as f32 + 0.5)),
|
||||
Outcome::ExpChange { .. }
|
||||
| Outcome::ComboChange { .. }
|
||||
| Outcome::Lightning { .. }
|
||||
| Outcome::SkillPointGain { .. } => None,
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ impl Weather {
|
||||
|
||||
// Get the rain velocity for this weather
|
||||
pub fn rain_vel(&self) -> Vec3<f32> {
|
||||
const FALL_RATE: f32 = 50.0;
|
||||
const FALL_RATE: f32 = 30.0;
|
||||
Vec3::new(self.wind.x, self.wind.y, -FALL_RATE)
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ use common::{
|
||||
link::Is,
|
||||
mounting::Rider,
|
||||
npc::{self, get_npc_name},
|
||||
outcome::Outcome,
|
||||
parse_cmd_args,
|
||||
resources::{BattleMode, PlayerPhysicsSettings, Time, TimeOfDay},
|
||||
terrain::{Block, BlockKind, SpriteKind, TerrainChunkSize},
|
||||
@ -192,6 +193,7 @@ fn do_command(
|
||||
ServerChatCommand::CreateLocation => handle_create_location,
|
||||
ServerChatCommand::DeleteLocation => handle_delete_location,
|
||||
ServerChatCommand::WeatherZone => handle_weather_zone,
|
||||
ServerChatCommand::Lightning => handle_lightning,
|
||||
};
|
||||
|
||||
handler(server, client, target, args, cmd)
|
||||
@ -3666,3 +3668,19 @@ fn handle_weather_zone(
|
||||
Err(action.help_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_lightning(
|
||||
server: &mut Server,
|
||||
client: EcsEntity,
|
||||
_target: EcsEntity,
|
||||
_args: Vec<String>,
|
||||
_action: &ServerChatCommand,
|
||||
) -> CmdResult<()> {
|
||||
let pos = position(server, client, "player")?.0;
|
||||
server
|
||||
.state
|
||||
.ecs()
|
||||
.read_resource::<EventBus<Outcome>>()
|
||||
.emit_now(Outcome::Lightning { pos });
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,15 +1,18 @@
|
||||
use common::{
|
||||
event::EventBus,
|
||||
grid::Grid,
|
||||
outcome::Outcome,
|
||||
resources::TimeOfDay,
|
||||
weather::{Weather, WeatherGrid, CELL_SIZE, CHUNKS_PER_CELL},
|
||||
};
|
||||
use noise::{NoiseFn, SuperSimplex, Turbulence};
|
||||
use rand::prelude::*;
|
||||
use vek::*;
|
||||
use world::World;
|
||||
|
||||
use crate::weather::WEATHER_DT;
|
||||
|
||||
fn cell_to_wpos(p: Vec2<i32>) -> Vec2<i32> { p * CELL_SIZE as i32 }
|
||||
fn cell_to_wpos_center(p: Vec2<i32>) -> Vec2<i32> { p * CELL_SIZE as i32 + CELL_SIZE as i32 / 2 }
|
||||
|
||||
#[derive(Clone)]
|
||||
struct WeatherZone {
|
||||
@ -19,7 +22,7 @@ struct WeatherZone {
|
||||
}
|
||||
|
||||
struct CellConsts {
|
||||
rain_factor: f32,
|
||||
humidity: f32,
|
||||
}
|
||||
|
||||
pub struct WeatherSim {
|
||||
@ -49,8 +52,9 @@ impl WeatherSim {
|
||||
}
|
||||
}
|
||||
let average_humid = humid_sum / (CHUNKS_PER_CELL * CHUNKS_PER_CELL) as f32;
|
||||
let rain_factor = (2.0 * average_humid.powf(0.2)).min(1.0);
|
||||
CellConsts { rain_factor }
|
||||
CellConsts {
|
||||
humidity: average_humid.powf(0.2).min(1.0),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
@ -82,7 +86,13 @@ impl WeatherSim {
|
||||
}
|
||||
|
||||
// Time step is cell size / maximum wind speed
|
||||
pub fn tick(&mut self, time_of_day: &TimeOfDay, out: &mut WeatherGrid) {
|
||||
pub fn tick(
|
||||
&mut self,
|
||||
time_of_day: &TimeOfDay,
|
||||
outcomes: &EventBus<Outcome>,
|
||||
out: &mut WeatherGrid,
|
||||
world: &World,
|
||||
) {
|
||||
let time = time_of_day.0;
|
||||
|
||||
let base_nz = Turbulence::new(
|
||||
@ -103,7 +113,7 @@ impl WeatherSim {
|
||||
self.zones[point] = None;
|
||||
}
|
||||
} else {
|
||||
let wpos = cell_to_wpos(point);
|
||||
let wpos = cell_to_wpos_center(point);
|
||||
|
||||
let pos = wpos.as_::<f64>() + time as f64 * 0.1;
|
||||
|
||||
@ -111,18 +121,43 @@ impl WeatherSim {
|
||||
let time_scale = 100_000.0;
|
||||
let spos = (pos / space_scale).with_z(time as f64 / time_scale);
|
||||
|
||||
let pressure =
|
||||
(base_nz.get(spos.into_array()) * 0.5 + 1.0).clamped(0.0, 1.0) as f32;
|
||||
let avg_scale = 20_000.0;
|
||||
let avg_delay = 250_000.0;
|
||||
let pressure = ((base_nz.get(
|
||||
(pos / avg_scale)
|
||||
.with_z(time as f64 / avg_delay)
|
||||
.into_array(),
|
||||
) + base_nz.get(
|
||||
(pos / (avg_scale * 0.25))
|
||||
.with_z(time as f64 / (avg_delay * 0.25))
|
||||
.into_array(),
|
||||
) * 0.5)
|
||||
* 0.5
|
||||
+ 1.0)
|
||||
.clamped(0.0, 1.0) as f32
|
||||
+ 0.55
|
||||
- self.consts[point].humidity * 0.6;
|
||||
|
||||
const RAIN_CLOUD_THRESHOLD: f32 = 0.26;
|
||||
cell.cloud = (1.0 - pressure) * 0.5;
|
||||
cell.rain = (1.0 - pressure - RAIN_CLOUD_THRESHOLD).max(0.0)
|
||||
* self.consts[point].rain_factor;
|
||||
const RAIN_CLOUD_THRESHOLD: f32 = 0.25;
|
||||
cell.cloud = (1.0 - pressure).max(0.0) * 0.5;
|
||||
cell.rain = ((1.0 - pressure - RAIN_CLOUD_THRESHOLD).max(0.0)
|
||||
* self.consts[point].humidity
|
||||
* 2.5)
|
||||
.powf(0.75);
|
||||
cell.wind = Vec2::new(
|
||||
rain_nz.get(spos.into_array()).powi(3) as f32,
|
||||
rain_nz.get((spos + 1.0).into_array()).powi(3) as f32,
|
||||
) * 200.0
|
||||
* (1.0 - pressure);
|
||||
|
||||
if cell.rain > 0.2 && cell.cloud > 0.15 && thread_rng().gen_bool(0.01) {
|
||||
let wpos = wpos.map(|e| {
|
||||
e as f32 + thread_rng().gen_range(-1.0..1.0) * CELL_SIZE as f32 * 0.5
|
||||
});
|
||||
outcomes.emit_now(Outcome::Lightning {
|
||||
pos: wpos.with_z(world.sim().get_alt_approx(wpos.as_()).unwrap_or(0.0)),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
use common::{resources::TimeOfDay, weather::WeatherGrid};
|
||||
use common::{event::EventBus, outcome::Outcome, resources::TimeOfDay, weather::WeatherGrid};
|
||||
use common_ecs::{Origin, Phase, System};
|
||||
use specs::{Read, Write, WriteExpect};
|
||||
use specs::{Read, ReadExpect, Write, WriteExpect};
|
||||
use std::sync::Arc;
|
||||
use world::World;
|
||||
|
||||
use crate::sys::SysScheduler;
|
||||
|
||||
@ -15,6 +17,8 @@ impl<'a> System<'a> for Sys {
|
||||
WriteExpect<'a, WeatherSim>,
|
||||
WriteExpect<'a, WeatherGrid>,
|
||||
Write<'a, SysScheduler<Self>>,
|
||||
ReadExpect<'a, EventBus<Outcome>>,
|
||||
ReadExpect<'a, Arc<World>>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "weather::tick";
|
||||
@ -23,13 +27,13 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
fn run(
|
||||
_job: &mut common_ecs::Job<Self>,
|
||||
(game_time, mut sim, mut grid, mut scheduler): Self::SystemData,
|
||||
(game_time, mut sim, mut grid, mut scheduler, outcomes, world): Self::SystemData,
|
||||
) {
|
||||
if scheduler.should_run() {
|
||||
if grid.size() != sim.size() {
|
||||
*grid = WeatherGrid::new(sim.size());
|
||||
}
|
||||
sim.tick(&game_time, &mut grid);
|
||||
sim.tick(&game_time, &outcomes, &mut grid, &world);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -191,6 +191,7 @@ pub enum SfxEvent {
|
||||
PoiseChange(PoiseState),
|
||||
GroundSlam,
|
||||
Utterance(UtteranceKind, VoiceKind),
|
||||
Lightning,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Deserialize, Hash, Eq)]
|
||||
@ -433,6 +434,16 @@ impl SfxMgr {
|
||||
underwater,
|
||||
);
|
||||
},
|
||||
Outcome::Lightning { pos } => {
|
||||
let power = (1.0 - pos.distance(audio.listener.pos) / 6_000.0)
|
||||
.clamped(0.0, 1.0)
|
||||
.powf(0.75);
|
||||
if power > 0.0 {
|
||||
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Lightning);
|
||||
// TODO: Don't use UI sfx, add a way to control position falloff
|
||||
audio.emit_ui_sfx(sfx_trigger_item, Some(power * 3.0));
|
||||
}
|
||||
},
|
||||
Outcome::GroundSlam { pos, .. } => {
|
||||
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::GroundSlam);
|
||||
audio.emit_sfx(sfx_trigger_item, *pos, Some(2.0), underwater);
|
||||
|
@ -476,6 +476,8 @@ pub enum ExperimentalShader {
|
||||
/// Display grid lines to visualize the distribution of shadow map texels
|
||||
/// for the directional light from the sun.
|
||||
DirectionalShadowMapTexelGrid,
|
||||
/// Enable rainbows
|
||||
Rainbows,
|
||||
/// Disable rainbows
|
||||
NoRainbows,
|
||||
/// Make objects appear wet when appropriate.
|
||||
Wetness,
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ pub struct Globals {
|
||||
medium: [u32; 4],
|
||||
select_pos: [i32; 4],
|
||||
gamma_exposure: [f32; 4],
|
||||
last_lightning: [f32; 4],
|
||||
ambiance: f32,
|
||||
cam_mode: u32,
|
||||
sprite_render_distance: f32,
|
||||
@ -108,6 +109,7 @@ impl Globals {
|
||||
select_pos: Option<Vec3<i32>>,
|
||||
gamma: f32,
|
||||
exposure: f32,
|
||||
last_lightning: (Vec3<f32>, f64),
|
||||
ambiance: f32,
|
||||
cam_mode: CameraMode,
|
||||
sprite_render_distance: f32,
|
||||
@ -156,6 +158,10 @@ impl Globals {
|
||||
.unwrap_or_else(Vec4::zero)
|
||||
.into_array(),
|
||||
gamma_exposure: [gamma, exposure, 0.0, 0.0],
|
||||
last_lightning: last_lightning
|
||||
.0
|
||||
.with_w(last_lightning.1 as f32)
|
||||
.into_array(),
|
||||
ambiance: ambiance.clamped(0.0, 1.0),
|
||||
cam_mode: cam_mode as u32,
|
||||
sprite_render_distance,
|
||||
@ -202,6 +208,7 @@ impl Default for Globals {
|
||||
None,
|
||||
1.0,
|
||||
1.0,
|
||||
(Vec3::zero(), -1000.0),
|
||||
1.0,
|
||||
CameraMode::ThirdPerson,
|
||||
250.0,
|
||||
|
@ -88,6 +88,7 @@ pub enum ParticleMode {
|
||||
EnergyBuffing = 35,
|
||||
WebStrand = 36,
|
||||
BlackSmoke = 37,
|
||||
Lightning = 38,
|
||||
}
|
||||
|
||||
impl ParticleMode {
|
||||
|
@ -195,7 +195,7 @@ impl RainOcclusionPipeline {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
strip_index_format: None,
|
||||
front_face: wgpu::FrontFace::Ccw,
|
||||
cull_mode: Some(wgpu::Face::Front),
|
||||
cull_mode: Some(wgpu::Face::Back),
|
||||
clamp_depth: true,
|
||||
polygon_mode: wgpu::PolygonMode::Fill,
|
||||
conservative: false,
|
||||
|
@ -108,6 +108,7 @@ pub struct Scene {
|
||||
ambient_mgr: AmbientMgr,
|
||||
|
||||
integrated_rain_vel: f32,
|
||||
last_lightning: Option<(Vec3<f32>, f64)>,
|
||||
}
|
||||
|
||||
pub struct SceneData<'a> {
|
||||
@ -325,6 +326,7 @@ impl Scene {
|
||||
ambience: ambient::load_ambience_items(),
|
||||
},
|
||||
integrated_rain_vel: 0.0,
|
||||
last_lightning: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -426,6 +428,9 @@ impl Scene {
|
||||
.handle_outcome(outcome, audio, scene_data.client, underwater);
|
||||
|
||||
match outcome {
|
||||
Outcome::Lightning { pos } => {
|
||||
self.last_lightning = Some((*pos, scene_data.state.get_time()));
|
||||
},
|
||||
Outcome::Explosion {
|
||||
pos,
|
||||
power,
|
||||
@ -689,6 +694,7 @@ impl Scene {
|
||||
self.select_pos.map(|e| e - focus_off.map(|e| e as i32)),
|
||||
scene_data.gamma,
|
||||
scene_data.exposure,
|
||||
self.last_lightning.unwrap_or((Vec3::zero(), -1000.0)),
|
||||
scene_data.ambiance,
|
||||
self.camera.get_mode(),
|
||||
scene_data.sprite_render_distance as f32 - 20.0,
|
||||
|
@ -62,6 +62,17 @@ impl ParticleMgr {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
match outcome {
|
||||
Outcome::Lightning { pos } => {
|
||||
self.particles.resize_with(self.particles.len() + 800, || {
|
||||
Particle::new_directed(
|
||||
Duration::from_secs_f32(rng.gen_range(0.5..1.0)),
|
||||
time,
|
||||
ParticleMode::Lightning,
|
||||
*pos + Vec3::new(0.0, 0.0, rng.gen_range(0.0..600.0)),
|
||||
*pos,
|
||||
)
|
||||
});
|
||||
},
|
||||
Outcome::Explosion {
|
||||
pos,
|
||||
power,
|
||||
|
@ -273,6 +273,7 @@ impl Scene {
|
||||
None,
|
||||
scene_data.gamma,
|
||||
scene_data.exposure,
|
||||
(Vec3::zero(), -1000.0),
|
||||
scene_data.ambiance,
|
||||
self.camera.get_mode(),
|
||||
250.0,
|
||||
|
@ -48,7 +48,7 @@ const SPRITE_LOD_LEVELS: usize = 5;
|
||||
|
||||
// For rain occlusion we only need to render the closest chunks.
|
||||
/// How many chunks are maximally rendered for rain occlusion.
|
||||
pub const RAIN_OCCLUSION_CHUNKS: usize = 9;
|
||||
pub const RAIN_OCCLUSION_CHUNKS: usize = 25;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct Visibility {
|
||||
|
Loading…
Reference in New Issue
Block a user