diff --git a/assets/voxygen/shaders/figure-frag.glsl b/assets/voxygen/shaders/figure-frag.glsl index 7803dadb3f..e15db63fe1 100644 --- a/assets/voxygen/shaders/figure-frag.glsl +++ b/assets/voxygen/shaders/figure-frag.glsl @@ -32,7 +32,7 @@ void main() { vec3 surf_color = srgb_to_linear(model_col.rgb * f_col) * 4.0 * 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); + 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); tgt_color = vec4(color, 1.0); diff --git a/assets/voxygen/shaders/fluid-frag.glsl b/assets/voxygen/shaders/fluid-frag.glsl index 8d060ca3da..667098ddc6 100644 --- a/assets/voxygen/shaders/fluid-frag.glsl +++ b/assets/voxygen/shaders/fluid-frag.glsl @@ -41,14 +41,14 @@ void main() { vec3 surf_color = f_col * 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); + vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, true); vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz); 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) * f_light; + vec3 reflect_color = get_sky_color(reflect_ray_dir, time_of_day.x, false) * f_light; // 0 = 100% reflection, 1 = translucent water float passthrough = pow(dot(faceforward(norm, norm, cam_to_frag), -cam_to_frag), 1.0); diff --git a/assets/voxygen/shaders/include/sky.glsl b/assets/voxygen/shaders/include/sky.glsl index aa38b4a337..1310f82f87 100644 --- a/assets/voxygen/shaders/include/sky.glsl +++ b/assets/voxygen/shaders/include/sky.glsl @@ -5,12 +5,12 @@ 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 DAY_LIGHT = vec3(0.75, 0.75, 1.0); +const vec3 DAY_LIGHT = vec3(1.3, 0.9, 1.1); -const vec3 SKY_DUSK_TOP = vec3(0.21, 0.28, 0.50); -const vec3 SKY_DUSK_MID = vec3(0.68, 0.03, 0.0); -const vec3 SKY_DUSK_BOT = vec3(0.0, 0.0, 0.13); -const vec3 DUSK_LIGHT = vec3(0.95, 0.6, 0.4); +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 DUSK_LIGHT = vec3(3.0, 0.65, 0.3); const vec3 SKY_NIGHT_TOP = vec3(0.001, 0.001, 0.0025); const vec3 SKY_NIGHT_MID = vec3(0.001, 0.005, 0.02); @@ -33,7 +33,7 @@ float get_sun_brightness(vec3 sun_dir) { const float PERSISTENT_AMBIANCE = 0.008; vec3 get_sun_diffuse(vec3 norm, float time_of_day) { - const float SUN_AMBIANCE = 0.075; + const float SUN_AMBIANCE = 0.15; vec3 sun_dir = get_sun_dir(time_of_day); @@ -41,7 +41,7 @@ vec3 get_sun_diffuse(vec3 norm, float time_of_day) { // clamp() changed to max() as sun_dir.z is produced from a cos() function and therefore never greater than 1 - vec3 sun_color = normalize(mix( + vec3 sun_color = mix( mix( DUSK_LIGHT, NIGHT_LIGHT, @@ -49,7 +49,7 @@ vec3 get_sun_diffuse(vec3 norm, float time_of_day) { ), DAY_LIGHT, max(-sun_dir.z, 0) - )); + ); vec3 diffuse_light = (SUN_AMBIANCE + max(dot(-norm, sun_dir), 0.0) * sun_color) * sun_light + PERSISTENT_AMBIANCE; @@ -83,12 +83,15 @@ float is_star_at(vec3 dir) { return 0.0; } -vec3 get_sky_color(vec3 dir, float time_of_day) { +vec3 get_sky_color(vec3 dir, float time_of_day, bool with_stars) { // Sky color vec3 sun_dir = get_sun_dir(time_of_day); // Add white dots for stars. Note these flicker and jump due to FXAA - float star = is_star_at(dir); + float star = 0.0; + if (with_stars) { + star = is_star_at(dir); + } // 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 @@ -134,8 +137,8 @@ vec3 get_sky_color(vec3 dir, float time_of_day) { // Sun - const vec3 SUN_HALO_COLOR = vec3(1.0, 0.35, 0.1) * 0.3; - const vec3 SUN_SURF_COLOR = vec3(1.0, 0.9, 0.35) * 200.0; + const vec3 SUN_HALO_COLOR = vec3(1.5, 0.35, 0.0) * 0.3; + const vec3 SUN_SURF_COLOR = vec3(1.5, 0.9, 0.35) * 200.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.0045, 0.0), 1000.0) * SUN_SURF_COLOR; diff --git a/assets/voxygen/shaders/skybox-frag.glsl b/assets/voxygen/shaders/skybox-frag.glsl index 7cabdd09ec..9277816577 100644 --- a/assets/voxygen/shaders/skybox-frag.glsl +++ b/assets/voxygen/shaders/skybox-frag.glsl @@ -13,5 +13,5 @@ uniform u_locals { out vec4 tgt_color; void main() { - tgt_color = vec4(get_sky_color(normalize(f_pos), time_of_day.x), 1.0); + tgt_color = vec4(get_sky_color(normalize(f_pos), time_of_day.x, true), 1.0); } diff --git a/assets/voxygen/shaders/sprite-frag.glsl b/assets/voxygen/shaders/sprite-frag.glsl new file mode 100644 index 0000000000..4a6e0b4ba8 --- /dev/null +++ b/assets/voxygen/shaders/sprite-frag.glsl @@ -0,0 +1,27 @@ +#version 330 core + +#include + +in vec3 f_pos; +flat in vec3 f_norm; +in vec3 f_col; +in float f_light; + +out vec4 tgt_color; + +#include +#include + +const float RENDER_DIST = 112.0; +const float FADE_DIST = 32.0; + +void main() { + vec3 light = get_sun_diffuse(f_norm, time_of_day.x) * f_light + light_at(f_pos, f_norm); + vec3 surf_color = f_col * 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); + + 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 new file mode 100644 index 0000000000..b6e86daea8 --- /dev/null +++ b/assets/voxygen/shaders/sprite-vert.glsl @@ -0,0 +1,49 @@ +#version 330 core + +#include +#include + +in vec3 v_pos; +in vec3 v_norm; +in vec3 v_col; +in vec4 inst_mat0; +in vec4 inst_mat1; +in vec4 inst_mat2; +in vec4 inst_mat3; +in vec3 inst_col; +in float inst_wind_sway; + +out vec3 f_pos; +flat out vec3 f_norm; +out vec3 f_col; +out float f_light; + +const float SCALE = 1.0 / 11.0; + +void main() { + mat4 inst_mat; + inst_mat[0] = inst_mat0; + inst_mat[1] = inst_mat1; + inst_mat[2] = inst_mat2; + inst_mat[3] = inst_mat3; + + f_pos = (inst_mat * vec4(v_pos * SCALE, 1)).xyz; + + // Wind waving + f_pos += inst_wind_sway * vec3( + sin(tick.x * 1.5 + f_pos.y * 0.1) * sin(tick.x * 0.35), + sin(tick.x * 1.5 + f_pos.x * 0.1) * sin(tick.x * 0.25), + 0.0 + ) * pow(v_pos.z * SCALE, 1.3) * 0.2; + + f_norm = (inst_mat * vec4(v_norm, 0)).xyz; + + f_col = v_col * inst_col; + + f_light = 1.0; + + gl_Position = + proj_mat * + view_mat * + vec4(f_pos, 1); +} diff --git a/assets/voxygen/shaders/terrain-frag.glsl b/assets/voxygen/shaders/terrain-frag.glsl index 55a7018dd7..5a0671054e 100644 --- a/assets/voxygen/shaders/terrain-frag.glsl +++ b/assets/voxygen/shaders/terrain-frag.glsl @@ -22,7 +22,7 @@ void main() { vec3 surf_color = f_col * 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); + 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); tgt_color = vec4(color, 1.0); diff --git a/assets/voxygen/voxel/sprite/cacti/barrel_cactus.vox b/assets/voxygen/voxel/sprite/cacti/barrel_cactus.vox new file mode 100644 index 0000000000..0d89f0a4cb Binary files /dev/null and b/assets/voxygen/voxel/sprite/cacti/barrel_cactus.vox differ diff --git a/assets/voxygen/voxel/sprite/cacti/large_cactus.vox b/assets/voxygen/voxel/sprite/cacti/large_cactus.vox new file mode 100644 index 0000000000..3a2d5e6dd5 Binary files /dev/null and b/assets/voxygen/voxel/sprite/cacti/large_cactus.vox differ diff --git a/assets/voxygen/voxel/sprite/flowers/flower_blue_1.vox b/assets/voxygen/voxel/sprite/flowers/flower_blue_1.vox new file mode 100644 index 0000000000..d7b79d04a4 Binary files /dev/null and b/assets/voxygen/voxel/sprite/flowers/flower_blue_1.vox differ diff --git a/assets/voxygen/voxel/sprite/flowers/flower_blue_2.vox b/assets/voxygen/voxel/sprite/flowers/flower_blue_2.vox new file mode 100644 index 0000000000..54fb972745 Binary files /dev/null and b/assets/voxygen/voxel/sprite/flowers/flower_blue_2.vox differ diff --git a/assets/voxygen/voxel/sprite/flowers/flower_pink_1.vox b/assets/voxygen/voxel/sprite/flowers/flower_pink_1.vox new file mode 100644 index 0000000000..cf9bbf0605 Binary files /dev/null and b/assets/voxygen/voxel/sprite/flowers/flower_pink_1.vox differ diff --git a/assets/voxygen/voxel/sprite/flowers/flower_pink_2.vox b/assets/voxygen/voxel/sprite/flowers/flower_pink_2.vox new file mode 100644 index 0000000000..cb963ef509 Binary files /dev/null and b/assets/voxygen/voxel/sprite/flowers/flower_pink_2.vox differ diff --git a/assets/voxygen/voxel/sprite/flowers/flower_pink_3.vox b/assets/voxygen/voxel/sprite/flowers/flower_pink_3.vox new file mode 100644 index 0000000000..fc850f56d3 Binary files /dev/null and b/assets/voxygen/voxel/sprite/flowers/flower_pink_3.vox differ diff --git a/assets/voxygen/voxel/sprite/flowers/flower_purple_1.vox b/assets/voxygen/voxel/sprite/flowers/flower_purple_1.vox new file mode 100644 index 0000000000..bc590c1a07 Binary files /dev/null and b/assets/voxygen/voxel/sprite/flowers/flower_purple_1.vox differ diff --git a/assets/voxygen/voxel/sprite/flowers/flower_red_1.vox b/assets/voxygen/voxel/sprite/flowers/flower_red_1.vox new file mode 100644 index 0000000000..a35c159086 Binary files /dev/null and b/assets/voxygen/voxel/sprite/flowers/flower_red_1.vox differ diff --git a/assets/voxygen/voxel/sprite/flowers/flower_white_1.vox b/assets/voxygen/voxel/sprite/flowers/flower_white_1.vox new file mode 100644 index 0000000000..a6de231553 Binary files /dev/null and b/assets/voxygen/voxel/sprite/flowers/flower_white_1.vox differ diff --git a/assets/voxygen/voxel/sprite/flowers/flower_yellow_1.vox b/assets/voxygen/voxel/sprite/flowers/flower_yellow_1.vox new file mode 100644 index 0000000000..c52bc571f6 Binary files /dev/null and b/assets/voxygen/voxel/sprite/flowers/flower_yellow_1.vox differ diff --git a/assets/voxygen/voxel/sprite/flowers/sunflower_1.vox b/assets/voxygen/voxel/sprite/flowers/sunflower_1.vox new file mode 100644 index 0000000000..864a65c77e Binary files /dev/null and b/assets/voxygen/voxel/sprite/flowers/sunflower_1.vox differ diff --git a/assets/voxygen/voxel/sprite/flowers/sunflower_2.vox b/assets/voxygen/voxel/sprite/flowers/sunflower_2.vox new file mode 100644 index 0000000000..c76a09a11f Binary files /dev/null and b/assets/voxygen/voxel/sprite/flowers/sunflower_2.vox differ diff --git a/assets/voxygen/voxel/sprite/fruit/apple.vox b/assets/voxygen/voxel/sprite/fruit/apple.vox new file mode 100644 index 0000000000..860e0fb3b8 Binary files /dev/null and b/assets/voxygen/voxel/sprite/fruit/apple.vox differ diff --git a/assets/voxygen/voxel/sprite/fruit/apple_half.vox b/assets/voxygen/voxel/sprite/fruit/apple_half.vox new file mode 100644 index 0000000000..58cfcb80cf Binary files /dev/null and b/assets/voxygen/voxel/sprite/fruit/apple_half.vox differ diff --git a/assets/voxygen/voxel/sprite/grass/grass_long_1.vox b/assets/voxygen/voxel/sprite/grass/grass_long_1.vox new file mode 100644 index 0000000000..af20632807 Binary files /dev/null and b/assets/voxygen/voxel/sprite/grass/grass_long_1.vox differ diff --git a/assets/voxygen/voxel/sprite/grass/grass_long_2.vox b/assets/voxygen/voxel/sprite/grass/grass_long_2.vox new file mode 100644 index 0000000000..4d279b6771 Binary files /dev/null and b/assets/voxygen/voxel/sprite/grass/grass_long_2.vox differ diff --git a/assets/voxygen/voxel/sprite/grass/grass_long_3.vox b/assets/voxygen/voxel/sprite/grass/grass_long_3.vox new file mode 100644 index 0000000000..fc5106a6c0 Binary files /dev/null and b/assets/voxygen/voxel/sprite/grass/grass_long_3.vox differ diff --git a/assets/voxygen/voxel/sprite/grass/grass_long_4.vox b/assets/voxygen/voxel/sprite/grass/grass_long_4.vox new file mode 100644 index 0000000000..1837f425e0 Binary files /dev/null and b/assets/voxygen/voxel/sprite/grass/grass_long_4.vox differ diff --git a/assets/voxygen/voxel/sprite/grass/grass_long_5.vox b/assets/voxygen/voxel/sprite/grass/grass_long_5.vox new file mode 100644 index 0000000000..936b4e2ce0 Binary files /dev/null and b/assets/voxygen/voxel/sprite/grass/grass_long_5.vox differ diff --git a/assets/voxygen/voxel/sprite/grass/grass_med_1.vox b/assets/voxygen/voxel/sprite/grass/grass_med_1.vox new file mode 100644 index 0000000000..aa8307cbb8 Binary files /dev/null and b/assets/voxygen/voxel/sprite/grass/grass_med_1.vox differ diff --git a/assets/voxygen/voxel/sprite/grass/grass_med_2.vox b/assets/voxygen/voxel/sprite/grass/grass_med_2.vox new file mode 100644 index 0000000000..25e613a212 Binary files /dev/null and b/assets/voxygen/voxel/sprite/grass/grass_med_2.vox differ diff --git a/assets/voxygen/voxel/sprite/grass/grass_med_3.vox b/assets/voxygen/voxel/sprite/grass/grass_med_3.vox new file mode 100644 index 0000000000..eee83cec1e Binary files /dev/null and b/assets/voxygen/voxel/sprite/grass/grass_med_3.vox differ diff --git a/assets/voxygen/voxel/sprite/grass/grass_med_4.vox b/assets/voxygen/voxel/sprite/grass/grass_med_4.vox new file mode 100644 index 0000000000..4fa252d061 Binary files /dev/null and b/assets/voxygen/voxel/sprite/grass/grass_med_4.vox differ diff --git a/assets/voxygen/voxel/sprite/grass/grass_med_5.vox b/assets/voxygen/voxel/sprite/grass/grass_med_5.vox new file mode 100644 index 0000000000..76ee74367a Binary files /dev/null and b/assets/voxygen/voxel/sprite/grass/grass_med_5.vox differ diff --git a/assets/voxygen/voxel/sprite/grass/grass_short_1.vox b/assets/voxygen/voxel/sprite/grass/grass_short_1.vox new file mode 100644 index 0000000000..20c5ad640b Binary files /dev/null and b/assets/voxygen/voxel/sprite/grass/grass_short_1.vox differ diff --git a/assets/voxygen/voxel/sprite/grass/grass_short_2.vox b/assets/voxygen/voxel/sprite/grass/grass_short_2.vox new file mode 100644 index 0000000000..02af793207 Binary files /dev/null and b/assets/voxygen/voxel/sprite/grass/grass_short_2.vox differ diff --git a/assets/voxygen/voxel/sprite/grass/grass_short_3.vox b/assets/voxygen/voxel/sprite/grass/grass_short_3.vox new file mode 100644 index 0000000000..563005778b Binary files /dev/null and b/assets/voxygen/voxel/sprite/grass/grass_short_3.vox differ diff --git a/assets/voxygen/voxel/sprite/grass/grass_short_4.vox b/assets/voxygen/voxel/sprite/grass/grass_short_4.vox new file mode 100644 index 0000000000..8f287fef1a Binary files /dev/null and b/assets/voxygen/voxel/sprite/grass/grass_short_4.vox differ diff --git a/assets/voxygen/voxel/sprite/grass/grass_short_5.vox b/assets/voxygen/voxel/sprite/grass/grass_short_5.vox new file mode 100644 index 0000000000..24a92ec150 Binary files /dev/null and b/assets/voxygen/voxel/sprite/grass/grass_short_5.vox differ diff --git a/assets/voxygen/voxel/sprite/velorite_small/velorite_1.vox b/assets/voxygen/voxel/sprite/velorite_small/velorite_1.vox new file mode 100644 index 0000000000..76cb76ddab Binary files /dev/null and b/assets/voxygen/voxel/sprite/velorite_small/velorite_1.vox differ diff --git a/assets/voxygen/voxel/sprite/velorite_small/velorite_10.vox b/assets/voxygen/voxel/sprite/velorite_small/velorite_10.vox new file mode 100644 index 0000000000..37cbba521a Binary files /dev/null and b/assets/voxygen/voxel/sprite/velorite_small/velorite_10.vox differ diff --git a/assets/voxygen/voxel/sprite/velorite_small/velorite_2.vox b/assets/voxygen/voxel/sprite/velorite_small/velorite_2.vox new file mode 100644 index 0000000000..cba1e4b955 Binary files /dev/null and b/assets/voxygen/voxel/sprite/velorite_small/velorite_2.vox differ diff --git a/assets/voxygen/voxel/sprite/velorite_small/velorite_3.vox b/assets/voxygen/voxel/sprite/velorite_small/velorite_3.vox new file mode 100644 index 0000000000..2a18293a4b Binary files /dev/null and b/assets/voxygen/voxel/sprite/velorite_small/velorite_3.vox differ diff --git a/assets/voxygen/voxel/sprite/velorite_small/velorite_4.vox b/assets/voxygen/voxel/sprite/velorite_small/velorite_4.vox new file mode 100644 index 0000000000..7275f215ae Binary files /dev/null and b/assets/voxygen/voxel/sprite/velorite_small/velorite_4.vox differ diff --git a/assets/voxygen/voxel/sprite/velorite_small/velorite_5.vox b/assets/voxygen/voxel/sprite/velorite_small/velorite_5.vox new file mode 100644 index 0000000000..2f689c9074 Binary files /dev/null and b/assets/voxygen/voxel/sprite/velorite_small/velorite_5.vox differ diff --git a/assets/voxygen/voxel/sprite/velorite_small/velorite_6.vox b/assets/voxygen/voxel/sprite/velorite_small/velorite_6.vox new file mode 100644 index 0000000000..de8078669a Binary files /dev/null and b/assets/voxygen/voxel/sprite/velorite_small/velorite_6.vox differ diff --git a/assets/voxygen/voxel/sprite/velorite_small/velorite_7.vox b/assets/voxygen/voxel/sprite/velorite_small/velorite_7.vox new file mode 100644 index 0000000000..f0811626cd Binary files /dev/null and b/assets/voxygen/voxel/sprite/velorite_small/velorite_7.vox differ diff --git a/assets/voxygen/voxel/sprite/velorite_small/velorite_8.vox b/assets/voxygen/voxel/sprite/velorite_small/velorite_8.vox new file mode 100644 index 0000000000..2d4664f10e Binary files /dev/null and b/assets/voxygen/voxel/sprite/velorite_small/velorite_8.vox differ diff --git a/assets/voxygen/voxel/sprite/velorite_small/velorite_9.vox b/assets/voxygen/voxel/sprite/velorite_small/velorite_9.vox new file mode 100644 index 0000000000..523c292e9a Binary files /dev/null and b/assets/voxygen/voxel/sprite/velorite_small/velorite_9.vox differ diff --git a/assets/world/tree/fruit/1.vox b/assets/world/tree/fruit/1.vox index 0648a279aa..4ed90a0b5b 100644 Binary files a/assets/world/tree/fruit/1.vox and b/assets/world/tree/fruit/1.vox differ diff --git a/assets/world/tree/fruit/2.vox b/assets/world/tree/fruit/2.vox index 3369c6c853..c47268df49 100644 Binary files a/assets/world/tree/fruit/2.vox and b/assets/world/tree/fruit/2.vox differ diff --git a/assets/world/tree/fruit/3.vox b/assets/world/tree/fruit/3.vox index 634099a2a4..f7d5fc915b 100644 Binary files a/assets/world/tree/fruit/3.vox and b/assets/world/tree/fruit/3.vox differ diff --git a/assets/world/tree/fruit/4.vox b/assets/world/tree/fruit/4.vox index 742845e60c..f4499f27ba 100644 Binary files a/assets/world/tree/fruit/4.vox and b/assets/world/tree/fruit/4.vox differ diff --git a/assets/world/tree/fruit/5.vox b/assets/world/tree/fruit/5.vox index b6b682ae48..5b649b1db7 100644 Binary files a/assets/world/tree/fruit/5.vox and b/assets/world/tree/fruit/5.vox differ diff --git a/assets/world/tree/fruit/6.vox b/assets/world/tree/fruit/6.vox index 936d825a06..cb5048186a 100644 Binary files a/assets/world/tree/fruit/6.vox and b/assets/world/tree/fruit/6.vox differ diff --git a/common/src/terrain/block.rs b/common/src/terrain/block.rs index e6650576ad..fbd5d035f4 100644 --- a/common/src/terrain/block.rs +++ b/common/src/terrain/block.rs @@ -3,19 +3,45 @@ use serde_derive::{Deserialize, Serialize}; use std::ops::Deref; use vek::*; -#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] #[repr(u8)] pub enum BlockKind { Air, Normal, Dense, Water, + LargeCactus, + BarrelCactus, + BlueFlower, + PinkFlower, + PurpleFlower, + RedFlower, + WhiteFlower, + YellowFlower, + Sunflower, + LongGrass, + MediumGrass, + ShortGrass, + Apple, } impl BlockKind { pub fn is_air(&self) -> bool { match self { BlockKind::Air => true, + BlockKind::LargeCactus => false, + BlockKind::BarrelCactus => true, + BlockKind::BlueFlower => true, + BlockKind::PinkFlower => true, + BlockKind::PurpleFlower => true, + BlockKind::RedFlower => true, + BlockKind::WhiteFlower => true, + BlockKind::YellowFlower => true, + BlockKind::Sunflower => true, + BlockKind::LongGrass => true, + BlockKind::MediumGrass => true, + BlockKind::ShortGrass => true, + BlockKind::Apple => true, _ => false, } } @@ -31,6 +57,19 @@ impl BlockKind { match self { BlockKind::Air => false, BlockKind::Water => false, + BlockKind::LargeCactus => false, + BlockKind::BarrelCactus => false, + BlockKind::BlueFlower => false, + BlockKind::PinkFlower => false, + BlockKind::PurpleFlower => false, + BlockKind::RedFlower => false, + BlockKind::WhiteFlower => false, + BlockKind::YellowFlower => false, + BlockKind::Sunflower => false, + BlockKind::LongGrass => false, + BlockKind::MediumGrass => false, + BlockKind::ShortGrass => false, + BlockKind::Apple => false, _ => true, } } @@ -39,6 +78,19 @@ impl BlockKind { match self { BlockKind::Air => false, BlockKind::Water => false, + BlockKind::LargeCactus => true, + BlockKind::BarrelCactus => true, + BlockKind::BlueFlower => false, + BlockKind::PinkFlower => false, + BlockKind::PurpleFlower => false, + BlockKind::RedFlower => false, + BlockKind::WhiteFlower => false, + BlockKind::YellowFlower => false, + BlockKind::Sunflower => false, + BlockKind::LongGrass => false, + BlockKind::MediumGrass => false, + BlockKind::ShortGrass => false, + BlockKind::Apple => true, _ => true, } } diff --git a/voxygen/src/mesh/mod.rs b/voxygen/src/mesh/mod.rs index c8b3b36308..86bd6cc55c 100644 --- a/voxygen/src/mesh/mod.rs +++ b/voxygen/src/mesh/mod.rs @@ -4,7 +4,7 @@ mod vol; use crate::render::{self, Mesh}; -pub trait Meshable { +pub trait Meshable { type Pipeline: render::Pipeline; type TranslucentPipeline: render::Pipeline; type Supplement; diff --git a/voxygen/src/mesh/segment.rs b/voxygen/src/mesh/segment.rs index e0b77ac31e..268d1e16f9 100644 --- a/voxygen/src/mesh/segment.rs +++ b/voxygen/src/mesh/segment.rs @@ -1,6 +1,6 @@ use crate::{ mesh::{vol, Meshable}, - render::{self, FigurePipeline, Mesh}, + render::{self, FigurePipeline, Mesh, SpritePipeline}, }; use common::{ figure::Segment, @@ -10,8 +10,9 @@ use common::{ use vek::*; type FigureVertex = ::Vertex; +type SpriteVertex = ::Vertex; -impl Meshable for Segment { +impl Meshable for Segment { type Pipeline = FigurePipeline; type TranslucentPipeline = FigurePipeline; type Supplement = Vec3; @@ -51,3 +52,43 @@ impl Meshable for Segment { (mesh, Mesh::new()) } } + +impl Meshable for Segment { + type Pipeline = SpritePipeline; + type TranslucentPipeline = SpritePipeline; + type Supplement = Vec3; + + fn generate_mesh( + &self, + offs: Self::Supplement, + ) -> (Mesh, Mesh) { + let mut mesh = Mesh::new(); + + for pos in self.iter_positions() { + if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) { + let col = col.map(|e| e as f32 / 255.0); + + vol::push_vox_verts( + &mut mesh, + self, + pos, + offs + pos.map(|e| e as f32), + col, + |origin, norm, col, ao, light| { + SpriteVertex::new( + origin, + norm, + linear_to_srgb(srgb_to_linear(col) * ao * light), + ) + }, + true, + &[[[1.0; 3]; 3]; 3], + |vox| vox.is_empty(), + |vox| !vox.is_empty(), + ); + } + } + + (mesh, Mesh::new()) + } +} diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index 90bdab211c..b3d479a672 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -14,15 +14,19 @@ type TerrainVertex = ::Vertex; type FluidVertex = ::Vertex; fn block_shadow_density(kind: BlockKind) -> (f32, f32) { + // (density, cap) match kind { - BlockKind::Air => (0.0, 0.0), BlockKind::Normal => (0.085, 0.3), BlockKind::Dense => (0.3, 0.0), BlockKind::Water => (0.15, 0.0), + kind if kind.is_air() => (0.0, 0.0), + _ => (1.0, 0.0), } } -impl + ReadVol + Debug, S: VolSize + Clone> Meshable for VolMap2d { +impl + ReadVol + Debug, S: VolSize + Clone> + Meshable for VolMap2d +{ type Pipeline = TerrainPipeline; type TranslucentPipeline = FluidPipeline; type Supplement = Aabb; diff --git a/voxygen/src/render/instances.rs b/voxygen/src/render/instances.rs new file mode 100644 index 0000000000..ba73968b23 --- /dev/null +++ b/voxygen/src/render/instances.rs @@ -0,0 +1,36 @@ +use super::{gfx_backend, RenderError}; +use gfx::{ + self, + buffer::Role, + memory::{Bind, Usage}, + Factory, +}; + +/// Represents a mesh that has been sent to the GPU. +pub struct Instances { + pub ibuf: gfx::handle::Buffer, +} + +impl Instances { + pub fn new(factory: &mut gfx_backend::Factory, len: usize) -> Result { + Ok(Self { + ibuf: factory + .create_buffer(len, Role::Vertex, Usage::Dynamic, Bind::TRANSFER_DST) + .map_err(|err| RenderError::BufferCreationError(err))?, + }) + } + + pub fn count(&self) -> usize { + self.ibuf.len() + } + + pub fn update( + &mut self, + encoder: &mut gfx::Encoder, + instances: &[T], + ) -> Result<(), RenderError> { + encoder + .update_buffer(&self.ibuf, instances, 0) + .map_err(|err| RenderError::UpdateError(err)) + } +} diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 369142cd90..787a36871f 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -1,4 +1,5 @@ pub mod consts; +pub mod instances; pub mod mesh; pub mod model; pub mod pipelines; @@ -9,6 +10,7 @@ mod util; // Reexports pub use self::{ consts::Consts, + instances::Instances, mesh::{Mesh, Quad, Tri}, model::{DynamicModel, Model}, pipelines::{ @@ -18,6 +20,7 @@ pub use self::{ create_mesh as create_pp_mesh, Locals as PostProcessLocals, PostProcessPipeline, }, skybox::{create_mesh as create_skybox_mesh, Locals as SkyboxLocals, SkyboxPipeline}, + sprite::{Instance as SpriteInstance, SpritePipeline}, terrain::{Locals as TerrainLocals, TerrainPipeline}, ui::{ create_quad as create_ui_quad, create_tri as create_ui_tri, Locals as UiLocals, diff --git a/voxygen/src/render/model.rs b/voxygen/src/render/model.rs index 420d505507..ece02ef913 100644 --- a/voxygen/src/render/model.rs +++ b/voxygen/src/render/model.rs @@ -10,22 +10,20 @@ use std::ops::Range; /// Represents a mesh that has been sent to the GPU. pub struct Model { pub vbuf: gfx::handle::Buffer, - pub slice: gfx::Slice, + pub vertex_range: Range, } impl Model

{ pub fn new(factory: &mut gfx_backend::Factory, mesh: &Mesh

) -> Self { Self { vbuf: factory.create_vertex_buffer(mesh.vertices()), - slice: gfx::Slice { - start: 0, - end: mesh.vertices().len() as u32, - base_vertex: 0, - instances: None, - buffer: gfx::IndexBuffer::Auto, - }, + vertex_range: 0..mesh.vertices().len() as u32, } } + + pub fn vertex_range(&self) -> Range { + self.vertex_range.clone() + } } /// Represents a mesh on the GPU which can be updated dynamically. @@ -46,13 +44,7 @@ impl DynamicModel

{ pub fn submodel(&self, range: Range) -> Model

{ Model { vbuf: self.vbuf.clone(), - slice: gfx::Slice { - start: range.start as u32, - end: range.end as u32, - base_vertex: 0, - instances: None, - buffer: gfx::IndexBuffer::Auto, - }, + vertex_range: range.start as u32..range.end as u32, } } diff --git a/voxygen/src/render/pipelines/mod.rs b/voxygen/src/render/pipelines/mod.rs index 08713bfc6b..14ac67169b 100644 --- a/voxygen/src/render/pipelines/mod.rs +++ b/voxygen/src/render/pipelines/mod.rs @@ -2,6 +2,7 @@ pub mod figure; pub mod fluid; pub mod postprocess; pub mod skybox; +pub mod sprite; pub mod terrain; pub mod ui; diff --git a/voxygen/src/render/pipelines/sprite.rs b/voxygen/src/render/pipelines/sprite.rs new file mode 100644 index 0000000000..e6265c3757 --- /dev/null +++ b/voxygen/src/render/pipelines/sprite.rs @@ -0,0 +1,79 @@ +use super::{ + super::{util::arr_to_mat, Pipeline, TgtColorFmt, TgtDepthFmt}, + Globals, Light, +}; +use gfx::{ + self, + // Macros + gfx_defines, + gfx_impl_struct_meta, + gfx_pipeline, + gfx_pipeline_inner, + gfx_vertex_struct_meta, + state::ColorMask, +}; +use vek::*; + +gfx_defines! { + vertex Vertex { + pos: [f32; 3] = "v_pos", + norm: [f32; 3] = "v_norm", + col: [f32; 3] = "v_col", + } + + vertex Instance { + inst_mat0: [f32; 4] = "inst_mat0", + inst_mat1: [f32; 4] = "inst_mat1", + inst_mat2: [f32; 4] = "inst_mat2", + inst_mat3: [f32; 4] = "inst_mat3", + inst_col: [f32; 3] = "inst_col", + inst_wind_sway: f32 = "inst_wind_sway", + } + + pipeline pipe { + vbuf: gfx::VertexBuffer = (), + ibuf: gfx::InstanceBuffer = (), + + globals: gfx::ConstantBuffer = "u_globals", + lights: gfx::ConstantBuffer = "u_lights", + + tgt_color: gfx::BlendTarget = ("tgt_color", ColorMask::all(), gfx::preset::blend::ALPHA), + tgt_depth: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE, + } +} + +impl Vertex { + pub fn new(pos: Vec3, norm: Vec3, col: Rgb) -> Self { + Self { + pos: pos.into_array(), + col: col.into_array(), + norm: norm.into_array(), + } + } +} + +impl Instance { + pub fn new(mat: Mat4, col: Rgb, wind_sway: f32) -> Self { + let mat_arr = arr_to_mat(mat.into_col_array()); + Self { + inst_mat0: mat_arr[0], + inst_mat1: mat_arr[1], + inst_mat2: mat_arr[2], + inst_mat3: mat_arr[3], + inst_col: col.into_array(), + inst_wind_sway: wind_sway, + } + } +} + +impl Default for Instance { + fn default() -> Self { + Self::new(Mat4::identity(), Rgb::broadcast(1.0), 0.0) + } +} + +pub struct SpritePipeline; + +impl Pipeline for SpritePipeline { + type Vertex = Vertex; +} diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index e862da5a29..347b4a6cdb 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -1,9 +1,10 @@ use super::{ consts::Consts, gfx_backend, + instances::Instances, mesh::Mesh, model::{DynamicModel, Model}, - pipelines::{figure, fluid, postprocess, skybox, terrain, ui, Globals, Light}, + pipelines::{figure, fluid, postprocess, skybox, sprite, terrain, ui, Globals, Light}, texture::Texture, Pipeline, RenderError, }; @@ -65,6 +66,7 @@ pub struct Renderer { figure_pipeline: GfxPipeline>, terrain_pipeline: GfxPipeline>, fluid_pipeline: GfxPipeline>, + sprite_pipeline: GfxPipeline>, ui_pipeline: GfxPipeline>, postprocess_pipeline: GfxPipeline>, @@ -86,6 +88,7 @@ impl Renderer { figure_pipeline, terrain_pipeline, fluid_pipeline, + sprite_pipeline, ui_pipeline, postprocess_pipeline, ) = create_pipelines(&mut factory, &mut shader_reload_indicator)?; @@ -114,6 +117,7 @@ impl Renderer { figure_pipeline, terrain_pipeline, fluid_pipeline, + sprite_pipeline, ui_pipeline, postprocess_pipeline, @@ -201,6 +205,7 @@ impl Renderer { figure_pipeline, terrain_pipeline, fluid_pipeline, + sprite_pipeline, ui_pipeline, postprocess_pipeline, )) => { @@ -208,6 +213,7 @@ impl Renderer { self.figure_pipeline = figure_pipeline; self.terrain_pipeline = terrain_pipeline; self.fluid_pipeline = fluid_pipeline; + self.sprite_pipeline = sprite_pipeline; self.ui_pipeline = ui_pipeline; self.postprocess_pipeline = postprocess_pipeline; } @@ -238,6 +244,16 @@ impl Renderer { consts.update(&mut self.encoder, vals) } + /// Create a new set of instances with the provided values. + pub fn create_instances( + &mut self, + vals: &[T], + ) -> Result, RenderError> { + let mut instances = Instances::new(&mut self.factory, vals.len())?; + instances.update(&mut self.encoder, vals)?; + Ok(instances) + } + /// Create a new model from the provided mesh. pub fn create_model(&mut self, mesh: &Mesh

) -> Result, RenderError> { Ok(Model::new(&mut self.factory, mesh)) @@ -350,7 +366,13 @@ impl Renderer { locals: &Consts, ) { self.encoder.draw( - &model.slice, + &gfx::Slice { + start: model.vertex_range().start, + end: model.vertex_range().end, + base_vertex: 0, + instances: None, + buffer: gfx::IndexBuffer::Auto, + }, &self.skybox_pipeline.pso, &skybox::pipe::Data { vbuf: model.vbuf.clone(), @@ -372,7 +394,13 @@ impl Renderer { lights: &Consts, ) { self.encoder.draw( - &model.slice, + &gfx::Slice { + start: model.vertex_range().start, + end: model.vertex_range().end, + base_vertex: 0, + instances: None, + buffer: gfx::IndexBuffer::Auto, + }, &self.figure_pipeline.pso, &figure::pipe::Data { vbuf: model.vbuf.clone(), @@ -395,7 +423,13 @@ impl Renderer { lights: &Consts, ) { self.encoder.draw( - &model.slice, + &gfx::Slice { + start: model.vertex_range().start, + end: model.vertex_range().end, + base_vertex: 0, + instances: None, + buffer: gfx::IndexBuffer::Auto, + }, &self.terrain_pipeline.pso, &terrain::pipe::Data { vbuf: model.vbuf.clone(), @@ -417,7 +451,13 @@ impl Renderer { lights: &Consts, ) { self.encoder.draw( - &model.slice, + &gfx::Slice { + start: model.vertex_range().start, + end: model.vertex_range().end, + base_vertex: 0, + instances: None, + buffer: gfx::IndexBuffer::Auto, + }, &self.fluid_pipeline.pso, &fluid::pipe::Data { vbuf: model.vbuf.clone(), @@ -430,6 +470,34 @@ impl Renderer { ); } + /// Queue the rendering of the provided terrain chunk model in the upcoming frame. + pub fn render_sprites( + &mut self, + model: &Model, + globals: &Consts, + instances: &Instances, + lights: &Consts, + ) { + self.encoder.draw( + &gfx::Slice { + start: model.vertex_range().start, + end: model.vertex_range().end, + base_vertex: 0, + instances: Some((instances.count() as u32, 0)), + buffer: gfx::IndexBuffer::Auto, + }, + &self.sprite_pipeline.pso, + &sprite::pipe::Data { + vbuf: model.vbuf.clone(), + ibuf: instances.ibuf.clone(), + globals: globals.buf.clone(), + lights: lights.buf.clone(), + tgt_color: self.tgt_color_view.clone(), + tgt_depth: self.tgt_depth_view.clone(), + }, + ); + } + /// Queue the rendering of the provided UI element in the upcoming frame. pub fn render_ui_element( &mut self, @@ -441,7 +509,13 @@ impl Renderer { ) { let Aabr { min, max } = scissor; self.encoder.draw( - &model.slice, + &gfx::Slice { + start: model.vertex_range().start, + end: model.vertex_range().end, + base_vertex: 0, + instances: None, + buffer: gfx::IndexBuffer::Auto, + }, &self.ui_pipeline.pso, &ui::pipe::Data { vbuf: model.vbuf.clone(), @@ -467,7 +541,13 @@ impl Renderer { locals: &Consts, ) { self.encoder.draw( - &model.slice, + &gfx::Slice { + start: model.vertex_range().start, + end: model.vertex_range().end, + base_vertex: 0, + instances: None, + buffer: gfx::IndexBuffer::Auto, + }, &self.postprocess_pipeline.pso, &postprocess::pipe::Data { vbuf: model.vbuf.clone(), @@ -495,6 +575,7 @@ fn create_pipelines( GfxPipeline>, GfxPipeline>, GfxPipeline>, + GfxPipeline>, GfxPipeline>, GfxPipeline>, ), @@ -571,6 +652,18 @@ fn create_pipelines( gfx::state::CullFace::Nothing, )?; + // Construct a pipeline for rendering sprites + let sprite_pipeline = create_pipeline( + factory, + sprite::pipe::new(), + &assets::load_watched::("voxygen.shaders.sprite-vert", shader_reload_indicator) + .unwrap(), + &assets::load_watched::("voxygen.shaders.sprite-frag", shader_reload_indicator) + .unwrap(), + &include_ctx, + gfx::state::CullFace::Back, + )?; + // Construct a pipeline for rendering UI elements let ui_pipeline = create_pipeline( factory, @@ -606,6 +699,7 @@ fn create_pipelines( figure_pipeline, terrain_pipeline, fluid_pipeline, + sprite_pipeline, ui_pipeline, postprocess_pipeline, )) diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 51aa213ca6..910e5a9c1b 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -163,9 +163,11 @@ impl FigureModelCache { // TODO: Don't make this public. pub fn load_mesh(mesh_name: &str, position: Vec3) -> Mesh { let full_specifier: String = ["voxygen.voxel.", mesh_name].concat(); - Segment::from(assets::load_expect::(full_specifier.as_str()).as_ref()) - .generate_mesh(position) - .0 + Meshable::::generate_mesh( + &Segment::from(assets::load_expect::(full_specifier.as_str()).as_ref()), + position, + ) + .0 } fn load_head(race: humanoid::Race, body_type: humanoid::BodyType) -> Mesh { diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index c6da07713f..96518f516b 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -68,7 +68,7 @@ impl Scene { .create_consts(&[PostProcessLocals::default()]) .unwrap(), }, - terrain: Terrain::new(), + terrain: Terrain::new(renderer), loaded_distance: 0.0, figure_mgr: FigureMgr::new(), } @@ -229,7 +229,12 @@ impl Scene { // Render terrain and figures. self.figure_mgr .render(renderer, client, &self.globals, &self.lights, &self.camera); - self.terrain.render(renderer, &self.globals, &self.lights); + self.terrain.render( + renderer, + &self.globals, + &self.lights, + self.camera.get_focus_pos(), + ); renderer.render_post_process( &self.postprocess.model, diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index deed0a9fcb..d01e5e52fa 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -1,27 +1,32 @@ use crate::{ mesh::Meshable, render::{ - Consts, FluidPipeline, Globals, Light, Mesh, Model, Renderer, TerrainLocals, - TerrainPipeline, + Consts, FluidPipeline, Globals, Instances, Light, Mesh, Model, Renderer, SpriteInstance, + SpritePipeline, TerrainLocals, TerrainPipeline, }, }; use client::Client; use common::{ - terrain::{TerrainChunkSize, TerrainMap}, - vol::{SampleVol, VolSize}, + assets, + figure::Segment, + terrain::{Block, BlockKind, TerrainChunkSize, TerrainMap}, + vol::{ReadVol, SampleVol, VolSize, Vox}, volumes::vol_map_2d::VolMap2dErr, }; use crossbeam::channel; +use dot_vox::DotVoxData; use frustum_query::frustum::Frustum; use hashbrown::HashMap; -use std::{i32, ops::Mul, time::Duration}; +use std::{f32, i32, ops::Mul, time::Duration}; use vek::*; struct TerrainChunk { // GPU data opaque_model: Model, fluid_model: Model, + sprite_instances: HashMap<(BlockKind, usize), Instances>, locals: Consts, + visible: bool, z_bounds: (f32, f32), } @@ -38,9 +43,72 @@ struct MeshWorkerResponse { z_bounds: (f32, f32), opaque_mesh: Mesh, fluid_mesh: Mesh, + sprite_instances: HashMap<(BlockKind, usize), Vec>, started_tick: u64, } +struct SpriteConfig { + variations: usize, + wind_sway: f32, // 1.0 is normal +} + +fn sprite_config_for(kind: BlockKind) -> Option { + match kind { + BlockKind::LargeCactus => Some(SpriteConfig { + variations: 1, + wind_sway: 0.0, + }), + BlockKind::BarrelCactus => Some(SpriteConfig { + variations: 1, + wind_sway: 0.0, + }), + + BlockKind::BlueFlower => Some(SpriteConfig { + variations: 2, + wind_sway: 0.3, + }), + BlockKind::PinkFlower => Some(SpriteConfig { + variations: 3, + wind_sway: 0.3, + }), + BlockKind::RedFlower => Some(SpriteConfig { + variations: 1, + wind_sway: 0.3, + }), + BlockKind::WhiteFlower => Some(SpriteConfig { + variations: 1, + wind_sway: 0.3, + }), + BlockKind::YellowFlower => Some(SpriteConfig { + variations: 1, + wind_sway: 0.3, + }), + BlockKind::Sunflower => Some(SpriteConfig { + variations: 2, + wind_sway: 0.3, + }), + + BlockKind::LongGrass => Some(SpriteConfig { + variations: 5, + wind_sway: 1.0, + }), + BlockKind::MediumGrass => Some(SpriteConfig { + variations: 5, + wind_sway: 1.0, + }), + BlockKind::ShortGrass => Some(SpriteConfig { + variations: 5, + wind_sway: 1.0, + }), + + BlockKind::Apple => Some(SpriteConfig { + variations: 1, + wind_sway: 0.0, + }), + _ => None, + } +} + /// Function executed by worker threads dedicated to chunk meshing. fn mesh_worker( pos: Vec2, @@ -55,6 +123,43 @@ fn mesh_worker( z_bounds, opaque_mesh, fluid_mesh, + // Extract sprite locations from volume + sprite_instances: { + let mut instances = HashMap::new(); + + for x in 0..TerrainChunkSize::SIZE.x as i32 { + for y in 0..TerrainChunkSize::SIZE.y as i32 { + for z in z_bounds.0 as i32..z_bounds.1 as i32 + 1 { + let wpos = Vec3::from( + pos * Vec2::from(TerrainChunkSize::SIZE).map(|e: u32| e as i32), + ) + Vec3::new(x, y, z); + + let kind = volume.get(wpos).unwrap_or(&Block::empty()).kind(); + + if let Some(cfg) = sprite_config_for(kind) { + let seed = wpos.x * 3 + wpos.y * 7 + wpos.z * 13 + wpos.x * wpos.y; + + let instance = SpriteInstance::new( + Mat4::identity() + .rotated_z(f32::consts::PI * 0.5 * (seed % 4) as f32) + .translated_3d( + wpos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0), + ), + Rgb::broadcast(1.0), + cfg.wind_sway, + ); + + instances + .entry((kind, seed as usize % cfg.variations)) + .or_insert_with(|| Vec::new()) + .push(instance); + } + } + } + } + + instances + }, started_tick, } } @@ -67,19 +172,158 @@ pub struct Terrain { mesh_send_tmp: channel::Sender, mesh_recv: channel::Receiver, mesh_todo: HashMap, ChunkMeshState>, + + // GPU data + sprite_models: HashMap<(BlockKind, usize), Model>, } impl Terrain { - pub fn new() -> Self { + pub fn new(renderer: &mut Renderer) -> Self { // Create a new mpsc (Multiple Produced, Single Consumer) pair for communicating with // worker threads that are meshing chunks. let (send, recv) = channel::unbounded(); + let mut make_model = |s| { + renderer + .create_model( + &Meshable::::generate_mesh( + &Segment::from(assets::load_expect::(s).as_ref()), + Vec3::new(-6.0, -6.0, 0.0), + ) + .0, + ) + .unwrap() + }; + Self { chunks: HashMap::default(), mesh_send_tmp: send, mesh_recv: recv, mesh_todo: HashMap::default(), + sprite_models: vec![ + // Cacti + ( + (BlockKind::LargeCactus, 0), + make_model("voxygen.voxel.sprite.cacti.large_cactus"), + ), + ( + (BlockKind::BarrelCactus, 0), + make_model("voxygen.voxel.sprite.cacti.barrel_cactus"), + ), + // Fruit + ( + (BlockKind::Apple, 0), + make_model("voxygen.voxel.sprite.fruit.apple"), + ), + // Flowers + ( + (BlockKind::BlueFlower, 0), + make_model("voxygen.voxel.sprite.flowers.flower_blue_1"), + ), + ( + (BlockKind::BlueFlower, 1), + make_model("voxygen.voxel.sprite.flowers.flower_blue_2"), + ), + ( + (BlockKind::PinkFlower, 0), + make_model("voxygen.voxel.sprite.flowers.flower_pink_1"), + ), + ( + (BlockKind::PinkFlower, 1), + make_model("voxygen.voxel.sprite.flowers.flower_pink_2"), + ), + ( + (BlockKind::PinkFlower, 2), + make_model("voxygen.voxel.sprite.flowers.flower_pink_3"), + ), + ( + (BlockKind::PurpleFlower, 0), + make_model("voxygen.voxel.sprite.flowers.flower_purple_1"), + ), + ( + (BlockKind::RedFlower, 0), + make_model("voxygen.voxel.sprite.flowers.flower_red_1"), + ), + ( + (BlockKind::WhiteFlower, 0), + make_model("voxygen.voxel.sprite.flowers.flower_white_1"), + ), + ( + (BlockKind::YellowFlower, 0), + make_model("voxygen.voxel.sprite.flowers.flower_purple_1"), + ), + ( + (BlockKind::Sunflower, 0), + make_model("voxygen.voxel.sprite.flowers.sunflower_1"), + ), + ( + (BlockKind::Sunflower, 1), + make_model("voxygen.voxel.sprite.flowers.sunflower_2"), + ), + // Grass + ( + (BlockKind::LongGrass, 0), + make_model("voxygen.voxel.sprite.grass.grass_long_1"), + ), + ( + (BlockKind::LongGrass, 1), + make_model("voxygen.voxel.sprite.grass.grass_long_2"), + ), + ( + (BlockKind::LongGrass, 2), + make_model("voxygen.voxel.sprite.grass.grass_long_3"), + ), + ( + (BlockKind::LongGrass, 3), + make_model("voxygen.voxel.sprite.grass.grass_long_4"), + ), + ( + (BlockKind::LongGrass, 4), + make_model("voxygen.voxel.sprite.grass.grass_long_5"), + ), + ( + (BlockKind::MediumGrass, 0), + make_model("voxygen.voxel.sprite.grass.grass_med_1"), + ), + ( + (BlockKind::MediumGrass, 1), + make_model("voxygen.voxel.sprite.grass.grass_med_2"), + ), + ( + (BlockKind::MediumGrass, 2), + make_model("voxygen.voxel.sprite.grass.grass_med_3"), + ), + ( + (BlockKind::MediumGrass, 3), + make_model("voxygen.voxel.sprite.grass.grass_med_4"), + ), + ( + (BlockKind::MediumGrass, 4), + make_model("voxygen.voxel.sprite.grass.grass_med_5"), + ), + ( + (BlockKind::ShortGrass, 0), + make_model("voxygen.voxel.sprite.grass.grass_short_1"), + ), + ( + (BlockKind::ShortGrass, 1), + make_model("voxygen.voxel.sprite.grass.grass_short_2"), + ), + ( + (BlockKind::ShortGrass, 2), + make_model("voxygen.voxel.sprite.grass.grass_short_3"), + ), + ( + (BlockKind::ShortGrass, 3), + make_model("voxygen.voxel.sprite.grass.grass_short_3"), + ), + ( + (BlockKind::ShortGrass, 4), + make_model("voxygen.voxel.sprite.grass.grass_short_5"), + ), + ] + .into_iter() + .collect(), } } @@ -275,6 +519,18 @@ impl Terrain { fluid_model: renderer .create_model(&response.fluid_mesh) .expect("Failed to upload chunk mesh to the GPU!"), + sprite_instances: response + .sprite_instances + .into_iter() + .map(|(kind, instances)| { + ( + kind, + renderer.create_instances(&instances).expect( + "Failed to upload chunk sprite instances to the GPU!", + ), + ) + }) + .collect(), locals: renderer .create_consts(&[TerrainLocals { model_offs: Vec3::from( @@ -343,18 +599,37 @@ impl Terrain { renderer: &mut Renderer, globals: &Consts, lights: &Consts, + focus_pos: Vec3, ) { // Opaque - for (_pos, chunk) in &self.chunks { + for (_, chunk) in &self.chunks { if chunk.visible { renderer.render_terrain_chunk(&chunk.opaque_model, globals, &chunk.locals, lights); } } // Translucent - for (_pos, chunk) in &self.chunks { + for (pos, chunk) in &self.chunks { if chunk.visible { renderer.render_fluid_chunk(&chunk.fluid_model, globals, &chunk.locals, lights); + + const SPRITE_RENDER_DISTANCE: f32 = 128.0; + + let chunk_center = pos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { + (e as f32 + 0.5) * sz as f32 + }); + if Vec2::from(focus_pos).distance_squared(chunk_center) + < SPRITE_RENDER_DISTANCE * SPRITE_RENDER_DISTANCE + { + for (kind, instances) in &chunk.sprite_instances { + renderer.render_sprites( + &self.sprite_models[&kind], + globals, + &instances, + lights, + ); + } + } } } } diff --git a/world/src/block/mod.rs b/world/src/block/mod.rs index ea166d4e93..22e9d530e4 100644 --- a/world/src/block/mod.rs +++ b/world/src/block/mod.rs @@ -148,11 +148,13 @@ impl<'a> BlockGen<'a> { //close_structures, cave_xy, cave_alt, + marble, + marble_small, rock, //cliffs, cliff_hill, close_cliffs, - //temp, + temp, .. } = &z_cache?.sample; @@ -254,6 +256,49 @@ impl<'a> BlockGen<'a> { BlockKind::Normal, saturate_srgb(col, 0.45).map(|e| (e * 255.0) as u8), )) + } else if (wposf.z as f32) < height + 0.9 + && temp < CONFIG.desert_temp + && (wposf.z as f32 > water_height + 3.0) + && marble > 0.68 + && marble_small > 0.65 + && (marble * 3173.7).fract() < 0.5 + { + let flowers = [ + BlockKind::BlueFlower, + BlockKind::PinkFlower, + BlockKind::PurpleFlower, + BlockKind::RedFlower, + BlockKind::WhiteFlower, + BlockKind::YellowFlower, + BlockKind::Sunflower, + ]; + + let grasses = [ + BlockKind::LongGrass, + BlockKind::MediumGrass, + BlockKind::ShortGrass, + ]; + + Some(Block::new( + if (height * 1271.0).fract() < 0.15 { + flowers[(height * 0.2) as usize % flowers.len()] + } else { + grasses[(height * 0.3) as usize % grasses.len()] + }, + Rgb::broadcast(0), + )) + } else if (wposf.z as f32) < height + 0.9 + && temp > CONFIG.desert_temp + && (marble * 4423.5).fract() < 0.0005 + { + Some(Block::new( + if (height * 1271.0).fract() < 0.5 { + BlockKind::LargeCactus + } else { + BlockKind::BarrelCactus + }, + Rgb::broadcast(0), + )) } else { None }; @@ -504,11 +549,7 @@ fn block_from_structure( ) .map(|e| e as u8), )), - StructureBlock::Fruit => Some(Block::new( - BlockKind::Normal, - Lerp::lerp(Rgb::new(237.0, 0.0, 0.0), Rgb::new(200.0, 237.0, 0.0), lerp) - .map(|e| e as u8), - )), + StructureBlock::Fruit => Some(Block::new(BlockKind::Apple, Rgb::new(194, 30, 37))), StructureBlock::Hollow => Some(Block::empty()), StructureBlock::Normal(color) => { Some(Block::new(default_kind, color)).filter(|block| !block.is_empty()) diff --git a/world/src/block/natural.rs b/world/src/block/natural.rs index 9360e87941..102a8c6c42 100644 --- a/world/src/block/natural.rs +++ b/world/src/block/natural.rs @@ -366,11 +366,11 @@ lazy_static! { pub static ref FRUIT_TREES: Vec> = vec![ // fruit trees st_asset("world.tree.fruit.1", (5, 5, 7)), - st_asset("world.tree.fruit.2", (5, 5, 7)), - st_asset("world.tree.fruit.3", (5, 5, 7)), - st_asset("world.tree.fruit.4", (5, 5, 7)), - st_asset("world.tree.fruit.5", (5, 5, 7)), - st_asset("world.tree.fruit.6", (5, 5, 7)), + st_asset("world.tree.fruit.2", (6, 6, 7)), + st_asset("world.tree.fruit.3", (6, 7, 7)), + st_asset("world.tree.fruit.4", (3, 3, 7)), + st_asset("world.tree.fruit.5", (6, 8, 7)), + st_asset("world.tree.fruit.6", (7, 7, 7)), ]; /* diff --git a/world/src/column/mod.rs b/world/src/column/mod.rs index 36b9416d92..9319fdd2f9 100644 --- a/world/src/column/mod.rs +++ b/world/src/column/mod.rs @@ -359,6 +359,8 @@ impl<'a> Sampler for ColumnGen<'a> { close_structures: self.gen_close_structures(wpos), cave_xy, cave_alt, + marble, + marble_small, rock, is_cliffs, near_cliffs, @@ -384,6 +386,8 @@ pub struct ColumnSample<'a> { pub close_structures: [Option; 9], pub cave_xy: f32, pub cave_alt: f32, + pub marble: f32, + pub marble_small: f32, pub rock: f32, pub is_cliffs: bool, pub near_cliffs: bool,