diff --git a/assets/voxygen/shaders/antialias/fxaa.glsl b/assets/voxygen/shaders/antialias/fxaa.glsl index 700dfa4e90..90fdff7c2b 100644 --- a/assets/voxygen/shaders/antialias/fxaa.glsl +++ b/assets/voxygen/shaders/antialias/fxaa.glsl @@ -1,6 +1,6 @@ uniform sampler2D src_color; -const float FXAA_SCALE = 1.5; +const float FXAA_SCALE = 1.25; /** Basic FXAA implementation based on the code on geeks3d.com with the @@ -134,4 +134,4 @@ vec4 aa_apply(sampler2D tex, vec2 fragCoord, vec2 resolution) { //compute FXAA return fxaa(tex, scaled_fc, scaled_res, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} \ No newline at end of file +} diff --git a/assets/voxygen/shaders/figure-frag.glsl b/assets/voxygen/shaders/figure-frag.glsl index 06156e2cf2..aba60bf8d5 100644 --- a/assets/voxygen/shaders/figure-frag.glsl +++ b/assets/voxygen/shaders/figure-frag.glsl @@ -39,8 +39,9 @@ void main() { vec3 surf_color = illuminate(srgb_to_linear(model_col.rgb * f_col), light, diffuse_light, ambient_light); float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x); - vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, true); - vec3 color = mix(surf_color, fog_color, fog_level); + vec4 clouds; + vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, cam_pos.xyz, f_pos, 0.5, true, clouds); + vec3 color = mix(mix(surf_color, fog_color, fog_level), clouds.rgb, clouds.a); tgt_color = vec4(color, 1.0); } diff --git a/assets/voxygen/shaders/figure-vert.glsl b/assets/voxygen/shaders/figure-vert.glsl index 8e9ead9aa7..dbaf30f964 100644 --- a/assets/voxygen/shaders/figure-vert.glsl +++ b/assets/voxygen/shaders/figure-vert.glsl @@ -43,4 +43,5 @@ void main() { ).xyz); gl_Position = proj_mat * view_mat * vec4(f_pos, 1); + gl_Position.z = 1.0 / (1.0 - gl_Position.z - 10.0); } diff --git a/assets/voxygen/shaders/fluid-frag.glsl b/assets/voxygen/shaders/fluid-frag.glsl index 2d4f3bae7b..836b405907 100644 --- a/assets/voxygen/shaders/fluid-frag.glsl +++ b/assets/voxygen/shaders/fluid-frag.glsl @@ -35,22 +35,23 @@ float wave_height(vec3 pos) { ); vec3 warp = ( - texture(t_waves, fract(pos.yx * 0.1 + tick.x * 0.02)).xyz * 0.3 + - texture(t_waves, fract(pos.yx * 0.1 - tick.x * 0.02)).xyz * 0.3 + + texture(t_noise, fract(pos.yx * 0.1 + tick.x * 0.02)).xyz * 0.3 + + texture(t_noise, fract(pos.yx * 0.1 - tick.x * 0.02)).xyz * 0.3 + vec3(0) ); float height = ( - (texture(t_waves, pos.xy * 0.03 + big_warp.xy + tick.x * 0.05).y - 0.5) * 1.0 + - (texture(t_waves, pos.yx * 0.03 + big_warp.yx - tick.x * 0.05).y - 0.5) * 1.0 + + (texture(t_noise, pos.xy * 0.03 + big_warp.xy + tick.x * 0.05).y - 0.5) * 1.0 + + (texture(t_noise, pos.yx * 0.03 + big_warp.yx - tick.x * 0.05).y - 0.5) * 1.0 + (texture(t_waves, pos.xy * 0.1 + warp.xy + tick.x * 0.1).x - 0.5) * 0.5 + (texture(t_waves, pos.yx * 0.1 + warp.yx - tick.x * 0.1).x - 0.5) * 0.5 + - (texture(t_waves, pos.yx * 0.3 + warp.xy * 0.5 + tick.x * 0.1).x - 0.5) * 0.2 + - (texture(t_waves, pos.yx * 0.3 + warp.yx * 0.5 - tick.x * 0.1).x - 0.5) * 0.2 + + (texture(t_noise, pos.yx * 0.3 + warp.xy * 0.5 + tick.x * 0.1).x - 0.5) * 0.2 + + (texture(t_noise, pos.yx * 0.3 + warp.yx * 0.5 - tick.x * 0.1).x - 0.5) * 0.2 + + (texture(t_noise, pos.yx * 1.0 + warp.yx * 0.0 - tick.x * 0.1).x - 0.5) * 0.05 + 0.0 ); - return pow(abs(height), 0.5) * sign(height) * 3.0; + return pow(abs(height), 0.5) * sign(height) * 5.5; } void main() { @@ -98,7 +99,7 @@ void main() { 0.1 / slope ); - nmap = mix(vec3(0, 0, 1), normalize(nmap), clamp(2.0 / pow(frag_dist, 0.5), 0, 1)); + nmap = mix(vec3(0, 0, 1), normalize(nmap), min(1.0 / pow(frag_dist, 0.75), 1)); vec3 norm = f_norm * nmap.z + b_norm * nmap.x + c_norm * nmap.y; @@ -113,17 +114,21 @@ void main() { vec3 surf_color = illuminate(srgb_to_linear(f_col), light, diffuse_light, ambient_light); float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x); - vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, true); + vec4 clouds; + vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, cam_pos.xyz, f_pos, 0.25, true, clouds); vec3 reflect_ray_dir = reflect(cam_to_frag, norm); // Hack to prevent the reflection ray dipping below the horizon and creating weird blue spots in the water reflect_ray_dir.z = max(reflect_ray_dir.z, 0.05); - vec3 reflect_color = get_sky_color(reflect_ray_dir, time_of_day.x, false) * f_light; + vec4 _clouds; + vec3 reflect_color = get_sky_color(reflect_ray_dir, time_of_day.x, f_pos, vec3(-100000), 0.25, false, _clouds) * f_light; + // Tint + reflect_color = mix(reflect_color, surf_color, 0.6); // 0 = 100% reflection, 1 = translucent water float passthrough = pow(dot(faceforward(f_norm, f_norm, cam_to_frag), -cam_to_frag), 0.5); - vec4 color = mix(vec4(reflect_color * 2.0, 1.0), vec4(surf_color, 4.0 / (1.0 + diffuse_light * 2.0)), passthrough); + vec4 color = mix(vec4(reflect_color * 2.0, 1.0), vec4(surf_color, 1.0 / (1.0 + diffuse_light * 0.25)), passthrough); - tgt_color = mix(color, vec4(fog_color, 0.0), fog_level); + tgt_color = mix(mix(color, vec4(fog_color, 0.0), fog_level), vec4(clouds.rgb, 0.0), clouds.a); } diff --git a/assets/voxygen/shaders/fluid-vert.glsl b/assets/voxygen/shaders/fluid-vert.glsl index 07834690e9..f38cfd2e56 100644 --- a/assets/voxygen/shaders/fluid-vert.glsl +++ b/assets/voxygen/shaders/fluid-vert.glsl @@ -24,6 +24,7 @@ void main() { float((v_pos_norm >> 8) & 0x00FFu), float((v_pos_norm >> 16) & 0x1FFFu) ) + model_offs; + f_pos.z -= 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0); f_col = vec3( float((v_col_light >> 8) & 0xFFu), @@ -39,4 +40,5 @@ void main() { proj_mat * view_mat * vec4(f_pos, 1); + gl_Position.z = 1.0 / (1.0 - gl_Position.z - 10.0); } diff --git a/assets/voxygen/shaders/include/sky.glsl b/assets/voxygen/shaders/include/sky.glsl index 59a27f00a8..8fc2b64929 100644 --- a/assets/voxygen/shaders/include/sky.glsl +++ b/assets/voxygen/shaders/include/sky.glsl @@ -1,31 +1,38 @@ #include +uniform sampler2D t_noise; + const float PI = 3.141592; const vec3 SKY_DAY_TOP = vec3(0.1, 0.2, 0.9); const vec3 SKY_DAY_MID = vec3(0.02, 0.08, 0.8); -const vec3 SKY_DAY_BOT = vec3(0.02, 0.01, 0.3); +const vec3 SKY_DAY_BOT = vec3(0.1, 0.2, 0.3); const vec3 DAY_LIGHT = vec3(1.2, 1.0, 1.0); const vec3 SUN_HALO_DAY = vec3(0.35, 0.35, 0.0); const vec3 SKY_DUSK_TOP = vec3(0.06, 0.1, 0.20); const vec3 SKY_DUSK_MID = vec3(0.35, 0.1, 0.15); -const vec3 SKY_DUSK_BOT = vec3(0.0, 0.1, 0.13); +const vec3 SKY_DUSK_BOT = vec3(0.0, 0.1, 0.23); const vec3 DUSK_LIGHT = vec3(3.0, 1.5, 0.3); -const vec3 SUN_HALO_DUSK = vec3(0.6, 0.1, 0.0); +const vec3 SUN_HALO_DUSK = vec3(1.2, 0.15, 0.0); const vec3 SKY_NIGHT_TOP = vec3(0.001, 0.001, 0.0025); const vec3 SKY_NIGHT_MID = vec3(0.001, 0.005, 0.02); -const vec3 SKY_NIGHT_BOT = vec3(0.002, 0.002, 0.005); +const vec3 SKY_NIGHT_BOT = vec3(0.002, 0.004, 0.004); const vec3 NIGHT_LIGHT = vec3(0.002, 0.01, 0.03); vec3 get_sun_dir(float time_of_day) { const float TIME_FACTOR = (PI * 2.0) / (3600.0 * 24.0); float sun_angle_rad = time_of_day * TIME_FACTOR; - vec3 sun_dir = vec3(sin(sun_angle_rad), 0.0, cos(sun_angle_rad)); + return vec3(sin(sun_angle_rad), 0.0, cos(sun_angle_rad)); +} - return sun_dir; +vec3 get_moon_dir(float time_of_day) { + const float TIME_FACTOR = (PI * 2.0) / (3600.0 * 24.0); + + float moon_angle_rad = time_of_day * TIME_FACTOR; + return normalize(-vec3(sin(moon_angle_rad), 0.0, cos(moon_angle_rad) - 0.5)); } const float PERSISTENT_AMBIANCE = 0.1; @@ -34,16 +41,12 @@ float get_sun_brightness(vec3 sun_dir) { return max(-sun_dir.z + 0.6, 0.0) * 0.9; } -void get_sun_diffuse(vec3 norm, float time_of_day, out vec3 light, out vec3 diffuse_light, out vec3 ambient_light, float diffusion) { - const float SUN_AMBIANCE = 0.1; +float get_moon_brightness(vec3 moon_dir) { + return max(-moon_dir.z + 0.6, 0.0) * 0.07; +} - vec3 sun_dir = get_sun_dir(time_of_day); - - float sun_light = get_sun_brightness(sun_dir); - - // clamp() changed to max() as sun_dir.z is produced from a cos() function and therefore never greater than 1 - - vec3 sun_color = mix( +vec3 get_sun_color(vec3 sun_dir) { + return mix( mix( DUSK_LIGHT, NIGHT_LIGHT, @@ -52,12 +55,36 @@ void get_sun_diffuse(vec3 norm, float time_of_day, out vec3 light, out vec3 diff DAY_LIGHT, max(-sun_dir.z, 0) ); +} + +vec3 get_moon_color(vec3 moon_dir) { + return vec3(0.05, 0.05, 0.6); +} + +void get_sun_diffuse(vec3 norm, float time_of_day, out vec3 light, out vec3 diffuse_light, out vec3 ambient_light, float diffusion) { + const float SUN_AMBIANCE = 0.1; + + vec3 sun_dir = get_sun_dir(time_of_day); + vec3 moon_dir = get_moon_dir(time_of_day); + + float sun_light = get_sun_brightness(sun_dir); + float moon_light = get_moon_brightness(moon_dir); + + // clamp() changed to max() as sun_dir.z is produced from a cos() function and therefore never greater than 1 + + vec3 sun_color = get_sun_color(sun_dir); + + vec3 moon_color = get_moon_color(moon_dir); vec3 sun_chroma = sun_color * sun_light; + vec3 moon_chroma = moon_color * moon_light; - light = sun_chroma + PERSISTENT_AMBIANCE; - diffuse_light = sun_chroma * mix(1.0, max(dot(-norm, sun_dir) * 0.6 + 0.4, 0.0), diffusion) + PERSISTENT_AMBIANCE; - ambient_light = vec3(SUN_AMBIANCE * sun_light); + light = sun_chroma + moon_chroma + PERSISTENT_AMBIANCE; + diffuse_light = + sun_chroma * mix(1.0, max(dot(-norm, sun_dir) * 0.6 + 0.4, 0.0), diffusion) + + moon_chroma * mix(1.0, pow(max(dot(-norm, moon_dir) * 2.0, 0.0), 2.0), diffusion) + + PERSISTENT_AMBIANCE; + ambient_light = vec3(SUN_AMBIANCE * sun_light + moon_light); } // This has been extracted into a function to allow quick exit when detecting a star. @@ -87,9 +114,83 @@ float is_star_at(vec3 dir) { return 0.0; } -vec3 get_sky_color(vec3 dir, float time_of_day, bool with_stars) { +const float CLOUD_AVG_HEIGHT = 1025.0; +const float CLOUD_HEIGHT_MIN = CLOUD_AVG_HEIGHT - 35.0; +const float CLOUD_HEIGHT_MAX = CLOUD_AVG_HEIGHT + 35.0; +const float CLOUD_THRESHOLD = 0.3; +const float CLOUD_SCALE = 1.0; +const float CLOUD_DENSITY = 100.0; + +float vsum(vec3 v) { + return v.x + v.y + v.z; +} + +vec2 cloud_at(vec3 pos) { + float tick_offs = 0.0 + + texture(t_noise, pos.xy * 0.0001 + tick.x * 0.001).x * 1.0 + + texture(t_noise, pos.xy * 0.000003).x * 5.0; + + float value = ( + 0.0 + + texture(t_noise, pos.xy / CLOUD_SCALE * 0.0003 + tick_offs).x + + texture(t_noise, pos.xy / CLOUD_SCALE * 0.0009 - tick_offs).x * 0.5 + + texture(t_noise, pos.xy / CLOUD_SCALE * 0.0025 - tick.x * 0.01).x * 0.25 + + texture(t_noise, pos.xy / CLOUD_SCALE * 0.008 + tick.x * 0.02).x * 0.1 + ) / 3.0; + + float density = max((value - CLOUD_THRESHOLD) - abs(pos.z - CLOUD_AVG_HEIGHT) / 500.0, 0.0) * CLOUD_DENSITY; + + float shade = ((pos.z - CLOUD_AVG_HEIGHT) / (CLOUD_AVG_HEIGHT - CLOUD_HEIGHT_MIN) + 0.5); + + return vec2(shade, density / (1.0 + vsum(abs(pos - cam_pos.xyz)) / 5000)); +} + +vec4 get_cloud_color(vec3 dir, vec3 origin, float time_of_day, float max_dist, float quality) { + + const float INCR = 0.06; + + float mind = (CLOUD_HEIGHT_MIN - origin.z) / dir.z; + float maxd = (CLOUD_HEIGHT_MAX - origin.z) / dir.z; + + float start = max(min(mind, maxd), 0.0); + float delta = min(abs(mind - maxd), max_dist); + + bool do_cast = true; + if (mind < 0.0 && maxd < 0.0) { + do_cast = false; + } + + float incr = INCR; + + float fuzz = sin(texture(t_noise, dir.xz * 100000.0).x * 100.0) * incr * delta; + + float cloud_shade = 1.0; + float passthrough = 1.0; + if (do_cast) { + for (float d = 0.0; d < 1.0; d += incr) { + float dist = start + d * delta; + dist += fuzz * min(pow(dist * 0.005, 2.0), 1.0); + + vec3 pos = origin + dir * min(dist, max_dist); + vec2 sample = cloud_at(pos); + + float integral = sample.y * incr; + passthrough *= max(1.0 - integral, 0.0); + cloud_shade = mix(cloud_shade, sample.x, passthrough * integral); + } + } + + float total_density = 1.0 - passthrough / (1.0 + delta * 0.0001); + + total_density = max(total_density - 1.0 / pow(max_dist, 0.25), 0.0); // Hack + + return vec4(vec3(cloud_shade), total_density); +} + +vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float quality, bool with_stars, out vec4 clouds) { // Sky color vec3 sun_dir = get_sun_dir(time_of_day); + vec3 moon_dir = get_moon_dir(time_of_day); // Add white dots for stars. Note these flicker and jump due to FXAA float star = 0.0; @@ -97,12 +198,33 @@ vec3 get_sky_color(vec3 dir, float time_of_day, bool with_stars) { star = is_star_at(dir); } + // Sun + const vec3 SUN_SURF_COLOR = vec3(1.5, 0.9, 0.35) * 200.0; + + vec3 sun_halo_color = mix( + SUN_HALO_DUSK, + SUN_HALO_DAY, + max(-sun_dir.z, 0) + ); + + vec3 sun_halo = pow(max(dot(dir, -sun_dir) + 0.1, 0.0), 8.0) * sun_halo_color; + vec3 sun_surf = pow(max(dot(dir, -sun_dir) - 0.001, 0.0), 3000.0) * SUN_SURF_COLOR; + vec3 sun_light = (sun_halo + sun_surf) * clamp(dir.z * 10.0, 0, 1); + + // Moon + const vec3 MOON_SURF_COLOR = vec3(0.7, 1.0, 1.5) * 500.0; + const vec3 MOON_HALO_COLOR = vec3(0.015, 0.015, 0.05); + + vec3 moon_halo = pow(max(dot(dir, -moon_dir) + 0.1, 0.0), 8.0) * MOON_HALO_COLOR; + vec3 moon_surf = pow(max(dot(dir, -moon_dir) - 0.001, 0.0), 3000.0) * MOON_SURF_COLOR; + vec3 moon_light = clamp(moon_halo + moon_surf, vec3(0), vec3(clamp(dir.z * 3.0, 0, 1))); + // Replaced all clamp(sun_dir, 0, 1) with max(sun_dir, 0) because sun_dir is calculated from sin and cos, which are never > 1 vec3 sky_top = mix( mix( - SKY_DUSK_TOP + star, - SKY_NIGHT_TOP + star, + SKY_DUSK_TOP + star / (1.0 + moon_surf * 100.0), + SKY_NIGHT_TOP + star / (1.0 + moon_surf * 100.0), max(pow(sun_dir.z, 0.2), 0) ), SKY_DAY_TOP, @@ -139,21 +261,18 @@ vec3 get_sky_color(vec3 dir, float time_of_day, bool with_stars) { max(dir.z, 0) ); - vec3 sun_halo_color = mix( - SUN_HALO_DUSK, - SUN_HALO_DAY, - max(-sun_dir.z, 0) - ); + // Approximate distance to fragment + float f_dist = distance(origin, f_pos); - // Sun + // Clouds + clouds = get_cloud_color(dir, origin, time_of_day, f_dist, quality); + clouds.rgb *= get_sun_brightness(sun_dir) * (sun_halo * 2.5 + get_sun_color(sun_dir)) + get_moon_brightness(moon_dir) * (moon_halo * 80.0 + get_moon_color(moon_dir)); - const vec3 SUN_SURF_COLOR = vec3(1.5, 0.9, 0.35) * 200.0; + if (f_dist > 5000.0) { + sky_color += sun_light + moon_light; + } - vec3 sun_halo = pow(max(dot(dir, -sun_dir) + 0.1, 0.0), 8.0) * sun_halo_color; - vec3 sun_surf = pow(max(dot(dir, -sun_dir) - 0.001, 0.0), 3000.0) * SUN_SURF_COLOR; - vec3 sun_light = (sun_halo + sun_surf) * clamp(dir.z * 10.0, 0, 1); - - return sky_color + sun_light; + return mix(sky_color, clouds.rgb, clouds.a); } float fog(vec3 f_pos, vec3 focus_pos, uint medium) { diff --git a/assets/voxygen/shaders/skybox-frag.glsl b/assets/voxygen/shaders/skybox-frag.glsl index 9277816577..ab39a37c3c 100644 --- a/assets/voxygen/shaders/skybox-frag.glsl +++ b/assets/voxygen/shaders/skybox-frag.glsl @@ -13,5 +13,6 @@ uniform u_locals { out vec4 tgt_color; void main() { - tgt_color = vec4(get_sky_color(normalize(f_pos), time_of_day.x, true), 1.0); + vec4 _clouds; + tgt_color = vec4(get_sky_color(normalize(f_pos), time_of_day.x, cam_pos.xyz, vec3(-100000), 1.0, true, _clouds), 1.0); } diff --git a/assets/voxygen/shaders/skybox-vert.glsl b/assets/voxygen/shaders/skybox-vert.glsl index c1816d4127..8cfe045eda 100644 --- a/assets/voxygen/shaders/skybox-vert.glsl +++ b/assets/voxygen/shaders/skybox-vert.glsl @@ -18,6 +18,6 @@ void main() { gl_Position = proj_mat * view_mat * - vec4(v_pos + cam_pos.xyz, 1); + vec4(v_pos * 100000.0 + cam_pos.xyz, 1); gl_Position.z = 0.0; } diff --git a/assets/voxygen/shaders/sprite-frag.glsl b/assets/voxygen/shaders/sprite-frag.glsl index d243cb5368..302bd0faeb 100644 --- a/assets/voxygen/shaders/sprite-frag.glsl +++ b/assets/voxygen/shaders/sprite-frag.glsl @@ -27,8 +27,9 @@ void main() { vec3 surf_color = illuminate(f_col, light, diffuse_light, ambient_light); float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x); - vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, true); - vec3 color = mix(surf_color, fog_color, fog_level); + vec4 clouds; + vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, cam_pos.xyz, f_pos, 0.5, true, clouds); + vec3 color = mix(mix(surf_color, fog_color, fog_level), clouds.rgb, clouds.a); tgt_color = vec4(color, 1.0 - clamp((distance(focus_pos.xy, f_pos.xy) - (RENDER_DIST - FADE_DIST)) / FADE_DIST, 0, 1)); } diff --git a/assets/voxygen/shaders/sprite-vert.glsl b/assets/voxygen/shaders/sprite-vert.glsl index fedbc0a749..6bbb5ea71f 100644 --- a/assets/voxygen/shaders/sprite-vert.glsl +++ b/assets/voxygen/shaders/sprite-vert.glsl @@ -53,4 +53,5 @@ void main() { proj_mat * view_mat * vec4(f_pos, 1); + gl_Position.z = 1.0 / (1.0 - gl_Position.z - 10.0); } diff --git a/assets/voxygen/shaders/terrain-frag.glsl b/assets/voxygen/shaders/terrain-frag.glsl index 7727afe185..0fb2811441 100644 --- a/assets/voxygen/shaders/terrain-frag.glsl +++ b/assets/voxygen/shaders/terrain-frag.glsl @@ -20,7 +20,7 @@ out vec4 tgt_color; void main() { // First 3 normals are negative, next 3 are positive - vec3 normals[6] = vec3[]( vec3(-1,0,0), vec3(0,-1,0), vec3(0,0,-1), vec3(1,0,0), vec3(0,1,0), vec3(0,0,1) ); + vec3 normals[6] = vec3[](vec3(-1,0,0), vec3(0,-1,0), vec3(0,0,-1), vec3(1,0,0), vec3(0,1,0), vec3(0,0,1)); // TODO: last 3 bits in v_pos_norm should be a number between 0 and 5, rather than 0-2 and a direction. uint norm_axis = (f_pos_norm >> 30) & 0x3u; @@ -40,8 +40,9 @@ void main() { vec3 surf_color = illuminate(srgb_to_linear(f_col), light, diffuse_light, ambient_light); float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x); - vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, true); - vec3 color = mix(surf_color, fog_color, fog_level); + vec4 clouds; + vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, cam_pos.xyz, f_pos, 1.0, true, clouds); + vec3 color = mix(mix(surf_color, fog_color, fog_level), clouds.rgb, clouds.a); tgt_color = vec4(color, 1.0); } diff --git a/assets/voxygen/shaders/terrain-vert.glsl b/assets/voxygen/shaders/terrain-vert.glsl index 61ef233cd2..cf273f6207 100644 --- a/assets/voxygen/shaders/terrain-vert.glsl +++ b/assets/voxygen/shaders/terrain-vert.glsl @@ -25,6 +25,7 @@ void main() { ) + model_offs; f_pos.z *= min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0); + f_pos.z -= 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0); f_col = vec3( float((v_col_light >> 8) & 0xFFu), @@ -40,4 +41,5 @@ void main() { proj_mat * view_mat * vec4(f_pos, 1); + gl_Position.z = 1.0 / (1.0 - gl_Position.z - 10.0); } diff --git a/assets/voxygen/texture/noise.png b/assets/voxygen/texture/noise.png new file mode 100644 index 0000000000..faef1bed6b --- /dev/null +++ b/assets/voxygen/texture/noise.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9c41eb6e06bf9fc61135ab9009bf81a6eaf55f34101d698032650188187670d4 +size 9532 diff --git a/voxygen/src/render/pipelines/figure.rs b/voxygen/src/render/pipelines/figure.rs index 246d294c2f..2a01f1e841 100644 --- a/voxygen/src/render/pipelines/figure.rs +++ b/voxygen/src/render/pipelines/figure.rs @@ -40,6 +40,8 @@ gfx_defines! { lights: gfx::ConstantBuffer = "u_lights", shadows: gfx::ConstantBuffer = "u_shadows", + noise: gfx::TextureSampler = "t_noise", + tgt_color: gfx::RenderTarget = "tgt_color", tgt_depth: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE, } diff --git a/voxygen/src/render/pipelines/fluid.rs b/voxygen/src/render/pipelines/fluid.rs index e387437da1..67264323ad 100644 --- a/voxygen/src/render/pipelines/fluid.rs +++ b/voxygen/src/render/pipelines/fluid.rs @@ -29,6 +29,7 @@ gfx_defines! { lights: gfx::ConstantBuffer = "u_lights", shadows: gfx::ConstantBuffer = "u_shadows", + noise: gfx::TextureSampler = "t_noise", waves: gfx::TextureSampler<[f32; 4]> = "t_waves", tgt_color: gfx::BlendTarget = ("tgt_color", ColorMask::all(), gfx::preset::blend::ALPHA), diff --git a/voxygen/src/render/pipelines/skybox.rs b/voxygen/src/render/pipelines/skybox.rs index 35aed1d861..030a1608fd 100644 --- a/voxygen/src/render/pipelines/skybox.rs +++ b/voxygen/src/render/pipelines/skybox.rs @@ -28,8 +28,10 @@ gfx_defines! { locals: gfx::ConstantBuffer = "u_locals", globals: gfx::ConstantBuffer = "u_globals", + noise: gfx::TextureSampler = "t_noise", + tgt_color: gfx::RenderTarget = "tgt_color", - tgt_depth: gfx::DepthTarget = gfx::preset::depth::PASS_TEST, + tgt_depth: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE, } } diff --git a/voxygen/src/render/pipelines/sprite.rs b/voxygen/src/render/pipelines/sprite.rs index be80c49afd..9dcfef88c9 100644 --- a/voxygen/src/render/pipelines/sprite.rs +++ b/voxygen/src/render/pipelines/sprite.rs @@ -38,6 +38,8 @@ gfx_defines! { lights: gfx::ConstantBuffer = "u_lights", shadows: gfx::ConstantBuffer = "u_shadows", + noise: gfx::TextureSampler = "t_noise", + tgt_color: gfx::BlendTarget = ("tgt_color", ColorMask::all(), gfx::preset::blend::ALPHA), tgt_depth: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE, } diff --git a/voxygen/src/render/pipelines/terrain.rs b/voxygen/src/render/pipelines/terrain.rs index cb264261e2..073185630e 100644 --- a/voxygen/src/render/pipelines/terrain.rs +++ b/voxygen/src/render/pipelines/terrain.rs @@ -34,6 +34,8 @@ gfx_defines! { lights: gfx::ConstantBuffer = "u_lights", shadows: gfx::ConstantBuffer = "u_shadows", + noise: gfx::TextureSampler = "t_noise", + tgt_color: gfx::RenderTarget = "tgt_color", tgt_depth: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE, } diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 94c2330915..7097be53cd 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -72,6 +72,8 @@ pub struct Renderer { shader_reload_indicator: ReloadIndicator, + noise_tex: Texture<(gfx::format::R8, gfx::format::Unorm)>, + aa_mode: AaMode, } @@ -102,6 +104,13 @@ impl Renderer { let sampler = factory.create_sampler_linear(); + let noise_tex = Texture::new( + &mut factory, + &assets::load_expect("voxygen.texture.noise"), + Some(gfx::texture::FilterMethod::Trilinear), + Some(gfx::texture::WrapMode::Tile), + )?; + Ok(Self { device, encoder: factory.create_command_buffer().into(), @@ -126,6 +135,8 @@ impl Renderer { shader_reload_indicator, + noise_tex, + aa_mode, }) } @@ -351,27 +362,24 @@ impl Renderer { } /// Create a new texture from the provided image. - pub fn create_texture( + pub fn create_texture( &mut self, image: &image::DynamicImage, filter_method: Option, wrap_mode: Option, - ) -> Result, RenderError> { + ) -> Result { Texture::new(&mut self.factory, image, filter_method, wrap_mode) } /// Create a new dynamic texture (gfx::memory::Usage::Dynamic) with the specified dimensions. - pub fn create_dynamic_texture( - &mut self, - dims: Vec2, - ) -> Result, RenderError> { + pub fn create_dynamic_texture(&mut self, dims: Vec2) -> Result { Texture::new_dynamic(&mut self.factory, dims.x, dims.y) } /// Update a texture with the provided offset, size, and data. - pub fn update_texture( + pub fn update_texture( &mut self, - texture: &Texture

, + texture: &Texture, offset: [u16; 2], size: [u16; 2], data: &[[u8; 4]], @@ -444,6 +452,7 @@ impl Renderer { vbuf: model.vbuf.clone(), locals: locals.buf.clone(), globals: globals.buf.clone(), + noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), tgt_color: self.tgt_color_view.clone(), tgt_depth: self.tgt_depth_view.clone(), }, @@ -476,6 +485,7 @@ impl Renderer { bones: bones.buf.clone(), lights: lights.buf.clone(), shadows: shadows.buf.clone(), + noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), tgt_color: self.tgt_color_view.clone(), tgt_depth: self.tgt_depth_view.clone(), }, @@ -506,6 +516,7 @@ impl Renderer { globals: globals.buf.clone(), lights: lights.buf.clone(), shadows: shadows.buf.clone(), + noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), tgt_color: self.tgt_color_view.clone(), tgt_depth: self.tgt_depth_view.clone(), }, @@ -520,7 +531,7 @@ impl Renderer { locals: &Consts, lights: &Consts, shadows: &Consts, - waves: &Texture, + waves: &Texture, ) { self.encoder.draw( &gfx::Slice { @@ -537,6 +548,7 @@ impl Renderer { globals: globals.buf.clone(), lights: lights.buf.clone(), shadows: shadows.buf.clone(), + noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), waves: (waves.srv.clone(), waves.sampler.clone()), tgt_color: self.tgt_color_view.clone(), tgt_depth: self.tgt_depth_view.clone(), @@ -568,6 +580,7 @@ impl Renderer { globals: globals.buf.clone(), lights: lights.buf.clone(), shadows: shadows.buf.clone(), + noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), tgt_color: self.tgt_color_view.clone(), tgt_depth: self.tgt_depth_view.clone(), }, @@ -578,7 +591,7 @@ impl Renderer { pub fn render_ui_element( &mut self, model: &Model, - tex: &Texture, + tex: &Texture, scissor: Aabr, globals: &Consts, locals: &Consts, diff --git a/voxygen/src/render/texture.rs b/voxygen/src/render/texture.rs index 66d0af88c4..8bd5c3b8a8 100644 --- a/voxygen/src/render/texture.rs +++ b/voxygen/src/render/texture.rs @@ -1,26 +1,31 @@ -use super::{gfx_backend, Pipeline, RenderError}; +use super::{gfx_backend, RenderError}; use gfx::{self, traits::Factory}; use image::{DynamicImage, GenericImageView}; -use std::marker::PhantomData; use vek::Vec2; -type ShaderFormat = (gfx::format::R8_G8_B8_A8, gfx::format::Srgb); +type DefaultShaderFormat = (gfx::format::R8_G8_B8_A8, gfx::format::Srgb); /// Represents an image that has been uploaded to the GPU. -pub struct Texture { - pub tex: gfx::handle::Texture< - gfx_backend::Resources, - ::Surface, - >, +pub struct Texture +where + F::Surface: gfx::format::TextureSurface, + F::Channel: gfx::format::TextureChannel, + ::DataType: Copy, +{ + pub tex: gfx::handle::Texture::Surface>, pub srv: gfx::handle::ShaderResourceView< gfx_backend::Resources, - ::View, + ::View, >, pub sampler: gfx::handle::Sampler, - _phantom: PhantomData

, } -impl Texture

{ +impl Texture +where + F::Surface: gfx::format::TextureSurface, + F::Channel: gfx::format::TextureChannel, + ::DataType: Copy, +{ pub fn new( factory: &mut gfx_backend::Factory, image: &DynamicImage, @@ -28,14 +33,14 @@ impl Texture

{ wrap_mode: Option, ) -> Result { let (tex, srv) = factory - .create_texture_immutable_u8::( + .create_texture_immutable_u8::( gfx::texture::Kind::D2( image.width() as u16, image.height() as u16, gfx::texture::AaMode::Single, ), gfx::texture::Mipmap::Provided, - &[&image.to_rgba().into_raw()], + &[&image.raw_pixels()], ) .map_err(|err| RenderError::CombinedError(err))?; @@ -46,7 +51,6 @@ impl Texture

{ filter_method.unwrap_or(gfx::texture::FilterMethod::Scale), wrap_mode.unwrap_or(gfx::texture::WrapMode::Clamp), )), - _phantom: PhantomData, }) } @@ -64,16 +68,12 @@ impl Texture

{ 1 as gfx::texture::Level, gfx::memory::Bind::SHADER_RESOURCE, gfx::memory::Usage::Dynamic, - Some(<::Channel as gfx::format::ChannelTyped>::get_channel_type()), + Some(<::Channel as gfx::format::ChannelTyped>::get_channel_type()), ) .map_err(|err| RenderError::CombinedError(gfx::CombinedError::Texture(err)))?; let srv = factory - .view_texture_as_shader_resource::( - &tex, - (0, 0), - gfx::format::Swizzle::new(), - ) + .view_texture_as_shader_resource::(&tex, (0, 0), gfx::format::Swizzle::new()) .map_err(|err| RenderError::CombinedError(gfx::CombinedError::Resource(err)))?; Ok(Self { @@ -83,7 +83,6 @@ impl Texture

{ gfx::texture::FilterMethod::Scale, gfx::texture::WrapMode::Clamp, )), - _phantom: PhantomData, }) } @@ -93,7 +92,7 @@ impl Texture

{ encoder: &mut gfx::Encoder, offset: [u16; 2], size: [u16; 2], - data: &[[u8; 4]], + data: &[::DataType], ) -> Result<(), RenderError> { let info = gfx::texture::ImageInfoCommon { xoffset: offset[0], @@ -106,7 +105,7 @@ impl Texture

{ mipmap: 0, }; encoder - .update_texture::<::Surface, ShaderFormat>( + .update_texture::<::Surface, F>( &self.tex, None, info, data, ) .map_err(|err| RenderError::TexUpdateError(err)) diff --git a/voxygen/src/scene/camera.rs b/voxygen/src/scene/camera.rs index a759153e20..6af3c3eb89 100644 --- a/voxygen/src/scene/camera.rs +++ b/voxygen/src/scene/camera.rs @@ -5,7 +5,7 @@ use std::f32::consts::PI; use vek::*; const NEAR_PLANE: f32 = 0.5; -const FAR_PLANE: f32 = 5000.0; +const FAR_PLANE: f32 = 100000.0; const FIRST_PERSON_INTERP_TIME: f32 = 0.05; const THIRD_PERSON_INTERP_TIME: f32 = 0.1; diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index bf3d6ef7b7..41f86ed39a 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -293,9 +293,6 @@ impl Scene { /// Render the scene using the provided `Renderer`. pub fn render(&mut self, renderer: &mut Renderer, client: &mut Client) { - // Render the skybox first (it appears over everything else so must be rendered first). - renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals); - // Render terrain and figures. self.figure_mgr.render( renderer, @@ -313,6 +310,17 @@ impl Scene { self.camera.get_focus_pos(), ); + // Render the skybox. + renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals); + + self.terrain.render_translucent( + renderer, + &self.globals, + &self.lights, + &self.shadows, + self.camera.get_focus_pos(), + ); + renderer.render_post_process( &self.postprocess.model, &self.globals, diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 3a7c93f6bf..02ffd92ec1 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -212,7 +212,7 @@ pub struct Terrain { // GPU data sprite_models: HashMap<(BlockKind, usize), Model>, - waves: Texture, + waves: Texture, phantom: PhantomData, } @@ -1092,6 +1092,32 @@ impl Terrain { ); } } + } + + pub fn render_translucent( + &self, + renderer: &mut Renderer, + globals: &Consts, + lights: &Consts, + shadows: &Consts, + focus_pos: Vec3, + ) { + let focus_chunk = Vec2::from(focus_pos).map2(TerrainChunk::RECT_SIZE, |e: f32, sz| { + (e as i32).div_euclid(sz as i32) + }); + + let chunks = &self.chunks; + let chunk_iter = Spiral2d::new() + .scan(0, |n, rpos| { + if *n >= chunks.len() { + None + } else { + *n += 1; + let pos = focus_chunk + rpos; + Some(chunks.get(&pos).map(|c| (pos, c))) + } + }) + .filter_map(|x| x); // Terrain sprites for (pos, chunk) in chunk_iter.clone() { diff --git a/voxygen/src/ui/cache.rs b/voxygen/src/ui/cache.rs index 51727c39e2..b4bb7b61cb 100644 --- a/voxygen/src/ui/cache.rs +++ b/voxygen/src/ui/cache.rs @@ -1,6 +1,6 @@ use super::graphic::{Graphic, GraphicCache, Id as GraphicId}; use crate::{ - render::{Renderer, Texture, UiPipeline}, + render::{Renderer, Texture}, Error, }; use conrod_core::text::GlyphCache; @@ -14,7 +14,7 @@ const POSITION_TOLERANCE: f32 = 0.1; pub struct Cache { glyph_cache: GlyphCache<'static>, - glyph_cache_tex: Texture, + glyph_cache_tex: Texture, graphic_cache: GraphicCache, } @@ -38,10 +38,10 @@ impl Cache { graphic_cache: GraphicCache::new(renderer), }) } - pub fn glyph_cache_tex(&self) -> &Texture { + pub fn glyph_cache_tex(&self) -> &Texture { &self.glyph_cache_tex } - pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphCache<'static>, &Texture) { + pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphCache<'static>, &Texture) { (&mut self.glyph_cache, &self.glyph_cache_tex) } pub fn graphic_cache(&self) -> &GraphicCache { diff --git a/voxygen/src/ui/graphic/mod.rs b/voxygen/src/ui/graphic/mod.rs index 7bdb59c3db..138a54d52e 100644 --- a/voxygen/src/ui/graphic/mod.rs +++ b/voxygen/src/ui/graphic/mod.rs @@ -1,6 +1,6 @@ mod renderer; -use crate::render::{Renderer, Texture, UiPipeline}; +use crate::render::{Renderer, Texture}; use dot_vox::DotVoxData; use guillotiere::{size2, SimpleAtlasAllocator}; use hashbrown::HashMap; @@ -84,7 +84,7 @@ pub struct GraphicCache { // Atlases with the index of their texture in the textures vec atlases: Vec<(SimpleAtlasAllocator, usize)>, - textures: Vec>, + textures: Vec, // Stores the location of graphics rendered at a particular resolution and cached on the cpu cache_map: HashMap, } @@ -131,7 +131,7 @@ impl GraphicCache { self.graphic_map.get(&id) } /// Used to aquire textures for rendering - pub fn get_tex(&self, id: TexId) -> &Texture { + pub fn get_tex(&self, id: TexId) -> &Texture { self.textures.get(id.0).expect("Invalid TexId used") } pub fn clear_cache(&mut self, renderer: &mut Renderer) { @@ -302,7 +302,7 @@ fn draw_graphic(graphic_map: &GraphicMap, graphic_id: Id, dims: Vec2) -> Op } } -fn create_atlas_texture(renderer: &mut Renderer) -> (SimpleAtlasAllocator, Texture) { +fn create_atlas_texture(renderer: &mut Renderer) -> (SimpleAtlasAllocator, Texture) { let (w, h) = renderer.get_resolution().into_tuple(); let max_texture_size = renderer.max_texture_size(); @@ -326,12 +326,7 @@ fn aabr_from_alloc_rect(rect: guillotiere::Rectangle) -> Aabr { } } -fn upload_image( - renderer: &mut Renderer, - aabr: Aabr, - tex: &Texture, - image: &RgbaImage, -) { +fn upload_image(renderer: &mut Renderer, aabr: Aabr, tex: &Texture, image: &RgbaImage) { let offset = aabr.min.into_array(); let size = aabr.size().into_array(); if let Err(err) = renderer.update_texture(