diff --git a/assets/voxygen/shaders/figure-frag.glsl b/assets/voxygen/shaders/figure-frag.glsl index 274fae9e12..9221658add 100644 --- a/assets/voxygen/shaders/figure-frag.glsl +++ b/assets/voxygen/shaders/figure-frag.glsl @@ -1,4 +1,18 @@ -#version 330 core +#version 400 core + +#include + +#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY + +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + +#define HAS_SHADOW_MAPS #include @@ -59,7 +73,7 @@ void main() { vec3 surf_color = /*srgb_to_linear*/(model_col.rgb * f_col); float alpha = 1.0; - const float n2 = 1.01; + const float n2 = 1.5; 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); @@ -102,7 +116,7 @@ void main() { // diffuse_light += point_light; // reflected_light += point_light; // vec3 surf_color = illuminate(srgb_to_linear(model_col.rgb * f_col), light, diffuse_light, ambient_light); - surf_color = illuminate(max_light, surf_color * emitted_light, surf_color * reflected_light); + surf_color = illuminate(max_light, view_dir, surf_color * emitted_light, surf_color * reflected_light); float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x); vec4 clouds; diff --git a/assets/voxygen/shaders/figure-vert.glsl b/assets/voxygen/shaders/figure-vert.glsl index 48840127a0..34e5baae57 100644 --- a/assets/voxygen/shaders/figure-vert.glsl +++ b/assets/voxygen/shaders/figure-vert.glsl @@ -1,5 +1,17 @@ #version 330 core +#include + +#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY + +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + #include #include diff --git a/assets/voxygen/shaders/fluid-frag/cheap.glsl b/assets/voxygen/shaders/fluid-frag/cheap.glsl index 71837dcd5e..2ab5f37561 100644 --- a/assets/voxygen/shaders/fluid-frag/cheap.glsl +++ b/assets/voxygen/shaders/fluid-frag/cheap.glsl @@ -1,4 +1,22 @@ -#version 330 core +#version 400 core + +#include + +#define LIGHTING_TYPE (LIGHTING_TYPE_TRANSMISSION | LIGHTING_TYPE_REFLECTION) + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_SPECULAR + +#if (FLUID_MODE == FLUID_MODE_CHEAP) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE +#elif (FLUID_MODE == FLUID_MODE_SHINY) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE +#endif + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + +#define HAS_SHADOW_MAPS #include #include @@ -25,7 +43,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(1,0,0), vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), 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; @@ -52,7 +70,7 @@ void main() { // float moon_shade_frac = horizon_at(/*f_shadow, f_pos.z, */f_pos, moon_dir); float shade_frac = /*1.0;*/sun_shade_frac + moon_shade_frac; - float fluid_alt = max(ceil(f_pos.z), floor(f_alt));// f_alt;//max(f_alt - f_pos.z, 0.0); + float fluid_alt = f_pos.z;//max(ceil(f_pos.z), floor(f_alt));// f_alt;//max(f_alt - f_pos.z, 0.0); const float alpha = 0.255/* / 4.0 / sqrt(2.0)*/; const float n2 = 1.3325; @@ -62,8 +80,15 @@ void main() { const float R_s1s2 = pow((1.3325 - 1.0) / (1.3325 + 1.0), 2); float R_s = (f_pos.z < fluid_alt) ? mix(R_s2s1 * R_s1s0, R_s1s0, medium.x) : mix(R_s2s0, R_s1s2 * R_s2s0, medium.x); + // Water is transparent so both normals are valid. + vec3 cam_norm = faceforward(f_norm, f_norm, cam_to_frag); + + vec3 mu = MU_WATER; + // NOTE: Default intersection point is camera position, meaning if we fail to intersect we assume the whole camera is in water. + vec3 cam_attenuation = vec3(1.0);//compute_attenuation_point(f_pos, -view_dir, mu, fluid_alt, cam_pos.xyz); + // NOTE: Assumes normal is vertical. - vec3 sun_view_dir = cam_pos.z <= fluid_alt ? /*refract(view_dir, -f_norm, 1.0 / n2)*//*reflect(view_dir, -f_norm)*/vec3(view_dir.xy, -view_dir.z) : view_dir; + vec3 sun_view_dir = cam_pos.z <= fluid_alt ? /*refract(view_dir, -f_norm, 1.0 / n2)*//*reflect(view_dir, -f_norm)*/-view_dir : view_dir;//vec3(view_dir.xy, -view_dir.z) : view_dir; vec3 k_a = vec3(1.0); vec3 k_d = vec3(1.0); @@ -83,7 +108,7 @@ void main() { // vec3 surf_color = /*srgb_to_linear*/(vec3(0.4, 0.7, 2.0)); float max_light = 0.0; - max_light += get_sun_diffuse2(f_norm, /*time_of_day.x*/sun_dir, moon_dir, /*-cam_to_frag*/sun_view_dir, k_a/* * (shade_frac * 0.5 + light_frac * 0.5)*/, /*vec3(0.0)*/k_d, k_s, alpha, emitted_light, reflected_light); + max_light += get_sun_diffuse2(f_norm, /*time_of_day.x*/sun_dir, moon_dir, /*-cam_to_frag*/sun_view_dir/*view_dir*/, f_pos, mu, cam_attenuation, fluid_alt, k_a/* * (shade_frac * 0.5 + light_frac * 0.5)*/, /*vec3(0.0)*/k_d, k_s, alpha, 1.0, emitted_light, reflected_light); reflected_light *= f_light * point_shadow * shade_frac; emitted_light *= f_light * point_shadow * max(shade_frac, MIN_SHADOW); max_light *= f_light * point_shadow * shade_frac; @@ -101,7 +126,7 @@ void main() { emitted_light += point_light; reflected_light += point_light; */ - max_light += lights_at(f_pos, f_norm, view_dir, /*vec3(0.0), vec3(1.0), fluid_alt, */k_a, k_d, k_s, alpha, emitted_light, reflected_light); + max_light += lights_at(f_pos, /*f_norm*/cam_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, 1.0, emitted_light, reflected_light); // vec3 diffuse_light_point = vec3(0.0); // max_light += lights_at(f_pos, f_norm, view_dir, k_a, vec3(1.0), k_s, alpha, emitted_light, diffuse_light_point); @@ -118,9 +143,9 @@ void main() { vec4 clouds; vec3 fog_color = get_sky_color(cam_to_frag, time_of_day.x, cam_pos.xyz, f_pos, 0.25, true, clouds); - float passthrough = /*pow(*/dot(faceforward(f_norm, f_norm, cam_to_frag/*view_dir*/), -cam_to_frag/*view_dir*/)/*, 0.5)*/; + float passthrough = /*pow(*/dot(cam_norm, -cam_to_frag/*view_dir*/)/*, 0.5)*/; - vec3 surf_color = illuminate(max_light, water_color * fog_color * emitted_light, /*surf_color * */water_color * reflected_light); + vec3 surf_color = illuminate(max_light, view_dir, water_color * fog_color * emitted_light, /*surf_color * */water_color * reflected_light); vec4 color = mix(vec4(surf_color, 1.0), vec4(surf_color, 1.0 / (1.0 + /*diffuse_light*//*(f_light * point_shadow + point_light)*/4.0 * reflected_light_point/* * 0.25*/)), passthrough); 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-frag/shiny.glsl b/assets/voxygen/shaders/fluid-frag/shiny.glsl index 7be35e1118..105da5a917 100644 --- a/assets/voxygen/shaders/fluid-frag/shiny.glsl +++ b/assets/voxygen/shaders/fluid-frag/shiny.glsl @@ -1,4 +1,22 @@ -#version 330 core +#version 400 core + +#include + +#define LIGHTING_TYPE (LIGHTING_TYPE_TRANSMISSION | LIGHTING_TYPE_REFLECTION) + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_SPECULAR + +#if (FLUID_MODE == FLUID_MODE_CHEAP) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE +#elif (FLUID_MODE == FLUID_MODE_SHINY) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE +#endif + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + +#define HAS_SHADOW_MAPS // https://www.shadertoy.com/view/XdsyWf @@ -119,7 +137,7 @@ void main() { vec4 _clouds; vec3 reflect_ray_dir = reflect(cam_to_frag/*-view_dir*/, norm); vec3 refract_ray_dir = refract(cam_to_frag/*-view_dir*/, norm, 1.0 / n2); - vec3 sun_view_dir = /*sign(cam_pos.z - fluid_alt) * view_dir;*/cam_pos.z <= fluid_alt ? -view_dir : view_dir; + vec3 sun_view_dir = view_dir;///*sign(cam_pos.z - fluid_alt) * view_dir;*/cam_pos.z <= fluid_alt ? -view_dir : view_dir; // vec3 sun_view_dir = cam_pos.z <= fluid_alt ? -view_dir : view_dir; vec3 beam_view_dir = reflect_ray_dir;//cam_pos.z <= fluid_alt ? -refract_ray_dir : reflect_ray_dir; /* vec4 reflect_ray_dir4 = view_mat * vec4(reflect_ray_dir, 1.0); @@ -132,7 +150,7 @@ void main() { // /*const */vec3 water_color = srgb_to_linear(vec3(0.8, 0.9, 1.0)); // NOTE: Linear RGB, attenuation coefficients for water at roughly R, G, B wavelengths. // See https://en.wikipedia.org/wiki/Electromagnetic_absorption_by_water - /*const */vec3 water_attenuation = MU_WATER;// vec3(0.8, 0.05, 0.01); + // /*const */vec3 water_attenuation = MU_WATER;// vec3(0.8, 0.05, 0.01); // /*const */vec3 water_color = vec3(0.2, 0.95, 0.99); vec3 sun_dir = get_sun_dir(time_of_day.x); @@ -167,7 +185,7 @@ void main() { // // Color goes down with distance... // // See https://en.wikipedia.org/wiki/Beer%E2%80%93Lambert_law. - vec3 water_color_direct = vec3(1.0);//exp(-MU_WATER);//vec3(1.0); + // vec3 water_color_direct = exp(-MU_WATER);//exp(-MU_WATER);//vec3(1.0); // vec3 water_color_direct = exp(-water_attenuation * (water_depth_to_light + water_depth_to_camera)); // vec3 water_color_ambient = exp(-water_attenuation * (water_depth_to_vertical + water_depth_to_camera)); vec3 mu = MU_WATER; @@ -176,8 +194,8 @@ void main() { // float water_depth_to_vertical = max(/*f_alt - f_pos.z*/f_light, 0.0); // For ambient color, we just take the distance to the surface out of laziness. // See https://en.wikipedia.org/wiki/Beer%E2%80%93Lambert_law. - float water_depth_to_vertical = max(fluid_alt - cam_pos.z/*f_light*/, 0.0); - vec3 ambient_attenuation = exp(-mu * water_depth_to_vertical); + // float water_depth_to_vertical = max(fluid_alt - cam_pos.z/*f_light*/, 0.0); + // vec3 ambient_attenuation = exp(-mu * water_depth_to_vertical); // For ambient reflection, we just take the water @@ -191,7 +209,7 @@ void main() { float point_shadow = shadow_at(f_pos, f_norm); // vec3 light_frac = /*vec3(1.0);*/light_reflection_factor(f_norm/*vec3(0, 0, 1.0)*/, view_dir, vec3(0, 0, -1.0), vec3(1.0), vec3(R_s), alpha); // 0 = 100% reflection, 1 = translucent water - float passthrough = /*pow(*/dot(faceforward(f_norm, f_norm, cam_to_frag/*view_dir*/), -cam_to_frag/*view_dir*/)/*, 0.5)*/; + float passthrough = /*pow(*/dot(faceforward(norm, norm, cam_to_frag/*view_dir*/), -cam_to_frag/*view_dir*/)/*, 0.5)*/; float max_light = 0.0; max_light += get_sun_diffuse2(norm, /*time_of_day.x*/sun_dir, moon_dir, sun_view_dir, f_pos, mu, cam_attenuation, fluid_alt, k_a/* * (shade_frac * 0.5 + light_frac * 0.5)*/, vec3(k_d), /*vec3(f_light * point_shadow)*//*reflect_color*/k_s, alpha, 1.0, emitted_light, reflected_light); @@ -208,7 +226,7 @@ void main() { // diffuse_light_point -= specular_light_point; // max_light += lights_at(f_pos, cam_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, /*k_d*/vec3(0.0), /*vec3(0.0)*/k_s, alpha, emitted_light, /*diffuse_light*/reflected_light); - max_light += lights_at(f_pos, cam_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, /*k_d*//*vec3(0.0)*/k_d, /*vec3(0.0)*/k_s, alpha, emitted_light, /*diffuse_light*/reflected_light); + max_light += lights_at(f_pos, cam_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, /*k_d*//*vec3(0.0)*/k_d, /*vec3(0.0)*/k_s, alpha, 1.0, emitted_light, /*diffuse_light*/reflected_light); float reflected_light_point = length(reflected_light);///*length*/(diffuse_light_point.r) + f_light * point_shadow; // TODO: See if we can be smarter about this using point light distances. @@ -226,7 +244,7 @@ void main() { // diffuse_light += point_light; // reflected_light += point_light; // vec3 surf_color = srgb_to_linear(vec3(0.2, 0.5, 1.0)) * light * diffuse_light * ambient_light; - vec3 surf_color = illuminate(max_light, emitted_light/* * log(1.0 - MU_WATER)*/, /*water_color * */reflected_light/* * log(1.0 - MU_WATER)*/); + vec3 surf_color = illuminate(max_light, view_dir, emitted_light/* * log(1.0 - MU_WATER)*/, /*cam_attenuation * *//*water_color * */reflected_light/* * log(1.0 - MU_WATER)*/); float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x); vec4 clouds; @@ -254,8 +272,9 @@ void main() { //vec4 color = vec4(surf_color, 1.0); // vec4 color = mix(vec4(reflect_color, 1.0), vec4(surf_color, 1.0 / (1.0 + /*diffuse_light*/(/*f_light * point_shadow*/reflected_light_point/* + point_light*//*reflected_light*/))), passthrough); - float log_cam = log(min(cam_attenuation.r, min(cam_attenuation.g, cam_attenuation.b))); - vec4 color = vec4(surf_color, passthrough * (1.0 - /*log(1.0 + cam_attenuation)*//*cam_attenuation*/1.0 / (1.0 - log_cam))); + // float log_cam = log(min(cam_attenuation.r, min(cam_attenuation.g, cam_attenuation.b))); + float min_refl = min(emitted_light.r, min(emitted_light.g, emitted_light.b)); + vec4 color = vec4(surf_color, passthrough * 1.0 / (1.0 + min_refl));// * (1.0 - /*log(1.0 + cam_attenuation)*//*cam_attenuation*/1.0 / (2.0 - log_cam))); // vec4 color = vec4(surf_color, mix(1.0, 1.0 / (1.0 + /*0.25 * *//*diffuse_light*/(/*f_light * point_shadow*/reflected_light_point)), passthrough)); // vec4 color = vec4(surf_color, mix(1.0, length(cam_attenuation), passthrough)); diff --git a/assets/voxygen/shaders/fluid-vert.glsl b/assets/voxygen/shaders/fluid-vert.glsl index 5c4bb3f758..9800f3e147 100644 --- a/assets/voxygen/shaders/fluid-vert.glsl +++ b/assets/voxygen/shaders/fluid-vert.glsl @@ -1,7 +1,24 @@ #version 330 core +#include + +#define LIGHTING_TYPE (LIGHTING_TYPE_TRANSMISSION | LIGHTING_TYPE_REFLECTION) + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_SPECULAR + +#if (FLUID_MODE == FLUID_MODE_CHEAP) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE +#elif (FLUID_MODE == FLUID_MODE_SHINY) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE +#endif + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + #include #include +#include in uint v_pos_norm; in uint v_col_light; @@ -26,7 +43,11 @@ void main() { // Small waves f_pos.xy += 0.01; // Avoid z-fighting - f_pos.z -= 0.1 + 0.1 * (sin(tick.x * 2.0 + f_pos.x * 2.0 + f_pos.y * 2.0) + 1.0) * 0.5; + // f_pos.x += 0.1 * sin(tick.x / 60 * hash(vec4(f_pos.xyz, 1.0))); + // f_pos.y += 0.1 * sin(tick.x / 60 * hash(vec4(f_pos.xyz, 2.0))); +#if (FLUID_MODE == FLUID_MODE_SHINY) + f_pos.z -= 0.1 + 0.1 * (sin(tick.x/* / 60.0*/* 2.0 + f_pos.x * 2.0 + f_pos.y * 2.0) + 1.0) * 0.5; +#endif f_col = vec3( float((v_col_light >> 8) & 0xFFu), diff --git a/assets/voxygen/shaders/include/cloud/regular.glsl b/assets/voxygen/shaders/include/cloud/regular.glsl index 71249695b9..60370f43ca 100644 --- a/assets/voxygen/shaders/include/cloud/regular.glsl +++ b/assets/voxygen/shaders/include/cloud/regular.glsl @@ -63,11 +63,11 @@ vec4 get_cloud_color(vec3 dir, vec3 origin, float time_of_day, float max_dist, f dist += fuzz * 0.01 * min(pow(dist * 0.005, 2.0), 1.0); vec3 pos = origin + dir * min(dist, max_dist); - vec2 sample = cloud_at(pos); + vec2 sample_ = cloud_at(pos); - float integral = sample.y * INCR; + float integral = sample_.y * INCR; passthrough *= 1.0 - integral; - cloud_shade = mix(cloud_shade, sample.x, passthrough * integral); + cloud_shade = mix(cloud_shade, sample_.x, passthrough * integral); dist += INCR * delta; if (passthrough < 0.1) { diff --git a/assets/voxygen/shaders/include/constants.glsl b/assets/voxygen/shaders/include/constants.glsl new file mode 100644 index 0000000000..4e4d9e4d61 --- /dev/null +++ b/assets/voxygen/shaders/include/constants.glsl @@ -0,0 +1,58 @@ +/* NOTE: When included, this file will contain values for the automatically defined settings specified below. */ + +/* TODO: Add the ability to control the tendency to do stuff in the vertex vs. fragment shader. + * Currently this flag is ignored and always set to prefer fragment, but this tradeoff is not correct on all + * machines in all cases (mine, for instance). */ +#define VOXYGEN_COMPUTATION_PREERENCE_FRAGMENT 0u +#define VOXYGEN_COMPUTATION_PREERENCE_VERTEX 1u + +#define FLUID_MODE_CHEAP 0u +#define FLUID_MODE_SHINY 1u + +#define CLOUD_MODE_NONE 0u +#define CLOUD_MODE_REGULAR 1u + +#define LIGHTING_ALGORITHM_LAMBERTIAN 0u +#define LIGHTING_ALGORITHM_BLINN_PHONG 1u +#define LIGHTING_ALGORITHM_ASHIKHMIN 2u + +/* Unlike the other flags (for now anyway), these are bitmask values */ +#define LIGHTING_TYPE_REFLECTION 0x01u +#define LIGHTING_TYPE_TRANSMISSION 0x02u + +/* Currently ignored, but ideally shoud be helpful for determining light transport properties. */ +#define LIGHTING_REFLECTION_KIND_DIFFUSE 0u +#define LIGHTING_REFLECTION_KIND_GLOSSY 1u +#define LIGHTING_REFLECTION_KIND_SPECULAR 2u + +#define LIGHTING_TRANSPORT_MODE_IMPORTANCE 0u +/* Radiance mode is currently used as a proxy for "attenuation and medium materials + * matter," but we may make it more granular. */ +#define LIGHTING_TRANSPORT_MODE_RADIANCE 1u + +#define LIGHTING_DISTRIBUTION_SCHEME_MICROFACET 0u +#define LIGHTING_DISTRIBUTION_SCHEME_VOXEL 1u + +#define LIGHTING_DISTRIBUTION_BECKMANN 0u +#define LIGHTING_DISTRIBUTION_TROWBRIDGE 1u + +/* Constants expected to be defined automatically by configuration: */ + +/* +#define VOXYGEN_COMPUTATION_PREERENCE +#define FLUID_MODE +#define CLOUD_MODE +#define LIGHTING_ALGORITHM +*/ + +/* Constants expected to be defined by any shader that needs to perform lighting calculations + * (but whose values may take automatically defined constants into account): */ + +/* +// At least one of LIGHTING_TYPE_REFLECTION or LIGHTING_TYPE_TRANSMISSION should be set. +#define LIGHTING_TYPE +#define LIGHTING_REFLECTION_KIND +#define LIGHTING_TRANSPORT_MODE +#define LIGHTING_DISTRIBUTION_SCHEME +#define LIGHTING_DISTRIBUTION +*/ diff --git a/assets/voxygen/shaders/include/light.glsl b/assets/voxygen/shaders/include/light.glsl index 153b49dbbd..cceadae608 100644 --- a/assets/voxygen/shaders/include/light.glsl +++ b/assets/voxygen/shaders/include/light.glsl @@ -25,9 +25,32 @@ float attenuation_strength(vec3 rpos) { return max(2.0 / pow(d2 + 10, 0.35) - pow(d2 / 50000.0, 0.8), 0.0); } -// Linear RGB, attenuation coefficients for water at roughly R, G, B wavelengths. -// See https://en.wikipedia.org/wiki/Electromagnetic_absorption_by_water -const vec3 MU_WATER = vec3(0.6, 0.04, 0.01); +#ifdef HAS_SHADOW_MAPS +uniform samplerCubeArrayShadow t_shadow_maps; + +float ShadowCalculation(uint lightIndex, vec3 fragToLight, float currentDepth) +{ + // return 1.0; + // use the light to fragment vector to sample from the depth map + float bias = 0.0;// 0.05; + // float closestDepth = texture(t_shadow_maps, vec4(fragToLight, lightIndex)/*, 0.0*//*, 0.0*//*, bias*/).r; + // // float closestDepth = texture(t_shadow_maps, vec4(fragToLight, lightIndex), bias); + // // it is currently in linear range between [0,1]. Re-transform back to original value + // closestDepth *= screen_res.w; // far plane + // // now test for shadows + // // float shadow = /*currentDepth*/(screen_res.w - bias) > closestDepth ? 1.0 : 0.0; + // float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; + // float visibility = textureProj(t_shadow_maps, vec4(fragToLight, lightIndex), bias); + float visibility = texture(t_shadow_maps, vec4(fragToLight, lightIndex), (currentDepth/* + screen_res.z*/) / screen_res.w);// / (screen_res.w/* - screen_res.z*/)/*1.0 -bias*//*-(currentDepth - bias) / screen_res.w*//*-screen_res.w*/); + + return visibility; +} +#else +float ShadowCalculation(uint lightIndex, vec3 fragToLight, float currentDepth) +{ + return 1.0; +} +#endif // // Compute attenuation due to light passing through a substance that fills an area below a horizontal plane // // (e.g. in most cases, water below the water surface depth). @@ -114,15 +137,15 @@ float shadow_at(vec3 wpos, vec3 wnorm) { // mu is the attenuation coefficient for any substance on a horizontal plane. // cam_attenuation is the total light attenuation due to the substance for beams between the point and the camera. // surface_alt is the altitude of the attenuating surface. -float lights_at(vec3 wpos, vec3 wnorm, vec3 cam_to_frag, vec3 mu, vec3 cam_attenuation, float surface_alt, vec3 k_a, vec3 k_d, vec3 k_s, float alpha, inout vec3 emitted_light, inout vec3 reflected_light/*, out float shadow*/) { +float lights_at(vec3 wpos, vec3 wnorm, vec3 /*cam_to_frag*/view_dir, vec3 mu, vec3 cam_attenuation, float surface_alt, vec3 k_a, vec3 k_d, vec3 k_s, float alpha, float voxel_lighting, inout vec3 emitted_light, inout vec3 reflected_light/*, out float shadow*/) { // shadow = 0.0; vec3 ambient_light = vec3(0.0); vec3 directed_light = vec3(0.0); vec3 max_light = vec3(0.0); - const float LIGHT_AMBIENCE = 0.5; + const float LIGHT_AMBIENCE = 0.015625; - for (uint i = 0u; i < light_shadow_count.x; i ++) { + for (uint i = 0u; i < light_shadow_count.x/*32u*/; i ++) { // Only access the array once Light L = lights[i]; @@ -160,19 +183,25 @@ float lights_at(vec3 wpos, vec3 wnorm, vec3 cam_to_frag, vec3 mu, vec3 cam_atten // shadow = min(shadow, shade); // Compute reflectance. - vec3 light_dir = -difference / sqrt(distance_2); // normalize(-difference); + float light_distance = sqrt(distance_2); + vec3 light_dir = -difference / light_distance; // normalize(-difference); // light_dir = faceforward(light_dir, wnorm, light_dir); bool is_direct = dot(-light_dir, wnorm) > 0.0; // reflected_light += color * (distance_2 == 0.0 ? vec3(1.0) : light_reflection_factor(wnorm, cam_to_frag, light_dir, k_d, k_s, alpha)); vec3 direct_light_dir = is_direct ? light_dir : -light_dir; + // vec3 direct_norm_dir = is_direct ? wnorm : -wnorm; // Compute attenuation due to fluid. // Default is light_pos, so we take the whole segment length for this beam if it never intersects the surface, unlesss the beam itself // is above the surface, in which case we take zero (wpos). color *= cam_attenuation * compute_attenuation_point(wpos, -direct_light_dir, mu, surface_alt, light_pos.z < surface_alt ? light_pos : wpos); - vec3 direct_light = PI * color * strength * square_factor * light_reflection_factor(wnorm, cam_to_frag, direct_light_dir, k_d, k_s, alpha); - directed_light += is_direct ? direct_light * square_factor : vec3(0.0); - ambient_light += is_direct ? vec3(0.0) : direct_light * LIGHT_AMBIENCE; +#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0 + is_direct = true; +#endif + vec3 direct_light = PI * color * strength * square_factor * light_reflection_factor(/*direct_norm_dir*/wnorm, /*cam_to_frag*/view_dir, direct_light_dir, k_d, k_s, alpha, voxel_lighting); + float computed_shadow = ShadowCalculation(i, -difference, light_distance); + directed_light += /*is_direct ? */max(computed_shadow, /*LIGHT_AMBIENCE*/0.0) * direct_light * square_factor/* : vec3(0.0)*/; + ambient_light += is_direct ? vec3(0.0) : vec3(0.0); // direct_light * square_factor * LIGHT_AMBIENCE; vec3 cam_light_diff = light_pos - focus_pos.xyz; float cam_distance_2 = dot(cam_light_diff, cam_light_diff);// + 0.0001; @@ -193,7 +222,7 @@ float lights_at(vec3 wpos, vec3 wnorm, vec3 cam_to_frag, vec3 mu, vec3 cam_atten // mix(cam_strength, strength, cam_distance_2 / (cam_distance_2 + distance_2)); // max(cam_strength, strength);//mix(cam_strength, strength, clamp(distance_2 / /*pos_distance_2*/cam_distance_2, 0.0, 1.0)); // float both_strength = mix(cam_strength, strength, cam_distance_2 / sqrt(cam_distance_2 + distance_2)); - max_light += /*max(1.0, cam_strength)*//*min(cam_strength, 1.0)*//*max*//*max(both_strength, 1.0) * *//*cam_strength*/both_strength * square_factor * square_factor * PI * color; + max_light += /*max(1.0, cam_strength)*//*min(cam_strength, 1.0)*//*max*//*max(both_strength, 1.0) * *//*cam_strength*/computed_shadow * both_strength * square_factor * square_factor * PI * color; // max_light += /*max(1.0, cam_strength)*//*min(cam_strength, 1.0)*//*max*/max(cam_strength, 1.0/*, strength*//*1.0*/) * square_factor * square_factor * PI * color; // light += color * (max(0, max(dot(normalize(difference), wnorm), 0.15)) + LIGHT_AMBIENCE); // Compute emiittance. @@ -211,6 +240,6 @@ float lights_at(vec3 wpos, vec3 wnorm, vec3 cam_to_frag, vec3 mu, vec3 cam_atten } // Same as lights_at, but with no assumed attenuation due to fluid. -float lights_at(vec3 wpos, vec3 wnorm, vec3 cam_to_frag, vec3 k_a, vec3 k_d, vec3 k_s, float alpha, inout vec3 emitted_light, inout vec3 reflected_light) { - return lights_at(wpos, wnorm, cam_to_frag, vec3(0.0), vec3(1.0), 0.0, k_a, k_d, k_s, alpha, emitted_light, reflected_light); +float lights_at(vec3 wpos, vec3 wnorm, vec3 view_dir, vec3 k_a, vec3 k_d, vec3 k_s, float alpha, inout vec3 emitted_light, inout vec3 reflected_light) { + return lights_at(wpos, wnorm, view_dir, vec3(0.0), vec3(1.0), 0.0, k_a, k_d, k_s, alpha, 1.0, emitted_light, reflected_light); } diff --git a/assets/voxygen/shaders/include/lod.glsl b/assets/voxygen/shaders/include/lod.glsl index a24d4c34b8..a788e096f7 100644 --- a/assets/voxygen/shaders/include/lod.glsl +++ b/assets/voxygen/shaders/include/lod.glsl @@ -73,7 +73,7 @@ vec4 textureBicubic(sampler2D sampler, vec2 texCoords) { } float alt_at(vec2 pos) { - return texture/*textureBicubic*/(t_map, pos_to_uv(t_map, pos)).a * (/*1300.0*//*1278.7266845703125*/view_distance.w) + /*140.0*/view_distance.z; + return (texture/*textureBicubic*/(t_map, pos_to_uv(t_map, pos)).a * (/*1300.0*//*1278.7266845703125*/view_distance.w) + /*140.0*/view_distance.z); //+ (texture(t_noise, pos * 0.002).x - 0.5) * 64.0; // return 0.0 @@ -83,7 +83,12 @@ float alt_at(vec2 pos) { } float alt_at_real(vec2 pos) { - return textureBicubic(t_map, pos_to_tex(pos)).a * (/*1300.0*//*1278.7266845703125*/view_distance.w) + /*140.0*/view_distance.z; + // Basic idea: only really need the real altitude for an accurate water height estimation, so if we are in the cheap shader take a shortcut. +// #if (FLUID_MODE == FLUID_MODE_CHEAP) +// return alt_at(pos); +// #elif (FLUID_MODE == FLUID_MODE_SHINY) + return (textureBicubic(t_map, pos_to_tex(pos)).a * (/*1300.0*//*1278.7266845703125*/view_distance.w) + /*140.0*/view_distance.z); +// #endif //+ (texture(t_noise, pos * 0.002).x - 0.5) * 64.0; // return 0.0 @@ -271,6 +276,6 @@ vec3 lod_pos(vec2 pos, vec2 focus_pos) { vec3 lod_col(vec2 pos) { //return vec3(0, 0.5, 0); return /*linear_to_srgb*/(textureBicubic(t_map, pos_to_tex(pos)).rgb) - + (texture(t_noise, pos * 0.04 + texture(t_noise, pos * 0.005).xy * 2.0 + texture(t_noise, pos * 0.06).xy * 0.6).x - 0.5) * 0.1; + ;//+ (texture(t_noise, pos * 0.04 + texture(t_noise, pos * 0.005).xy * 2.0 + texture(t_noise, pos * 0.06).xy * 0.6).x - 0.5) * 0.1; //+ (texture(t_noise, pos * 0.04 + texture(t_noise, pos * 0.005).xy * 2.0 + texture(t_noise, pos * 0.06).xy * 0.6).x - 0.5) * 0.1; } diff --git a/assets/voxygen/shaders/include/sky.glsl b/assets/voxygen/shaders/include/sky.glsl index 10f2f33d54..276d58ffe1 100644 --- a/assets/voxygen/shaders/include/sky.glsl +++ b/assets/voxygen/shaders/include/sky.glsl @@ -8,7 +8,7 @@ const float PI = 3.141592; const vec3 SKY_DAY_TOP = vec3(0.1, 0.5, 0.9); const vec3 SKY_DAY_MID = vec3(0.02, 0.28, 0.8); const vec3 SKY_DAY_BOT = vec3(0.1, 0.2, 0.3); -const vec3 DAY_LIGHT = vec3(1.5, 1.4, 1.0); +const vec3 DAY_LIGHT = vec3(1.5, 1.4, 1.0);//vec3(1.5, 1.4, 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); @@ -26,9 +26,9 @@ const vec3 NIGHT_LIGHT = vec3(0.002, 0.02, 0.02); // Linear RGB, scattering coefficients for atmosphere at roughly R, G, B wavelengths. // // See https://en.wikipedia.org/wiki/Diffuse_sky_radiation -const vec3 MU_SCATTER = vec3(0.05, 0.10, 0.23); +const vec3 MU_SCATTER = vec3(0.05, 0.10, 0.23) * 2.0; -const float SUN_COLOR_FACTOR = 6.0;//1.8; +const float SUN_COLOR_FACTOR = 6.0;//6.0;// * 1.5;//1.8; const float UNDERWATER_MIST_DIST = 100.0; @@ -423,12 +423,16 @@ float fog(vec3 f_pos, vec3 focus_pos, uint medium) { float avg_col = (color.r + color.g + color.b) / 3.0; return ((color - avg_col) * light + (diffuse + ambience) * avg_col) * (diffuse + ambience); } */ -vec3 illuminate(float max_light, /*vec3 max_light, */vec3 emitted, vec3 reflected) { +vec3 illuminate(float max_light, vec3 view_dir, /*vec3 max_light, */vec3 emitted, vec3 reflected) { const float NIGHT_EXPOSURE = 10.0; const float DUSK_EXPOSURE = 2.0;//0.8; const float DAY_EXPOSURE = 1.0;//0.7; +#if (LIGHTING_ALGORITHM == LIGHTING_ALGORITHM_ASHIKHMIN) const float DAY_SATURATION = 1.1; +#else + const float DAY_SATURATION = 1.0; +#endif const float DUSK_SATURATION = 0.6; const float NIGHT_SATURATION = 0.1; @@ -460,6 +464,10 @@ vec3 illuminate(float max_light, /*vec3 max_light, */vec3 emitted, vec3 reflecte DAY_EXPOSURE, max(-sun_dir.z, 0) ); + vec3 now_light = moon_dir.z < 0 ? moon_dir : sun_dir; + float cos_view_light = dot(-now_light, view_dir); + // alpha *= exp(1.0 - cos_view_light); + // sky_light *= 1.0 - log(1.0 + view_dir.z); float alph = sky_light > 0.0 && max_light > 0.0 ? mix(1.0 / log(/*1.0*//*1.0 + *//*lum_sky + */1.0 + max_light / (0.0 + sky_light)), 1.0, clamp(max_light - sky_light, 0.0, 1.0)) : 1.0; alpha = alpha * min(alph, 1.0);//((max_light > 0.0 && max_light > sky_light /* && sky_light > 0.0*/) ? /*1.0*/1.0 / log(/*1.0*//*1.0 + *//*lum_sky + */1.0 + max_light - (0.0 + sky_light)) : 1.0); // alpha = alpha * min(1.0, (max_light == 0.0 ? 1.0 : (1.0 + abs(lum_sky)) / /*(1.0 + max_light)*/max_light)); @@ -505,7 +513,8 @@ vec3 illuminate(float max_light, /*vec3 max_light, */vec3 emitted, vec3 reflecte // vec3 c = sqrt(col_adjusted) * T; // vec3 c = /*col_adjusted * */col_adjusted * T; - return c; + return color; + // return c; // float sum_col = color.r + color.g + color.b; // return /*srgb_to_linear*/(/*0.5*//*0.125 * */vec3(pow(color.x, gamma), pow(color.y, gamma), pow(color.z, gamma))); } diff --git a/assets/voxygen/shaders/include/srgb.glsl b/assets/voxygen/shaders/include/srgb.glsl index 360b5f4b3b..d2408923a3 100644 --- a/assets/voxygen/shaders/include/srgb.glsl +++ b/assets/voxygen/shaders/include/srgb.glsl @@ -1,3 +1,7 @@ +// Linear RGB, attenuation coefficients for water at roughly R, G, B wavelengths. +// See https://en.wikipedia.org/wiki/Electromagnetic_absorption_by_water +const vec3 MU_WATER = vec3(0.6, 0.04, 0.01); + //https://gamedev.stackexchange.com/questions/92015/optimized-linear-to-srgb-glsl vec3 srgb_to_linear(vec3 srgb) { bvec3 cutoff = lessThan(srgb, vec3(0.04045)); @@ -54,7 +58,7 @@ float BeckmannDistribution_D_Voxel(vec3 wh, vec3 norm, float alpha) { // vec3 cos_sides_i = /*sides * */sides * norm; // vec3 cos_sides_o = max(sides * view_dir, 0.0); - vec3 NdotH = max(wh * sides, 0.0);/*cos_sides_i*///max(sides * wh, 0.0); + vec3 NdotH = wh * sides;//max(wh * sides, 0.0);/*cos_sides_i*///max(sides * wh, 0.0); const float PI = 3.1415926535897932384626433832795; vec3 NdotH2 = NdotH * NdotH; @@ -96,6 +100,27 @@ float BeckmannDistribution_D_Voxel(vec3 wh, vec3 norm, float alpha) { // return voxel_norm; } +float TrowbridgeReitzDistribution_D_Voxel(vec3 wh, vec3 norm, float alpha) { + vec3 sides = sign(norm); + // vec3 cos_sides_i = /*sides * */sides * norm; + // vec3 cos_sides_o = max(sides * view_dir, 0.0); + + vec3 NdotH = wh * sides;//max(wh * sides, 0.0);/*cos_sides_i*///max(sides * wh, 0.0); + + const float PI = 3.1415926535897932384626433832795; + vec3 NdotH2 = NdotH * NdotH; + // vec3 m2 = alpha * alpha; + // vec3 NdotH2m2 = NdotH2 * m2; + vec3 NdotH2m2 = NdotH2 * alpha * alpha; + // vec3 Tan2Theta = (1 - NdotH2) / NdotH2; + // vec3 e = (NdotH2 / m2 + (1 - NdotH2) / m2) * Tan2Theta; + // vec3 e = 1 / m2 * (1 - NdotH2) / NdotH2; + vec3 e = (1 - NdotH2) / NdotH2m2; + vec3 k_spec = 1.0 / (PI * NdotH2m2 * NdotH2 * (1 + e) * (1 + e)); + // vec3 k_spec = exp((NdotH2 - 1) / NdotH2m2) / (PI * NdotH2m2 * NdotH2); + return dot(mix(k_spec, /*cos_sides_o*/vec3(0.0), equal(NdotH, vec3(0.0))), /*cos_sides_i*/abs(norm)); +} + float BeckmannDistribution_Lambda(vec3 norm, vec3 dir, float alpha) { float CosTheta = /*max(dot(norm, dir), 0.0);*/dot(norm, dir); /* if (CosTheta == 0.0) { @@ -162,7 +187,12 @@ vec3 FresnelBlend_f(vec3 norm, vec3 dir, vec3 light_dir, vec3 R_d, vec3 R_s, flo (1 - pow5(1 - .5f * AbsCosTheta(wo))); */ // Vector3f wh = wi + wo; vec3 wh = -light_dir + dir; - if (cos_wi <= 0.0 || cos_wo <= 0.0) { +#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0 + bool is_blocked = cos_wi == 0.0 || cos_wo == 0.0; +#else + bool is_blocked = cos_wi <= 0.0 || cos_wo <= 0.0; +#endif + if (is_blocked) { return vec3(/*diffuse*/0.0); } // if (cos_wo < 0.0) { @@ -178,8 +208,8 @@ vec3 FresnelBlend_f(vec3 norm, vec3 dir, vec3 light_dir, vec3 R_d, vec3 R_s, flo wh = normalize(wh);//mix(normalize(wh), vec3(0.0), equal(light_dir, dir)); float dot_wi_wh = dot(-light_dir, wh); vec3 specular = BeckmannDistribution_D(dot(wh, norm), alpha) / - (4 * abs(dot_wi_wh)) * - max(abs(cos_wi), abs(cos_wo)) * + (4 * abs(dot_wi_wh) * + max(abs(cos_wi), abs(cos_wo))) * schlick_fresnel(R_s, dot_wi_wh); // Spectrum specular = distribution->D(wh) / // (4 * AbsDot(wi, wh) * @@ -199,26 +229,71 @@ vec3 FresnelBlend_Voxel_f(vec3 norm, vec3 dir, vec3 light_dir, vec3 R_d, vec3 R_ float cos_wi = /*max(*/dot(-light_dir, norm)/*, 0.0)*/; float cos_wo = /*max(*/dot(dir, norm)/*, 0.0)*/; +#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0 + vec4 AbsNdotL = abs(vec4(light_dir, cos_wi)); + vec4 AbsNdotV = abs(vec4(dir, cos_wo)); +#else vec3 sides = sign(norm); - vec4 diffuse_factor = - (1.0 - pow5(1.0 - 0.5 * max(vec4(-light_dir * sides, abs(cos_wi)), 0.0))) * - (1.0 - pow5(1.0 - 0.5 * max(vec4(dir * sides, abs(cos_wo)), 0.0))); + vec4 AbsNdotL = vec4(max(-light_dir * sides, 0.0), abs(cos_wi)); + vec4 AbsNdotV = vec4(max(dir * sides, 0.0), abs(cos_wo)); +#endif - vec3 diffuse = (28.0 / (23.0 * PI)) * R_d * + // float R_r = 1.0 - R_s; + // float R_r = 1.0 - schlick_fresnel(R_s, cos_wi); + // // Rs + pow5(1.0 - cosTheta) * (1.0 - Rs) + // vec4 R_r = 1.0 - (R_s + (1.0 - R_s) * schlick_fresnel(R_s, cos_wi)); + // mat4 R_r = 1.0 - (vec4(R_s, 0.0) + vec4(1.0 - R_s, 0.0) * pow5(1.0 - AbsNdotL)); + // vec4 AbsNdotL5 = pow5(1.0 - AbsNdotL); + // vec4 R_s4 = vec4(R_s, 0.0); + // mat4 R_r = + // // mat4(1.0 - (R_s.r + (1.0 - R_s.r) * AbsNdotL5), + // // 1.0 - (R_s.g + (1.0 - R_s.g) * AbsNdotL5), + // // 1.0 - (R_s.b + (1.0 - R_s.b) * AbsNdotL5), + // // vec4(0.0) + // // ); + // mat4(1.0 - (R_s4 + (1.0 - R_s4) * AbsNdotL5.x), + // 1.0 - (R_s4 + (1.0 - R_s4) * AbsNdotL5.y), + // 1.0 - (R_s4 + (1.0 - R_s4) * AbsNdotL5.z), + // 1.0 - (R_s4 + (1.0 - R_s4) * AbsNdotL5.w) + // ); + // * ) (R1.0 - R_s.r) 1.0 - (vec4(R_s, 0.0) + vec4(1.0 - R_s, 0.0) * pow5(1.0 - AbsNdotL)); + + vec4 diffuse_factor = + // vec4(abs(vec4(-light_dir * sides, cos_wi))) + (1.0 - pow5(1.0 - 0.5 * AbsNdotL)) * + // (1.0 - pow5(1.0 - 0.5 * abs(vec4(-light_dir * sides, cos_wi)))) * + // (1.0 - pow5(1.0 - 0.5 * abs(vec4(dir * sides, cos_wo)))) + (1.0 - pow5(1.0 - 0.5 * AbsNdotV)) + // vec4(1.0) + ; + /* vec4 diffuse_factor = + (1.0 - pow5(1.0 - 0.5 * max(vec4(-light_dir * sides, abs(cos_wi)), 0.0))) * + (1.0 - pow5(1.0 - 0.5 * max(vec4(dir * sides, abs(cos_wo)), 0.0))); */ + + vec3 diffuse = (28.0 / (23.0 * PI))/*(1.0 / PI)*/ * R_d * (1.0 - R_s) * - dot(diffuse_factor, vec4(abs(norm) * (1.0 - dist), dist)); + //vec3( + dot(diffuse_factor, /*R_r * */vec4(abs(norm) * (1.0 - dist), dist)) + //) + ; vec3 wh = -light_dir + dir; - if (cos_wi <= 0.0 || cos_wo <= 0.0) { +#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0 + bool is_blocked = cos_wi == 0.0 || cos_wo == 0.0; +#else + bool is_blocked = cos_wi <= 0.0 || cos_wo <= 0.0; +#endif + if (is_blocked) { return vec3(/*diffuse*/0.0); } wh = normalize(wh);//mix(normalize(wh), vec3(0.0), equal(light_dir, dir)); float dot_wi_wh = dot(-light_dir, wh); + // float distr = TrowbridgeReitzDistribution_D_Voxel(wh, norm, alpha); float distr = BeckmannDistribution_D_Voxel(wh, norm, alpha); // float distr = BeckmannDistribution_D(dot(wh, norm), alpha); vec3 specular = distr / - (4 * abs(dot_wi_wh)) * - max(abs(cos_wi), abs(cos_wo)) * + (4 * abs(dot_wi_wh) * + max(abs(cos_wi), abs(cos_wo))) * schlick_fresnel(R_s, dot_wi_wh); return mix(/*diffuse*//* + specular*/diffuse + specular, vec3(0.0), bvec3(all(equal(light_dir, dir)))); } @@ -226,7 +301,7 @@ vec3 FresnelBlend_Voxel_f(vec3 norm, vec3 dir, vec3 light_dir, vec3 R_d, vec3 R_ // Phong reflection. // // Note: norm, dir, light_dir must all be normalizd. -vec3 light_reflection_factor(vec3 norm, vec3 dir, vec3 light_dir, vec3 k_d, vec3 k_s, float alpha) { +vec3 light_reflection_factor2(vec3 norm, vec3 dir, vec3 light_dir, vec3 k_d, vec3 k_s, float alpha) { // TODO: These are supposed to be the differential changes in the point location p, in tangent space. // That is, assuming we can parameterize a 2D surface by some function p : R² → R³, mapping from // points in a plane to 3D points on the surface, we can define @@ -291,11 +366,67 @@ vec3 light_reflection_factor(vec3 norm, vec3 dir, vec3 light_dir, vec3 k_d, vec3 } vec3 light_reflection_factor(vec3 norm, vec3 dir, vec3 light_dir, vec3 k_d, vec3 k_s, float alpha, float voxel_lighting) { - //if (voxel_lighting < 1.0) { +#if (LIGHTING_ALGORITHM == LIGHTING_ALGORITHM_LAMBERTIAN) + const float PI = 3.141592; +#if (LIGHTING_DISTRIBUTION_SCHEME == LIGHTING_DISTRIBUTION_SCHEME_VOXEL) +#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0 + vec4 AbsNdotL = abs(vec4(light_dir, dot(norm, light_dir))); +#else + vec3 sides = sign(norm); + vec4 AbsNdotL = max(vec4(-light_dir * sides, dot(norm, -light_dir)), 0.0); +#endif + float diffuse = dot(AbsNdotL, vec4(abs(norm) * (1.0 - voxel_lighting), voxel_lighting)); +#elif (LIGHTING_DISTRIBUTION_SCHEME == LIGHTING_DISTRIBUTION_SCHEME_MICROFACET) +#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0 + float diffuse = abs(dot(norm, light_dir)); +#else + float diffuse = max(dot(norm, -light_dir), 0.0); +#endif +#endif + return k_d / PI * diffuse; +#elif (LIGHTING_ALGORITHM == LIGHTING_ALGORITHM_BLINN_PHONG) + const float PI = 3.141592; + alpha = alpha * sqrt(2.0); +#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0 + float ndotL = abs(dot(norm, light_dir)); +#else + float ndotL = max(dot(norm, -light_dir), 0.0); +#endif + + if (ndotL > 0.0) { +#if (LIGHTING_DISTRIBUTION_SCHEME == LIGHTING_DISTRIBUTION_SCHEME_VOXEL) +#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0 + vec4 AbsNdotL = abs(vec4(light_dir, ndotL)); +#else + vec3 sides = sign(norm); + vec4 AbsNdotL = max(vec4(-light_dir * sides, ndotL), 0.0); +#endif + float diffuse = dot(AbsNdotL, vec4(abs(norm) * (1.0 - voxel_lighting), voxel_lighting)); +#elif (LIGHTING_DISTRIBUTION_SCHEME == LIGHTING_DISTRIBUTION_SCHEME_MICROFACET) + float diffuse = ndotL; +#endif + vec3 H = normalize(-light_dir + dir); + +#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0 + float NdotH = abs(dot(norm, H)); +#else + float NdotH = max(dot(norm, H), 0.0); +#endif + return (1.0 - k_s) / PI * k_d * diffuse + k_s * pow(NdotH, alpha/* * 4.0*/); + } + + return vec3(0.0); +#elif (LIGHTING_ALGORITHM == LIGHTING_ALGORITHM_ASHIKHMIN) +#if (LIGHTING_DISTRIBUTION_SCHEME == LIGHTING_DISTRIBUTION_SCHEME_VOXEL) return FresnelBlend_Voxel_f(norm, dir, light_dir, k_d/* * max(dot(norm, -light_dir), 0.0)*/, k_s, alpha, voxel_lighting); +#elif (LIGHTING_DISTRIBUTION_SCHEME == LIGHTING_DISTRIBUTION_SCHEME_MICROFACET) + //if (voxel_lighting < 1.0) { + return FresnelBlend_f(norm, dir, light_dir, k_d/* * max(dot(norm, -light_dir), 0.0)*/, k_s, alpha); //} else { // return FresnelBlend_f(norm, dir, light_dir, k_d/* * max(dot(norm, -light_dir), 0.0)*/, k_s, alpha); //} +#endif +#endif } float rel_luminance(vec3 rgb) @@ -338,6 +469,9 @@ bool IntersectRayPlane(vec3 rayOrigin, vec3 rayDirection, vec3 posOnPlane, vec3 // // Ideally, defaultpos is set so we can avoid branching on error. vec3 compute_attenuation(vec3 wpos, vec3 ray_dir, vec3 mu, float surface_alt, vec3 defaultpos) { +#if (LIGHTING_TRANSPORT_MODE == LIGHTING_TRANSPORT_MODE_IMPORTANCE) + return vec3(1.0); +#elif (LIGHTING_TRANSPORT_MODE == LIGHTING_TRANSPORT_MODE_RADIANCE) // return vec3(1.0); /*if (mu == vec3(0.0)) { return vec3(1.0); @@ -345,17 +479,41 @@ vec3 compute_attenuation(vec3 wpos, vec3 ray_dir, vec3 mu, float surface_alt, ve return vec3(0.0); }*/ // return vec3(0.0); - vec3 surface_dir = /*surface_alt < wpos.z ? vec3(0.0, 0.0, -1.0) : vec3(0.0, 0.0, 1.0)*/vec3(0.0, 0.0, sign(surface_alt - wpos.z)); - // vec3 surface_dir = surface_alt < wpos.z ? vec3(0.0, 0.0, -1.0) : vec3(0.0, 0.0, 1.0); + // vec3 surface_dir = /*surface_alt < wpos.z ? vec3(0.0, 0.0, -1.0) : vec3(0.0, 0.0, 1.0)*/vec3(0.0, 0.0, sign(surface_alt - wpos.z)); + vec3 surface_dir = surface_alt < wpos.z ? vec3(0.0, 0.0, -1.0) : vec3(0.0, 0.0, 1.0); // vec3 surface_dir = faceforward(vec3(0.0, 0.0, 1.0), ray_dir, vec3(0.0, 0.0, 1.0)); bool _intersects_surface = IntersectRayPlane(wpos, ray_dir, vec3(0.0, 0.0, surface_alt), surface_dir, defaultpos); float depth = length(defaultpos - wpos); return exp(-mu * depth); +#endif +} + +vec3 compute_attenuation2(vec3 wpos, vec3 ray_dir, vec3 mu, float surface_alt, vec3 defaultpos) { +#if (LIGHTING_TRANSPORT_MODE == LIGHTING_TRANSPORT_MODE_IMPORTANCE) + return vec3(1.0); +#elif (LIGHTING_TRANSPORT_MODE == LIGHTING_TRANSPORT_MODE_RADIANCE) + // return vec3(1.0); + /*if (mu == vec3(0.0)) { + return vec3(1.0); + }*//* else { + return vec3(0.0); + }*/ + // return vec3(0.0); + // vec3 surface_dir = /*surface_alt < wpos.z ? vec3(0.0, 0.0, -1.0) : vec3(0.0, 0.0, 1.0)*/vec3(0.0, 0.0, sign(surface_alt - wpos.z)); + vec3 surface_dir = surface_alt < wpos.z ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0); + // vec3 surface_dir = faceforward(vec3(0.0, 0.0, 1.0), ray_dir, vec3(0.0, 0.0, 1.0)); + bool _intersects_surface = IntersectRayPlane(wpos, ray_dir, vec3(0.0, 0.0, surface_alt), surface_dir, defaultpos); + float depth = length(defaultpos - wpos); + return exp(-mu * depth); +#endif } // Same as compute_attenuation but since both point are known, set a maximum to make sure we don't exceed the length // from the default point. vec3 compute_attenuation_point(vec3 wpos, vec3 ray_dir, vec3 mu, float surface_alt, vec3 defaultpos) { +#if (LIGHTING_TRANSPORT_MODE == LIGHTING_TRANSPORT_MODE_IMPORTANCE) + return vec3(1.0); +#elif (LIGHTING_TRANSPORT_MODE == LIGHTING_TRANSPORT_MODE_RADIANCE) // return vec3(1.0); /*if (mu == vec3(0.0)) { return vec3(1.0); @@ -370,4 +528,5 @@ vec3 compute_attenuation_point(vec3 wpos, vec3 ray_dir, vec3 mu, float surface_a bool _intersects_surface = IntersectRayPlane(wpos, ray_dir, vec3(0.0, 0.0, surface_alt), surface_dir, defaultpos); float depth2 = min(max_length, dot(defaultpos - wpos, defaultpos - wpos)); return exp(-mu * sqrt(depth2)); +#endif } diff --git a/assets/voxygen/shaders/light-shadows-frag.glsl b/assets/voxygen/shaders/light-shadows-frag.glsl new file mode 100644 index 0000000000..a9619fc528 --- /dev/null +++ b/assets/voxygen/shaders/light-shadows-frag.glsl @@ -0,0 +1,41 @@ +// NOTE: We currently do nothing, and just rely on the default shader behavior. +// +// However, in the future we might apply some depth transforms here. + +#version 330 core + +#include + +#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY + +#if (FLUID_MODE == FLUID_MODE_CHEAP) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE +#elif (FLUID_MODE == FLUID_MODE_SHINY) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE +#endif + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + +// Currently, we only need globals for the far plane. +#include +// Currently, we only need lights for the light position +#include + +in vec4 FragPos; // FragPos from GS (output per emitvertex) +flat in int FragLayer; + +void main() +{ + // get distance between fragment and light source + float lightDistance = length(FragPos.xyz - lights[FragLayer & 31].light_pos.xyz); + + // map to [0;1] range by dividing by far_plane + lightDistance = lightDistance / /*FragPos.w;*/screen_res.w; + + // write this as modified depth + gl_FragDepth = lightDistance; +} diff --git a/assets/voxygen/shaders/light-shadows-geom.glsl b/assets/voxygen/shaders/light-shadows-geom.glsl new file mode 100644 index 0000000000..b1b8d92dfb --- /dev/null +++ b/assets/voxygen/shaders/light-shadows-geom.glsl @@ -0,0 +1,198 @@ +// Adapted from https://learnopengl.com/Advanced-Lighting/Shadows/Point-Shadows + +// NOTE: We only technically need this for cube map arrays and geometry shader +// instancing. +#version 400 core + +// Currently, we only need globals for the max light count (light_shadow_count.x). +#include + +// Since our output primitive is a triangle strip, we have to render three vertices +// each. +#define VERTICES_PER_FACE 3 + +// Since we render our depth texture to a cube map, we need to render each face +// six times. If we used other shadow mapping methods with fewer outputs, this would +// shrink considerably. +#define FACES_PER_POINT_LIGHT 6 + +// If MAX_VERTEX_UNIFORM_COMPONENTS_ARB = 512 on many platforms, and we want a mat4 +// for each of 6 directions for each light, 20 is close to the maximum allowable +// size. We could add a final matrix for the directional light of the sun or moon +// to bring us to 126 matrices, which is just 2 off. +// +// To improve this limit, we could do many things, such as: +// - choose an implementation that isn't cube maps (e.g. tetrahedrons or curves; +// if there were an easy way to sample from tetrahedrons, we'd be at 32 * 4 = 128 +// exactly, leaving no room for a solar body, though). +// - Do more work in the geometry shader (e.g. just have a single projection +// matrix per light, and derive the different-facing components; or there may be +// other ways of greatly simplifying this). The tradeoff would be losing performance +// here. +// - Use ARB_instanced_arrays and switch lights with indexing, instead of a uniform +// buffer. This would probably work fine (and ARB_instanced_arrays is supported on +// pretty much every platform), but AFAIK it's possible that instanced arrays are +// slower than uniform arraay access on many platforms. +// - Don't try to do everything in one call (break this out into multiple passes). +// +// Actually, according to what I'm reading, MAX_GEOM_UNIFORM_COMPONENTS = 1024, and +// gl_MaxGeometryUniformComponents = 1024. +// +// Also, this only applies to uniforms defined *outside* of uniform blocks, of which +// there can be up to 12 (14 in OpenGL 4.3, which we definitely can't support). +// GL_MAX_UNIFORM_BLOCK_SIZE has a minimum of 16384, which *easily* exceeds our usage +// constraints. So this part might not matter. +// +// Other restrictions are easy to satisfy: +// +// gl_MaxGeometryVaryingComponents has a minimum of 64 and is the maximum number of +// varying components; I think this is the number of out components per vertex, which +// is technically 0, but would be 4 if we wrote FragPos. But it might also +// be the *total* number of varying components, in which case if we wrote FragPos +// it would be 4 * 20 * 6 * 3 = 1440, which would blow it out of the water. However, +// I kind of doubt this interpretation because writing FragPos for each of 18 vertices, +// as the original shader did, already yields 4 * 18 = 72, and it seems unlikely that +// the original example exceeds OpenGL limits. +// +// gl_MaxGeometryOutputComponents has a minimum of 128 and is the maximum number of +// components allowed in out variables; we easily fall under this since we actually +// have 0 of these. However, if we were to write FragPos for each vertex, it *might* +// cause us to exceed this limit, depending on whether it refers to the total output +// component count *including* varying components, or not. See the previous +// discussion; since 72 < 128 it's more plausible that this interpretation might be +// correct, but hopefully it's not. +// +// gl_MaxGeometryInputComponents has a minimum of 64 and we easily fall under that +// limit (I'm actually not sure we even have any user-defined input components?). +// +// gl_MaxGeometryTextureImageUnits = 16 and we have no texture image units (or maybe +// 1, the one we bound?). This might come into play if we were to have attached +// cubemaps instead of a single cubemap array, in which case it would limit us to +// 16 lights *regardless* of any of the fixes mentioned above (i.e., we'd just have +// to split up draw calls, I think). +// +// --- +// +// However, there is another limit to consider: GL_MAX_GEOMETRY_OUTPUT_VERTICES. Its +// minimum is 256, and 20 * 6 * 3 = 360, which exceeds that. This introduces a new +// limit of at most 14 point lights. +// +// Another, related limit is GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS. This counts +// every component output ("component" is usually a 4-byte field of a vector, but maybe +// this would improve with something like half-floats?), and has a minimum (as of +// OpenGL 3.3) of 1024. Since even builtin outputs gl_Layer count against this total, +// this means we issue 5 components per vertex, and 14 * 6 * 3 * 5 = 1260 > 1024. +// +// Ultimately, we find our maximum output limit of 11, ≤ 1024/5/3/6. +// +// If we choose to reserve a slot for a non-point light (and/or other uniforms), it +// is just 10, or half what we got from VERTICES_PER_FACE (we could also round down to +// 8 as a power of 2, if we had to). +// +// Unlike the input limits, whwich we can get around with "clever" solutions, it seems +// likely that the only real way to defeat the vertex limits is to use instancing of +// some sort (be it geometry shader or otherwise). This would restrict us to OpenGL +// 4.0 or above. +// +// A further consideration (were we to switch to OpenGL 4.1-supported features, but +// actually it is often supported on 3.3 hardware with ARB_viewport_array--whereas +// geometry shader instancing is *not* supported on any 3.3 hardware, so would actually +// require us to upgrade) would be setting gl_ViewportIndex. The main reason to consider +// this is that it allows specifying a separate scissor rectangle per viewport. This +// introduces two new constraints. Firstly, it adds an extra component to each vertex +// (lowering our maximum to 9 faces per light ≤ 1024/6/3/6, or 8 if we want to support a +// directional light). +// +// Secondly, a new constant (MAX_VIEWPORTS) is introduced, which would restrict the +// total number of active viewports; the minimum value for this is 16. While this may +// not seem all that relevant since our current hard limit is 11, the difference is that +// this limit would apply *across* instanced calls (since it may be a "global" +// restriction, tied to the OpenGL context; this means it couldn't even be a multiple +// frame buffer thing, as there is usually one per window). This would also tie in +// with gl_MaxGeometryTextureImageUnits, I guess. +// +// -- +// +// I just realized tht using cube map arrays at all bumps our required OpenGL +// version to 4.0, so let's just do instancing... +// +// The instancing limit on MAX_GEOMETRY_SHADER_INVOCATIONS has a minimum of 32, which +// would be sufficient to run through all 32 lights with a different cube map and +// completely removes any imits on ight count. +// +// This should instantly bring us below all relevant limits in all cases considered +// except for the two that would require 16. Unfortunately, 32 is also the *maximum* +// number of point lights, which is much higher than the usual value, and the instance +// count has to be a constant. If we were to instead geometry-shader-instance each +// *face*, we'd get a maximum light count of 56 ≤ 1024/6/3, which is not as elegant +// but is easily higher than 32. So, let's try using that instead. +// +// It is *possible* that using instancing on the *vertex* shader with the (dynamically +// uniform) total number of instances set to the actual number of point lights, would +// improve performance, since it would give us a 1:1 vertex input:output ratio, which +// might be optimized in hardware. +// +// It also seems plausible that constructing a separate geometry shader with values +// from 1 to 32 would be worthwhile, but that seems a little extreme. +// +// --- +// +// Since wgpu doesn't support geometry shaders anyway, it seems likely that we'll have +// to do the multiple draw calls, anyway... I don't think gl_Layer can be set from +// outside a geometry shader. But in wgpu, such a thing is much cheaper, anyway. +#define MAX_POINT_LIGHTS 32 + +// We use geometry shader instancing to construct each face separately. +#define MAX_LAYER_VERTICES_PER_FACE (MAX_POINT_LIGHTS * VERTICES_PER_FACE) + +#define MAX_LAYER_FACES (MAX_POINT_LIGHTS * FACES_PER_POINT_LIGHT) + +layout (triangles, invocations = 6) in; + +layout (triangle_strip, max_vertices = /*MAX_LAYER_VERTICES_PER_FACE*/96) out; + +struct ShadowLocals { + mat4 shadowMatrices; +}; + +layout (std140) +uniform u_light_shadows { + ShadowLocals shadowMats[/*MAX_LAYER_FACES*/192]; +}; + +// NOTE: We choose not to output FragPos currently to save on space limitations +// (see extensive documentation above). However, as these limitations have been +// relaxed (unless the total of all our varying output components can't exceed +// 128, which would mean FragPos would sum to 4 * 3 * 32 = 384; this could be +// remedied only by setting MAX_POINT_LIGHTS to ), we might enable it again soon. +// +out vec4 FragPos; // FragPos from GS (output per emitvertex) +flat out int FragLayer; // Current layer + +void main() { + // NOTE: Assuming that light_shadow_count.x < MAX_POINT_LIGHTS. We could min + // it, but that might make this less optimized, and I'd like to keep this loop as + // optimized as is reasonably possible. + int face = gl_InvocationID; + + for (int layer = 0; layer < light_shadow_count.x; ++layer) + { + // We use instancing here in order to increase the number of emitted vertices. + // int face = gl_InvocationID; + // for(int face = 0; face < FACES_PER_POINT_LIGHT; ++face) + // { + int layer_face = layer * FACES_PER_POINT_LIGHT + face; + for(int i = 0; i < VERTICES_PER_FACE; ++i) // for each triangle vertex + { + // NOTE: See above, we don't make FragPos a uniform. + FragPos = gl_in[i].gl_Position; + FragLayer = layer; + // vec4 FragPos = gl_in[i].gl_Position; + gl_Layer = layer_face; // built-in variable that specifies to which face we render. + gl_Position = shadowMats[layer_face].shadowMatrices * FragPos; + EmitVertex(); + } + EndPrimitive(); + // } + } +} diff --git a/assets/voxygen/shaders/light-shadows-vert.glsl b/assets/voxygen/shaders/light-shadows-vert.glsl new file mode 100644 index 0000000000..5dc64d717e --- /dev/null +++ b/assets/voxygen/shaders/light-shadows-vert.glsl @@ -0,0 +1,51 @@ +#version 330 core + +#include + +#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY + +#if (FLUID_MODE == FLUID_MODE_CHEAP) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE +#elif (FLUID_MODE == FLUID_MODE_SHINY) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE +#endif + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + +// Currently, we only need globals for the all_mat matrix. +#include + +/* Accurate packed shadow maps for many lights at once! + * + * Ideally, we would just write to a bitmask... + * + * */ + +in uint v_pos_norm; +in uint v_col_light; + +// Light projection matrices. +layout (std140) +uniform u_locals { + vec3 model_offs; + float load_time; +}; + +// out vec4 shadowMapCoord; + +const int EXTRA_NEG_Z = 32768; + +void main() { + vec3 f_chunk_pos = vec3(ivec3((uvec3(v_pos_norm) >> uvec3(0, 6, 12)) & uvec3(0x3Fu, 0x3Fu, 0xFFFFu)) - ivec3(0, 0, EXTRA_NEG_Z)); + // f_pos = f_chunk_pos + model_offs; + // f_pos = v_pos; + vec3 f_pos = f_chunk_pos + model_offs; + + gl_Position = /*all_mat * */vec4(f_pos, 1.0); + // shadowMapCoord = lights[gl_InstanceID].light_pos * gl_Vertex; + // vec4(v_pos, 0.0, 1.0); +} diff --git a/assets/voxygen/shaders/lod-terrain-frag.glsl b/assets/voxygen/shaders/lod-terrain-frag.glsl index 1ed1ddbacd..fee0977e85 100644 --- a/assets/voxygen/shaders/lod-terrain-frag.glsl +++ b/assets/voxygen/shaders/lod-terrain-frag.glsl @@ -1,5 +1,21 @@ #version 330 core +#include + +#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY + +#if (FLUID_MODE == FLUID_MODE_CHEAP) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE +#elif (FLUID_MODE == FLUID_MODE_SHINY) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE +#endif + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_VOXEL + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + #include #include #include @@ -83,10 +99,6 @@ void main() { // vec3 f_up = faceforward(cam_pos.xyz - f_pos, vec3(0.0, 0.0, -1.0), cam_pos.xyz - f_pos); // vec3 f_norm = faceforward(f_norm, /*vec3(cam_pos.xyz - f_pos.xyz)*/vec3(0.0, 0.0, -1.0), f_norm); - vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz); - vec3 view_dir = -cam_to_frag; - // vec3 view_dir = normalize(f_pos - cam_pos.xyz); - // const vec3 normals[3] = 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)); // const mat3 side_norms = vec3(1, 0, 0), vec3(0, 1, 0), vec3(0, 0, 1); // mat3 sides = mat3( @@ -156,11 +168,138 @@ void main() { // } // voxel_norm = normalize(voxel_norm); */ - float dist_lerp = clamp(pow(max(distance(focus_pos.xy, f_pos.xy) - view_distance.x, 0.0) / 1024.0, 2.0), 0, 1); + float dist_lerp = clamp(pow(max(distance(focus_pos.xy, f_pos.xy) - view_distance.x, 0.0) / 4096.0, 2.0), 0, 1); // dist_lerp = 0.0; // voxel_norm = normalize(mix(voxel_norm, f_norm, /*pow(dist_lerp, 1.0)*/dist_lerp)); - vec3 voxel_norm = f_norm; + // IDEA: + // We can represent three faces as sign(voxel_norm). + vec3 sides = sign(f_norm); + // There are three relevant vectors: normal, tangent, and bitangent. + // We say normal is the z component, tangent the x component, bitangent the y. + // A blocking side is in the reverse direction of each. + // So -sides is the *direction* of the next block. + // Now, we want to multiply this by the *distance* to the nearest integer in that direction. + // If sides.x is -1, the direction is 1, so the distance is 1.0 - fract(f_pos.x) and the delta is 1.0 - fract(f_pos.x). + // If sides.x is 1, the direction is -1, so the distance is fract(f_pos.x) and the delta is -fract(f_pos.x) = 1.0 + fract(-f_pos.x). + // If sides.x is 0, the direction is 0, so the distance is 0.0 and the delta is 0.0 = 0.0 + fract(0.0 * f_pos.x). + // (we ignore f_pos < 0 for the time being). + // Then this is 1.0 + sides.x * fract(-sides.x * f_pos.x); + // We repeat this for y. + // + // We treat z as the dependent variable. + // IF voxel_norm.x > 0.0, z should increase by voxel_norm.z / voxel_norm.x * delta_sides.x in the x direction; + // IF voxel_norm.y > 0.0, z should increase by voxel_norm.z / voxel_norm.y * delta_sides.y in the y direction; + // IF voxel_norm.x = 0.0, z should not increase in the x direction; + // IF voxel_norm.y = 0.0, z should not increase in the y direction; + // we assume that ¬(voxel_norm.z = 0). + // + // Now observe that we can rephrase this as saying, given a desired change in z (to get to the next integer), how far must + // we travel along x and y? + // + // TODO: Handle negative numbers. + vec3 delta_sides = mix(-fract(f_pos), 1.0 - fract(f_pos), lessThan(sides, vec3(0.0))); + // vec3 delta_sides = mix(1.0 - fract(f_pos), -fract(f_pos), lessThan(sides, vec3(0.0))); + // vec3 delta_sides = 1.0 + sides * fract(-sides * f_pos); + // Three faces: xy, xz, and yz. + // TODO: Handle zero slopes (for xz and yz). + vec2 corner_xy = min(abs(f_norm.xy / f_norm.z * delta_sides.z), 1.0); + vec2 corner_yz = min(abs(f_norm.yz / f_norm.x * delta_sides.x), 1.0); + vec2 corner_xz = min(abs(f_norm.xz / f_norm.y * delta_sides.y), 1.0); + // vec3 corner_delta = vec3(voxel_norm.xy / voxel_norm.z * delta_sides.z, delta_sides.z); + // Now we just compute an (upper bounded) distance to the corner in each direction. + // vec3 corner_distance = min(abs(corner_delta), 1.0); + // Now, if both sides hit something, lerp to 0.0. If one side hits something, lerp to 0.4. And if no sides hit something, + // lerp to 1.0. + // Bilinear interpolation on each plane: + float ao_xy = dot(vec2(1.0 - corner_xy.x, corner_xy.x), mat2(vec2(corner_xy.x < 1.00 ? corner_xy.y < 1.00 ? 0.0 : 0.25 : corner_xy.y < 1.00 ? 0.25 : 1.0, corner_xy.x < 1.00 ? 0.25 : 1.0), vec2(corner_xy.y < 1.00 ? 0.25 : 1.0, 1.0)) * vec2(1.0 - corner_xy.y, corner_xy.y)); + float ao_yz = dot(vec2(1.0 - corner_yz.x, corner_yz.x), mat2(vec2(corner_yz.x < 1.00 ? corner_yz.y < 1.00 ? 0.0 : 0.25 : corner_yz.y < 1.00 ? 0.25 : 1.0, corner_yz.x < 1.00 ? 0.25 : 1.0), vec2(corner_yz.y < 1.00 ? 0.25 : 1.0, 1.0)) * vec2(1.0 - corner_yz.y, corner_yz.y)); + float ao_xz = dot(vec2(1.0 - corner_xz.x, corner_xz.x), mat2(vec2(corner_xz.x < 1.00 ? corner_xz.y < 1.00 ? 0.0 : 0.25 : corner_xz.y < 1.00 ? 0.25 : 1.0, corner_xz.x < 1.00 ? 0.25 : 1.0), vec2(corner_xz.y < 1.00 ? 0.25 : 1.0, 1.0)) * vec2(1.0 - corner_xz.y, corner_xz.y)); + // Now, multiply each component by the face "share" which is just the absolute value of its normal for that plane... + // vec3 f_ao_vec = mix(abs(vec3(ao_yz, ao_xz, ao_xy)), vec3(1.0), bvec3(f_norm.yz == vec2(0.0), f_norm.xz == vec2(0.0), f_norm.xy == vec2(0.0))); + // vec3 f_ao_vec = mix(abs(vec3(ao_yz, ao_xz, ao_xy)), vec3(1.0), bvec3(length(f_norm.yz) <= 0.0, length(f_norm.xz) <= 0.0, length(f_norm.xy) <= 0.0)); + // vec3 f_ao_vec = mix(abs(vec3(ao_yz, ao_xz, ao_xy)), vec3(1.0), bvec3(abs(f_norm.x) <= 0.0, abs(f_norm.y) <= 0.0, abs(f_norm.z) <= 0.0)); + vec3 f_ao_vec = mix(/*abs(voxel_norm)*/vec3(1.0, 1.0, 1.0), /*abs(voxel_norm) * */vec3(ao_yz, ao_xz, ao_xy), /*abs(voxel_norm)*/vec3(length(f_norm.yz), length(f_norm.xz), length(f_norm.xy))/*vec3(1.0)*//*sign(max(view_dir * sides, 0.0))*/); + // f_ao_vec *= sign(max(view_dir * sides, 0.0)); + // vec3 f_ao_view = max(vec3(dot(view_dir.yz, sides.yz), dot(view_dir.xz, sides.xz), dot(view_dir.xy, sides.xy)), 0.0); + // delta_sides *= sqrt(1.0 - f_ao_view * f_ao_view); + // delta_sides *= 1.0 - mix(view_dir / f_ao_view, vec3(0.0), equal(f_ao_view, vec3(0.0)));// sqrt(1.0 - f_ao_view * f_ao_view); + // delta_sides *= 1.0 - /*sign*/(max(vec3(dot(view_dir.yz, sides.yz), dot(view_dir.xz, sides.xz), dot(view_dir.xy, sides.xy)), 0.0)); + // f_ao = length(f_ao_vec); + // f_ao = dot(f_ao_vec, vec3(1.0)) / 3.0; + // f_ao = 1.0 / sqrt(3.0) * sqrt(dot(f_ao_vec, vec3(1.0))); + // f_ao = pow(f_ao_vec.x * f_ao_vec.y * f_ao_vec.z * 3.0, 1.0 / 2.0); // 1.0 / sqrt(3.0) * sqrt(dot(f_ao_vec, vec3(1.0))); + // f_ao = pow(f_ao_vec.x * f_ao_vec.y * f_ao_vec.z, 1.0 / 3.0); // 1.0 / sqrt(3.0) * sqrt(dot(f_ao_vec, vec3(1.0))); + // f_ao = f_ao_vec.x * f_ao_vec.y * f_ao_vec.z + (1.0 - f_ao_vec.x) * (1.0 - f_ao_vec.y) * (1.0 - f_ao_vec.z); + // f_ao = sqrt((f_ao_vec.x + f_ao_vec.y + f_ao_vec.z) / 3.0); // 1.0 / sqrt(3.0) * sqrt(dot(f_ao_vec, vec3(1.0))); + // f_ao = sqrt(dot(f_ao_vec, abs(voxel_norm))); + // f_ao = 3.0 / (1.0 / f_ao_vec.x + 1.0 / f_ao_vec.y + 1.0 / f_ao_vec.z); + // f_ao = min(ao_yz, min(ao_xz, ao_xy)); + // f_ao = max(f_ao_vec.x, max(f_ao_vec.y, f_ao_vec.z)); + // f_ao = min(f_ao_vec.x, min(f_ao_vec.y, f_ao_vec.z)); + // f_ao = sqrt(dot(f_ao_vec * abs(voxel_norm), sqrt(1.0 - delta_sides * delta_sides)) / 3.0); + // f_ao = dot(f_ao_vec, sqrt(1.0 - delta_sides * delta_sides)); + // f_ao = dot(f_ao_vec, 1.0 - abs(delta_sides)); + // f_ao = + // f_ao_vec.x < 1.0 ? + // f_ao_vec.y < 1.0 ? + // abs(delta_sides.x) < abs(delta_sides.y) ? + // f_ao_vec.z < 1.0 ? abs(delta_sides.x) < abs(delta_sides.z) ? f_ao_vec.x : f_ao_vec.z : f_ao_vec.x : + // f_ao_vec.z < 1.0 ? abs(delta_sides.y) < abs(delta_sides.z) ? f_ao_vec.y : f_ao_vec.z : f_ao_vec.y : + // f_ao_vec.z < 1.0 ? abs(delta_sides.x) < abs(delta_sides.z) ? f_ao_vec.x : f_ao_vec.z : f_ao_vec.x : + // f_ao_vec.y < 1.0 ? + // f_ao_vec.z < 1.0 ? abs(delta_sides.y) < abs(delta_sides.z) ? f_ao_vec.y : f_ao_vec.z : f_ao_vec.y : + // f_ao_vec.z; + // f_ao = abs(delta_sides.x) < abs(delta_sides.y) ? abs(delta_sides.x) < abs(delta_sides.z) ? f_ao_vec.x : f_ao_vec.z : + // abs(delta_sides.y) < abs(delta_sides.z) ? f_ao_vec.y : f_ao_vec.z; + // f_ao = abs(delta_sides.x) * f_ao_vec.x < abs(delta_sides.y) * f_ao_vec.y ? abs(delta_sides.x) * f_ao_vec.x < abs(delta_sides.z) * f_ao_vec.z ? f_ao_vec.x : f_ao_vec.z : + // abs(delta_sides.y) * f_ao_vec.y < abs(delta_sides.z) * f_ao_vec.z ? f_ao_vec.y : f_ao_vec.z; + // f_ao = dot(abs(voxel_norm), abs(voxel_norm) * f_ao_vec)/* / 3.0*/; + // f_ao = sqrt(dot(abs(voxel_norm), f_ao_vec) / 3.0); + // f_ao = /*abs(sides)*/max(sign(1.0 + view_dir * sides), 0.0) * f_ao); + // f_ao = mix(f_ao, 1.0, dist_lerp); + + // vec3 voxel_norm = f_norm; + // vec3 voxel_norm = + // /*f_ao_vec.x < 1.0*/true ? + // /*f_ao_vec.y < 1.0*/true ? + // abs(delta_sides.x) < abs(delta_sides.y) ? + // /*f_ao_vec.z < 1.0 */true ? abs(delta_sides.x) < abs(delta_sides.z) ? vec3(sides.x, 0.0, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(sides.x, 0.0, 0.0) : + // /*f_ao_vec.z < 1.0*/true ? abs(delta_sides.y) < abs(delta_sides.z) ? vec3(0.0, sides.y, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(0.0, sides.y, 0.0) : + // /*f_ao_vec.z < 1.0*/true ? abs(delta_sides.x) < abs(delta_sides.z) ? vec3(sides.x, 0.0, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(sides.x, 0.0, 0.0) : + // /*f_ao_vec.y < 1.0*/true ? + // /*f_ao_vec.z < 1.0*/true ? abs(delta_sides.y) < abs(delta_sides.z) ? vec3(0.0, sides.y, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(0.0, sides.y, 0.0) : + // vec3(0.0, 0.0, sides.z); + /* vec3 voxel_norm = + f_ao_vec.x < 1.0 ? + f_ao_vec.y < 1.0 ? + abs(delta_sides.x) < abs(delta_sides.y) ? + f_ao_vec.z < 1.0 ? abs(delta_sides.x) < abs(delta_sides.z) ? vec3(sides.x, 0.0, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(sides.x, 0.0, 0.0) : + f_ao_vec.z < 1.0 ? abs(delta_sides.y) < abs(delta_sides.z) ? vec3(0.0, sides.y, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(0.0, sides.y, 0.0) : + f_ao_vec.z < 1.0 ? abs(delta_sides.x) < abs(delta_sides.z) ? vec3(sides.x, 0.0, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(sides.x, 0.0, 0.0) : + f_ao_vec.y < 1.0 ? + f_ao_vec.z < 1.0 ? abs(delta_sides.y) < abs(delta_sides.z) ? vec3(0.0, sides.y, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(0.0, sides.y, 0.0) : + f_ao_vec.z < 1.0 ? vec3(0.0, 0.0, sides.z) : vec3(0.0, 0.0, 0.0); */ + // vec3 voxel_norm = + // f_ao_vec.x < 1.0 ? + // f_ao_vec.y < 1.0 ? + // abs(delta_sides.x) * f_ao_vec.x < abs(delta_sides.y) * f_ao_vec.y ? + // f_ao_vec.z < 1.0 ? abs(delta_sides.x) * f_ao_vec.x < abs(delta_sides.z) * f_ao_vec.z ? vec3(sides.x, 0.0, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(sides.x, 0.0, 0.0) : + // f_ao_vec.z < 1.0 ? abs(delta_sides.y) * f_ao_vec.y < abs(delta_sides.z) * f_ao_vec.z ? vec3(0.0, sides.y, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(0.0, sides.y, 0.0) : + // f_ao_vec.z < 1.0 ? abs(delta_sides.x) * f_ao_vec.x < abs(delta_sides.z) * f_ao_vec.z ? vec3(sides.x, 0.0, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(sides.x, 0.0, 0.0) : + // f_ao_vec.y < 1.0 ? + // f_ao_vec.z < 1.0 ? abs(delta_sides.y) * f_ao_vec.y < abs(delta_sides.z) * f_ao_vec.z ? vec3(0.0, sides.y, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(0.0, sides.y, 0.0) : + // f_ao_vec.z < 1.0 ? vec3(0.0, 0.0, sides.z) : vec3(0.0, 0.0, 0.0); + vec3 voxel_norm = vec3(0.0); + // voxel_norm = mix(voxel_norm, f_norm, dist_lerp); + + f_pos.xyz -= abs(voxel_norm) * delta_sides; + voxel_norm = voxel_norm == vec3(0.0) ? f_norm : voxel_norm; + + // f_ao = 1.0; + // f_ao = dot(f_ao_vec, sqrt(1.0 - delta_sides * delta_sides)); + f_ao = sqrt(dot(f_ao_vec * abs(voxel_norm), sqrt(1.0 - delta_sides * delta_sides)) / 3.0); + // f_ao = dot(abs(voxel_norm), f_ao_vec); // voxel_norm = f_norm; // Note: because voxels, we reduce the normal for reflections to just its z component, dpendng on distance to camera. @@ -188,6 +327,10 @@ void main() { mix(-1.0, 1.0, clamp(pow(f_norm.y * 0.5, 64), 0, 1)), mix(-1.0, 1.0, clamp(pow(f_norm.z * 0.5, 64), 0, 1)) )); */ + vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz); + vec3 view_dir = -cam_to_frag; + // vec3 view_dir = normalize(f_pos - cam_pos.xyz); + vec3 sun_dir = get_sun_dir(time_of_day.x); vec3 moon_dir = get_moon_dir(time_of_day.x); @@ -212,27 +355,70 @@ void main() { // float brightness_denominator = (ambient_sides + vec3(SUN_AMBIANCE * sun_light + moon_light); float alpha = 1.0;//0.1;//0.2;///1.0;//sqrt(2.0); - const float n2 = 1.01; + const float n2 = 1.5; 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); const float R_s1s2 = pow((1.3325 - 1.0) / (1.3325 + 1.0), 2); + float cam_alt = alt_at(cam_pos.xy); + float fluid_alt = medium.x == 1u ? max(cam_alt + 1, floor(shadow_alt)) : view_distance.w; float R_s = (f_pos.z < my_alt) ? mix(R_s2s1 * R_s1s0, R_s1s0, medium.x) : mix(R_s2s0, R_s1s2 * R_s2s0, medium.x); vec3 emitted_light, reflected_light; + + vec3 mu = medium.x == 1u/* && f_pos.z <= fluid_alt*/ ? MU_WATER : vec3(0.0); + // NOTE: Default intersection point is camera position, meaning if we fail to intersect we assume the whole camera is in water. + vec3 cam_attenuation = compute_attenuation_point(cam_pos.xyz, view_dir, mu, fluid_alt, /*cam_pos.z <= fluid_alt ? cam_pos.xyz : f_pos*/f_pos); // Use f_norm here for better shadows. // vec3 light_frac = light_reflection_factor(f_norm/*l_norm*/, view_dir, vec3(0, 0, -1.0), vec3(1.0), vec3(/*1.0*/R_s), alpha); // vec3 light, diffuse_light, ambient_light; // get_sun_diffuse(f_norm, time_of_day.x, cam_to_frag, (0.25 * shade_frac + 0.25 * light_frac) * f_col, 0.5 * shade_frac * f_col, 0.5 * shade_frac * /*vec3(1.0)*/f_col, 2.0, emitted_light, reflected_light); float max_light = 0.0; - max_light += get_sun_diffuse2(/*f_norm*/voxel_norm/*l_norm*/, sun_dir, moon_dir, view_dir, vec3(1.0)/* * (0.5 * light_frac + vec3(0.5 * shade_frac))*/, vec3(1.0), /*0.5 * shade_frac * *//*vec3(1.0)*//*f_col*/vec3(R_s), alpha, dist_lerp/*max(distance(focus_pos.xy, f_pos.xyz) - view_distance.x, 0.0) / 1000 < 1.0*/, emitted_light, reflected_light); + max_light += get_sun_diffuse2(/*f_norm*/voxel_norm/*l_norm*/, sun_dir, moon_dir, view_dir, f_pos, vec3(0.0), cam_attenuation, fluid_alt, vec3(1.0)/* * (0.5 * light_frac + vec3(0.5 * shade_frac))*/, vec3(1.0), /*0.5 * shade_frac * *//*vec3(1.0)*//*f_col*/vec3(R_s), alpha, dist_lerp/*max(distance(focus_pos.xy, f_pos.xyz) - view_distance.x, 0.0) / 1000 < 1.0*/, emitted_light, reflected_light); // emitted_light = vec3(1.0); emitted_light *= max(shade_frac, MIN_SHADOW); reflected_light *= shade_frac; max_light *= shade_frac; // reflected_light = vec3(0.0); + // dot(diffuse_factor, /*R_r * */vec4(abs(norm) * (1.0 - dist), dist)) + + // corner_xy = mix(all(lessThan(corner_xy, 1.0)) ? vec2(0.0) : 0.4 * (), 1.0 + // + // TODO: Handle similar logic for z. + + // So we repeat this for all three sides to find the "next" position on each side. + // vec3 delta_sides = 1.0 + sides * fract(-sides * f_pos); + // Now, we + // Now, all we have to do is find out whether (again, assuming f_pos is positive) next_sides represents a new integer. + // We currently just treat this as "new floor != old floor". + + // So to find the position at the nearest voxel, we just subtract voxel_norm * fract(sides * ) from f_pos.z. + // Then to find out whether we meet a new "block" in 1 voxel, we just + // on the "other" side can be found (according to my temporary theory) as the cross product + // vec3 norm = normalize(cross( + // vec3(/*2.0 * SAMPLE_W*/square.z - square.x, 0.0, altx1 - altx0), + // vec3(0.0, /*2.0 * SAMPLE_W*/square.w - square.y, alty1 - alty0) + // )); + // vec3 norm = normalize(vec3( + // (altx0 - altx1) / (square.z - square.x), + // (alty0 - alty1) / (square.w - square.y), + // 1.0 + // //(abs(square.w - square.y) + abs(square.z - square.x)) / (slope + 0.00001) // Avoid NaN + // )); + // + // If a side coordinate is 0, then it counts as no AO; + // otherwise, it counts as fractional AO. So what we need is to know whether the fractional AO to the next block in that direction pushes us to a new integer. + // + // vec3 ao_pos_z = floor(f_pos + f_norm); + // vec3 ao_pos_z = corner_distance; + // vec3 ao_pos = 0.5 - clamp(min(fract(abs(f_pos)), 1.0 - fract(abs(f_pos))), 0.0, 0.5); + // + // f_ao = /*sqrt*/1.0 - 2.0 * sqrt(dot(ao_pos, ao_pos) / 2.0); + // f_ao = /*sqrt*/1.0 - (dot(ao_pos, ao_pos)/* / 2.0*/); + // f_ao = /*sqrt*/1.0 - 2.0 * (dot(ao_pos, ao_pos)/* / 2.0*/); + // f_ao = /*sqrt*/1.0 - 2.0 * sqrt(dot(ao_pos, ao_pos) / 2.0); float ao = /*pow(f_ao, 0.5)*/f_ao * 0.9 + 0.1; emitted_light *= ao; reflected_light *= ao; @@ -246,7 +432,7 @@ void main() { // get_sun_diffuse(f_norm, time_of_day.x, light, diffuse_light, ambient_light, 1.0); // vec3 surf_color = illuminate(f_col, light, diffuse_light, ambient_light); // f_col = f_col + (hash(vec4(floor(vec3(focus_pos.xy + splay(v_pos_orig), f_pos.z)) * 3.0 - round(f_norm) * 0.5, 0)) - 0.5) * 0.05; // Small-scale noise - vec3 surf_color = /*illuminate(emitted_light, reflected_light)*/illuminate(max_light, f_col * emitted_light, f_col * reflected_light); + vec3 surf_color = /*illuminate(emitted_light, reflected_light)*/illuminate(max_light, view_dir, f_col * emitted_light, f_col * reflected_light); float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x); diff --git a/assets/voxygen/shaders/lod-terrain-vert.glsl b/assets/voxygen/shaders/lod-terrain-vert.glsl index f83cf491d2..9b62d6e490 100644 --- a/assets/voxygen/shaders/lod-terrain-vert.glsl +++ b/assets/voxygen/shaders/lod-terrain-vert.glsl @@ -1,5 +1,21 @@ #version 330 core +#include + +#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY + +#if (FLUID_MODE == FLUID_MODE_CHEAP) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE +#elif (FLUID_MODE == FLUID_MODE_SHINY) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE +#endif + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_VOXEL + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + #include #include #include diff --git a/assets/voxygen/shaders/player-shadow-frag.glsl b/assets/voxygen/shaders/player-shadow-frag.glsl index 4427e22f5f..5a0f5f82f4 100644 --- a/assets/voxygen/shaders/player-shadow-frag.glsl +++ b/assets/voxygen/shaders/player-shadow-frag.glsl @@ -1,5 +1,17 @@ #version 330 core +#include + +#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY + +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + #include in vec3 f_pos; diff --git a/assets/voxygen/shaders/postprocess-frag.glsl b/assets/voxygen/shaders/postprocess-frag.glsl index fd8e65c68a..2dc7e44d45 100644 --- a/assets/voxygen/shaders/postprocess-frag.glsl +++ b/assets/voxygen/shaders/postprocess-frag.glsl @@ -1,8 +1,25 @@ #version 330 core +#include + +#define LIGHTING_TYPE (LIGHTING_TYPE_TRANSMISSION | LIGHTING_TYPE_REFLECTION) + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_SPECULAR + +#if (FLUID_MODE == FLUID_MODE_CHEAP) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE +#elif (FLUID_MODE == FLUID_MODE_SHINY) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE +#endif + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + #include // Note: The sampler uniform is declared here because it differs for MSAA #include +#include in vec2 f_pos; @@ -29,6 +46,101 @@ vec3 hsv2rgb(vec3 c) { return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); } +vec3 illuminate(float max_light, vec3 view_dir, /*vec3 max_light, */vec3 emitted, vec3 reflected) { + const float NIGHT_EXPOSURE = 10.0; + const float DUSK_EXPOSURE = 2.0;//0.8; + const float DAY_EXPOSURE = 1.0;//0.7; + + const float DAY_SATURATION = 1.0; + const float DUSK_SATURATION = 0.6; + const float NIGHT_SATURATION = 0.1; + + const float gamma = /*0.5*//*1.*0*/1.0;//1.0; + /* float light = length(emitted + reflected); + float color = srgb_to_linear(emitted + reflected); + float avg_col = (color.r + color.g + color.b) / 3.0; + return ((color - avg_col) * light + reflected * avg_col) * (emitted + reflected); */ + // float max_intensity = vec3(1.0); + vec3 color = emitted + reflected; + float lum = rel_luminance(color); + // float lum_sky = lum - max_light; + + // vec3 sun_dir = get_sun_dir(time_of_day.x); + // vec3 moon_dir = get_moon_dir(time_of_day.x); + // float sky_light = rel_luminance( + // get_sun_color(sun_dir) * get_sun_brightness(sun_dir) * SUN_COLOR_FACTOR + + // get_moon_color(moon_dir) * get_moon_brightness(moon_dir)); + float sky_light = lum; + + // Tone mapped value. + // vec3 T = /*color*//*lum*/color;//normalize(color) * lum / (1.0 + lum); + // float alpha = 0.5;//2.0; + // float alpha = mix( + // mix( + // DUSK_EXPOSURE, + // NIGHT_EXPOSURE, + // max(sun_dir.z, 0) + // ), + // DAY_EXPOSURE, + // max(-sun_dir.z, 0) + // ); + float alpha = 1.0;//log(1.0 - lum) / lum; + // vec3 now_light = moon_dir.z < 0 ? moon_dir : sun_dir; + // float cos_view_light = dot(-now_light, view_dir); + // alpha *= exp(1.0 - cos_view_light); + // sky_light *= 1.0 - log(1.0 + view_dir.z); + float alph = sky_light > 0.0 && max_light > 0.0 ? mix(1.0 / log(/*1.0*//*1.0 + *//*lum_sky + */1.0 + max_light / (0.0 + sky_light)), 1.0, clamp(max_light - sky_light, 0.0, 1.0)) : 1.0; + alpha = alpha * alph;// min(alph, 1.0);//((max_light > 0.0 && max_light > sky_light /* && sky_light > 0.0*/) ? /*1.0*/1.0 / log(/*1.0*//*1.0 + *//*lum_sky + */1.0 + max_light - (0.0 + sky_light)) : 1.0); + // alpha = alpha * min(1.0, (max_light == 0.0 ? 1.0 : (1.0 + abs(lum_sky)) / /*(1.0 + max_light)*/max_light)); + + vec3 col_adjusted = lum == 0.0 ? vec3(0.0) : color / lum; + + // float L = lum == 0.0 ? 0.0 : log(lum); + + + // // float B = T; + // // float B = L + log(alpha); + // float B = lum; + + // float D = L - B; + + // float o = 0.0;//log(PERSISTENT_AMBIANCE); + // float scale = /*-alpha*/-alpha;//1.0; + + // float B_ = (B - o) * scale; + + // // float T = lum; + // float O = exp(B_ + D); + + float T = 1.0 - exp(-alpha * lum);//lum / (1.0 + lum); + // float T = lum; + + // Heuristic desaturation + // const float s = 0.8; + float s = 1.0; + // float s = mix( + // mix( + // DUSK_SATURATION, + // NIGHT_SATURATION, + // max(sun_dir.z, 0) + // ), + // DAY_SATURATION, + // max(-sun_dir.z, 0) + // ); + // s = max(s, (max_light) / (1.0 + s)); + // s = max(s, max_light / (1.0 + max_light)); + // s = max_light / (1.0 + max_light); + + vec3 c = pow(col_adjusted, vec3(s)) * T; + // vec3 c = col_adjusted * T; + // vec3 c = sqrt(col_adjusted) * T; + // vec3 c = /*col_adjusted * */col_adjusted * T; + + return c; + // float sum_col = color.r + color.g + color.b; + // return /*srgb_to_linear*/(/*0.5*//*0.125 * */vec3(pow(color.x, gamma), pow(color.y, gamma), pow(color.z, gamma))); +} + void main() { vec2 uv = (f_pos + 1.0) * 0.5; @@ -36,8 +148,36 @@ void main() { uv = clamp(uv + vec2(sin(uv.y * 16.0 + tick.x), sin(uv.x * 24.0 + tick.x)) * 0.005, 0, 1); } + vec2 c_uv = vec2(0.5);//uv;//vec2(0.5);//uv; + vec2 delta = /*sqrt*//*sqrt(2.0) / 2.0*//*sqrt(2.0) / 2.0*//*0.5 - */min(uv, 1.0 - uv);//min(uv * (1.0 - uv), 0.25) * 2.0; + // delta = /*sqrt(2.0) / 2.0 - */sqrt(vec2(dot(delta, delta))); + // delta = 0.5 - vec2(min(delta.x, delta.y)); + delta = vec2(0.25);//vec2(dot(/*0.5 - */delta, /*0.5 - */delta));//vec2(min(delta.x, delta.y));//sqrt(2.0) * (0.5 - vec2(min(delta.x, delta.y))); + // delta = vec2(sqrt(dot(delta, delta))); + // vec2 delta = /*sqrt*//*sqrt(2.0) / 2.0*//*sqrt(2.0) / 2.0*/1.0 - vec2(sqrt(dot(uv, 1.0 - uv)));//min(uv * (1.0 - uv), 0.25) * 2.0; + // float delta = /*sqrt*//*sqrt(2.0) / 2.0*//*sqrt(2.0) / 2.0*/1.0 - (dot(uv - 0.5, uv - 0.5));//0.01;//25; + // vec2 delta = /*sqrt*//*sqrt(2.0) / 2.0*//*sqrt(2.0) / 2.0*/sqrt(uv * (1.0 - uv));//min(uv * (1.0 - uv), 0.25) * 2.0; + + // float bright_color0 = rel_luminance(texelFetch/*texture*/(src_color, ivec2(clamp(c_uv + vec2(0.0, 0.0), 0.0, 1.0) * screen_res.xy/* / 50*/)/* * 50*/, 0).rgb); + // float bright_color1 = rel_luminance(texelFetch/*texture*/(src_color, ivec2(clamp(c_uv + vec2(delta.x, delta.y), 0.0, 1.0) * screen_res.xy/* / 50*/)/* * 50*/, 0).rgb); + // float bright_color2 = rel_luminance(texelFetch/*texture*/(src_color, ivec2(clamp(c_uv + vec2(delta.x, -delta.y), 0.0, 1.0) * screen_res.xy/* / 50*/)/* * 50*/, 0).rgb); + // float bright_color3 = rel_luminance(texelFetch/*texture*/(src_color, ivec2(clamp(c_uv + vec2(-delta.x, delta.y), 0.0, 1.0) * screen_res.xy/* / 50*/)/* * 50*/, 0).rgb); + // float bright_color4 = rel_luminance(texelFetch/*texture*/(src_color, ivec2(clamp(c_uv + vec2(-delta.x, -delta.y), 0.0, 1.0) * screen_res.xy/* / 50*/)/* * 50*/, 0).rgb); + + // float bright_color0 = rel_luminance(texture(src_color, /*ivec2*/(clamp(c_uv + vec2(0.0, 0.0), 0.0, 1.0)/* * screen_res.xy*//* / 50*/)/* * 50*/, 0).rgb); + // float bright_color1 = rel_luminance(texture(src_color, /*ivec2*/(clamp(c_uv + vec2(delta, delta), 0.0, 1.0)/* * screen_res.xy*//* / 50*/)/* * 50*/, 0).rgb); + // float bright_color2 = rel_luminance(texture(src_color, /*ivec2*/(clamp(c_uv + vec2(delta, -delta), 0.0, 1.0)/* * screen_res.xy*//* / 50*/)/* * 50*/, 0).rgb); + // float bright_color3 = rel_luminance(texture(src_color, /*ivec2*/(clamp(c_uv + vec2(-delta, delta), 0.0, 1.0)/* * screen_res.xy*//* / 50*/)/* * 50*/, 0).rgb); + // float bright_color4 = rel_luminance(texture(src_color, /*ivec2*/(clamp(c_uv + vec2(-delta, -delta), 0.0, 1.0)/* * screen_res.xy*//* / 50*/)/* * 50*/, 0).rgb); + + // float bright_color = max(bright_color0, max(bright_color1, max(bright_color2, max(bright_color3, bright_color4))));// / 2.0;// / 5.0; + + // float bright_color = (bright_color0 + bright_color1 + bright_color2 + bright_color3 + bright_color4) / 5.0; + vec4 aa_color = aa_apply(src_color, uv * screen_res.xy, screen_res.xy); + // aa_color.rgb = illuminate(1.0 - 1.0 / (1.0 + bright_color), normalize(cam_pos.xyz - focus_pos.xyz), /*vec3 max_light, */vec3(0.0), aa_color.rgb); + //vec4 hsva_color = vec4(rgb2hsv(fxaa_color.rgb), fxaa_color.a); //hsva_color.y *= 1.45; //hsva_color.z *= 0.85; diff --git a/assets/voxygen/shaders/postprocess-vert.glsl b/assets/voxygen/shaders/postprocess-vert.glsl index eef08e40d4..8002bc6df0 100644 --- a/assets/voxygen/shaders/postprocess-vert.glsl +++ b/assets/voxygen/shaders/postprocess-vert.glsl @@ -1,5 +1,21 @@ #version 330 core +#include + +#define LIGHTING_TYPE (LIGHTING_TYPE_TRANSMISSION | LIGHTING_TYPE_REFLECTION) + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_SPECULAR + +#if (FLUID_MODE == FLUID_MODE_CHEAP) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE +#elif (FLUID_MODE == FLUID_MODE_SHINY) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE +#endif + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + #include in vec2 v_pos; diff --git a/assets/voxygen/shaders/skybox-frag.glsl b/assets/voxygen/shaders/skybox-frag.glsl index 6c94e1afe5..068b31572e 100644 --- a/assets/voxygen/shaders/skybox-frag.glsl +++ b/assets/voxygen/shaders/skybox-frag.glsl @@ -1,7 +1,24 @@ #version 330 core +#include + +#define LIGHTING_TYPE LIGHTING_TYPE_TRANSMISSION + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_SPECULAR + +#if (FLUID_MODE == FLUID_MODE_CHEAP) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE +#elif (FLUID_MODE == FLUID_MODE_SHINY) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE +#endif + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + #include #include +#include in vec3 f_pos; @@ -16,6 +33,18 @@ void main() { vec4 _clouds; vec3 cam_dir = normalize(f_pos - cam_pos.xyz); + + float cam_alt = alt_at(cam_pos.xy); + // float f_alt = alt_at(f_pos.xy); + float fluid_alt = medium.x == 1u ? floor(cam_alt + 1) : view_distance.w; + // float fluid_alt = max(f_pos.z + 1, floor(f_alt)); + vec3 mu = medium.x == 1u /* && f_pos.z <= fluid_alt*/ ? MU_WATER : vec3(0.0); + // vec3 sun_attenuation = compute_attenuation(wpos, -sun_dir, mu, surface_alt, wpos); + vec3 cam_attenuation = compute_attenuation(cam_pos.xyz, -cam_dir, mu, fluid_alt, /*cam_pos.z <= fluid_alt ? cam_pos.xyz : f_pos*//*f_pos*//*vec3(f_pos.xy, fluid_alt)*/cam_pos.xyz); + // vec3 cam_attenuation = compute_attenuation_point(f_pos, -view_dir, mu, fluid_alt, cam_pos.xyz); + // vec3 cam_attenuation = vec3(1.0); + + /* vec3 world_pos = cam_pos.xyz + cam_dir * 500000.0; tgt_color = vec4(get_sky_color(normalize(f_pos), time_of_day.x, cam_pos.xyz, world_pos, 1.0, true, _clouds), 1.0); */ float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x); @@ -28,5 +57,5 @@ void main() { } */ vec3 wpos = cam_pos.xyz + /*normalize(f_pos)*/cam_dir * dist; - tgt_color = vec4(get_sky_color(normalize(f_pos), time_of_day.x, cam_pos.xyz, wpos, 1.0, true, refractionIndex, _clouds), 1.0); + tgt_color = vec4(cam_attenuation * get_sky_color(normalize(f_pos), time_of_day.x, cam_pos.xyz, wpos, 1.0, true, refractionIndex, _clouds), 1.0); } diff --git a/assets/voxygen/shaders/skybox-vert.glsl b/assets/voxygen/shaders/skybox-vert.glsl index 8cfe045eda..7947ca4ec3 100644 --- a/assets/voxygen/shaders/skybox-vert.glsl +++ b/assets/voxygen/shaders/skybox-vert.glsl @@ -1,5 +1,21 @@ #version 330 core +#include + +#define LIGHTING_TYPE LIGHTING_TYPE_TRANSMISSION + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_SPECULAR + +#if (FLUID_MODE == FLUID_MODE_CHEAP) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE +#elif (FLUID_MODE == FLUID_MODE_SHINY) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE +#endif + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + #include in vec3 v_pos; diff --git a/assets/voxygen/shaders/sprite-frag.glsl b/assets/voxygen/shaders/sprite-frag.glsl index 49006a15b3..1eec83683e 100644 --- a/assets/voxygen/shaders/sprite-frag.glsl +++ b/assets/voxygen/shaders/sprite-frag.glsl @@ -1,4 +1,18 @@ -#version 330 core +#version 400 core + +#include + +#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY + +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + +// #define HAS_SHADOW_MAPS #include @@ -42,7 +56,7 @@ void main() { vec3 surf_color = /*srgb_to_linear*//*linear_to_srgb*/(f_col); float alpha = 1.0; - const float n2 = 1.01; + const float n2 = 1.5; 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); @@ -92,7 +106,7 @@ void main() { emitted_light *= ao; reflected_light *= ao; - surf_color = illuminate(max_light, surf_color * emitted_light, surf_color * reflected_light); + surf_color = illuminate(max_light, view_dir, surf_color * emitted_light, surf_color * reflected_light); // vec3 surf_color = illuminate(f_col, light, diffuse_light, ambient_light); float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x); diff --git a/assets/voxygen/shaders/sprite-vert.glsl b/assets/voxygen/shaders/sprite-vert.glsl index c99a58e6fd..6581fe4811 100644 --- a/assets/voxygen/shaders/sprite-vert.glsl +++ b/assets/voxygen/shaders/sprite-vert.glsl @@ -1,5 +1,17 @@ #version 330 core +#include + +#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY + +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + #include #include diff --git a/assets/voxygen/shaders/terrain-frag.glsl b/assets/voxygen/shaders/terrain-frag.glsl index 914213af47..d8513874e2 100644 --- a/assets/voxygen/shaders/terrain-frag.glsl +++ b/assets/voxygen/shaders/terrain-frag.glsl @@ -1,4 +1,22 @@ -#version 330 core +#version 400 core + +#include + +#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY + +#if (FLUID_MODE == FLUID_MODE_CHEAP) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE +#elif (FLUID_MODE == FLUID_MODE_SHINY) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE +#endif + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + +#define HAS_SHADOW_MAPS #include #include @@ -19,13 +37,45 @@ out vec4 tgt_color; #include void main() { + // tgt_color = vec4(0.0, 0.0, 0.0, 1.0); + // for (uint i = 0u; i < light_shadow_count.x; i ++) { + // // uint i = 1u; + // Light L = lights[i]; + + // vec4 light_col = vec4( + // hash(vec4(1.0, 0.0, 0.0, i)), + // hash(vec4(1.0, 1.0, 0.0, i)), + // hash(vec4(1.0, 0.0, 1.0, i)), + // 1.0 + // ); + + // vec3 light_pos = L.light_pos.xyz; + + // // Pre-calculate difference between light and fragment + // vec3 fragToLight = f_pos - light_pos; + + // // use the light to fragment vector to sample from the depth map + // float bias = 0.05;//0.05; + // // float closestDepth = texture(t_shadow_maps, vec4(fragToLight, i)/*, 0.0*//*, bias*/).r; + // // float closestDepth = texture(t_shadow_maps, vec4(fragToLight, lightIndex), bias); + // float visibility = texture(t_shadow_maps, vec4(fragToLight, i), (length(fragToLight) - bias)/* / screen_res.w*/); + // // it is currently in linear range between [0,1]. Re-transform back to original value + // // closestDepth *= screen_res.w; // far plane + // // now test for shadows + // // float shadow = /*currentDepth*/(screen_res.w - bias) > closestDepth ? 1.0 : 0.0; + // // float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; + + // tgt_color += light_col * vec4(vec3(/*closestDepth*/visibility/* + bias*//* / screen_res.w */) * 1.0 / light_shadow_count.x, 0.0); + // } + // return; + // First 3 normals are negative, next 3 are positive vec3 normals[6] = vec3[](vec3(-1,0,0), vec3(1,0,0), vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), 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; - // Increase array access by 3 to access positive values - uint norm_dir = ((f_pos_norm >> 29) & 0x1u) * 3u; + // uint norm_axis = (f_pos_norm >> 30) & 0x3u; + // // Increase array access by 3 to access positive values + // uint norm_dir = ((f_pos_norm >> 29) & 0x1u) * 3u; // Use an array to avoid conditional branching vec3 f_norm = normals[(f_pos_norm >> 29) & 0x7u]; // Whether this face is facing fluid or not. @@ -43,9 +93,9 @@ void main() { float f_alt = alt_at(f_pos.xy); vec4 f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy)); - float alpha = 1.0; + float alpha = 1.0;//0.0001;//1.0; // TODO: Possibly angle with water surface into account? Since we can basically assume it's horizontal. - const float n2 = 1.01; + const float n2 = 1.5;//1.01; 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); @@ -84,7 +134,9 @@ void main() { // Compute attenuation due to water from the camera. vec3 mu = faces_fluid/* && f_pos.z <= fluid_alt*/ ? MU_WATER : vec3(0.0); // NOTE: Default intersection point is camera position, meaning if we fail to intersect we assume the whole camera is in water. - vec3 cam_attenuation = compute_attenuation_point(f_pos, -view_dir, mu, fluid_alt, /*cam_pos.z <= fluid_alt ? cam_pos.xyz : f_pos*/cam_pos.xyz); + vec3 cam_attenuation = + medium.x == 1u ? compute_attenuation_point(cam_pos.xyz, view_dir, MU_WATER, fluid_alt, /*cam_pos.z <= fluid_alt ? cam_pos.xyz : f_pos*/f_pos) + : compute_attenuation_point(f_pos, -view_dir, mu, fluid_alt, /*cam_pos.z <= fluid_alt ? cam_pos.xyz : f_pos*/cam_pos.xyz); // Computing light attenuation from water. vec3 emitted_light, reflected_light; @@ -97,7 +149,7 @@ void main() { reflected_light *= f_light * point_shadow * shade_frac; max_light *= f_light * point_shadow * shade_frac; - max_light += lights_at(f_pos, f_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, emitted_light, reflected_light); + max_light += lights_at(f_pos, f_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, 1.0, emitted_light, reflected_light); // float f_ao = 1.0; @@ -127,7 +179,7 @@ void main() { // vec3 surf_color = illuminate(srgb_to_linear(f_col), light, diffuse_light, ambient_light); vec3 col = srgb_to_linear(f_col + hash(vec4(floor(f_chunk_pos * 3.0 - f_norm * 0.5), 0)) * 0.02); // Small-scale noise - vec3 surf_color = illuminate(max_light, col * emitted_light, col * reflected_light); + vec3 surf_color = illuminate(max_light, view_dir, col * emitted_light, col * reflected_light); float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x); vec4 clouds; diff --git a/assets/voxygen/shaders/terrain-vert.glsl b/assets/voxygen/shaders/terrain-vert.glsl index e3fd157767..8f44fa7492 100644 --- a/assets/voxygen/shaders/terrain-vert.glsl +++ b/assets/voxygen/shaders/terrain-vert.glsl @@ -1,5 +1,21 @@ #version 330 core +#include + +#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY + +#if (FLUID_MODE == FLUID_MODE_CHEAP) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE +#elif (FLUID_MODE == FLUID_MODE_SHINY) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE +#endif + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + #include #include #include diff --git a/voxygen/examples/character_renderer.rs b/voxygen/examples/character_renderer.rs index 72e26def69..c6b6849404 100644 --- a/voxygen/examples/character_renderer.rs +++ b/voxygen/examples/character_renderer.rs @@ -22,6 +22,7 @@ fn main() { render::AaMode::SsaaX4, render::CloudMode::Regular, render::FluidMode::Shiny, + render::LightingMode::Ashikmin, ) .unwrap(); diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 7ef6bd13eb..0814530fd4 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -35,7 +35,7 @@ use spell::Spell; use crate::{ ecs::comp as vcomp, i18n::{i18n_asset_key, LanguageMetadata, VoxygenLocalization}, - render::{AaMode, CloudMode, Consts, FluidMode, Globals, Renderer}, + render::{AaMode, CloudMode, Consts, FluidMode, Globals, LightingMode, Renderer}, scene::camera::{self, Camera}, ui::{fonts::ConrodVoxygenFonts, slot, Graphic, Ingameable, ScaleMode, Ui}, window::{Event as WinEvent, GameInput}, @@ -246,6 +246,7 @@ pub enum Event { ChangeLanguage(LanguageMetadata), ChangeBinding(GameInput), ChangeFreeLookBehavior(PressBehavior), + ChangeLightingMode(LightingMode), } // TODO: Are these the possible layouts we want? @@ -1858,6 +1859,9 @@ impl Hud { settings_window::Event::ChangeLanguage(language) => { events.push(Event::ChangeLanguage(language)); }, + settings_window::Event::ChangeLightingMode(new_lighting_mode) => { + events.push(Event::ChangeLightingMode(new_lighting_mode)); + }, settings_window::Event::ToggleFullscreen => { events.push(Event::ToggleFullscreen); }, diff --git a/voxygen/src/hud/settings_window.rs b/voxygen/src/hud/settings_window.rs index a8cb33cf06..8b7e6e1a91 100644 --- a/voxygen/src/hud/settings_window.rs +++ b/voxygen/src/hud/settings_window.rs @@ -4,7 +4,7 @@ use super::{ }; use crate::{ i18n::{list_localizations, LanguageMetadata, VoxygenLocalization}, - render::{AaMode, CloudMode, FluidMode}, + render::{AaMode, CloudMode, FluidMode, LightingMode}, ui::{fonts::ConrodVoxygenFonts, ImageSlider, ScaleMode, ToggleButton}, window::GameInput, GlobalState, @@ -115,6 +115,8 @@ widget_ids! { fluid_mode_list, fullscreen_button, fullscreen_label, + lighting_mode_text, + lighting_mode_list, save_window_size_button, audio_volume_slider, audio_volume_text, @@ -228,6 +230,7 @@ pub enum Event { ChangeAaMode(AaMode), ChangeCloudMode(CloudMode), ChangeFluidMode(FluidMode), + ChangeLightingMode(LightingMode), AdjustMusicVolume(f32), AdjustSfxVolume(f32), ChangeAudioDevice(String), @@ -1858,11 +1861,56 @@ impl<'a> Widget for SettingsWindow<'a> { events.push(Event::ChangeFluidMode(mode_list[clicked])); } + // LightingMode + Text::new( + &self + .localized_strings + .get("hud.settings.lighting_rendering_mode"), + ) + .down_from(state.ids.fluid_mode_list, 8.0) + .font_size(self.fonts.cyri.scale(14)) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .set(state.ids.lighting_mode_text, ui); + + let mode_list = [ + LightingMode::Ashikmin, + LightingMode::BlinnPhong, + LightingMode::Lambertian, + ]; + let mode_label_list = [ + &self + .localized_strings + .get("hud.settings.lighting_rendering_mode.ashikmin"), + &self + .localized_strings + .get("hud.settings.lighting_rendering_mode.blinnphong"), + &self + .localized_strings + .get("hud.settings.lighting_rendering_mode.lambertian"), + ]; + + // Get which lighting rendering mode is currently active + let selected = mode_list + .iter() + .position(|x| *x == self.global_state.settings.graphics.lighting_mode); + + if let Some(clicked) = DropDownList::new(&mode_label_list, selected) + .w_h(400.0, 22.0) + .color(MENU_BG) + .label_color(TEXT_COLOR) + .label_font_id(self.fonts.cyri.conrod_id) + .down_from(state.ids.lighting_mode_text, 8.0) + .set(state.ids.lighting_mode_list, ui) + { + events.push(Event::ChangeLightingMode(mode_list[clicked])); + } + // Fullscreen Text::new(&self.localized_strings.get("hud.settings.fullscreen")) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) - .down_from(state.ids.fluid_mode_list, 8.0) + .down_from(state.ids.lighting_mode_list, 8.0) .color(TEXT_COLOR) .set(state.ids.fullscreen_label, ui); diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index a7ba620a99..946b780da3 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -22,6 +22,7 @@ pub use self::{ postprocess::{ create_mesh as create_pp_mesh, Locals as PostProcessLocals, PostProcessPipeline, }, + shadow::{Locals as ShadowLocals, ShadowPipeline}, skybox::{create_mesh as create_skybox_mesh, Locals as SkyboxLocals, SkyboxPipeline}, sprite::{Instance as SpriteInstance, SpritePipeline}, terrain::{Locals as TerrainLocals, TerrainPipeline}, @@ -32,8 +33,8 @@ pub use self::{ Globals, Light, Shadow, }, renderer::{ - LodColorFmt, LodTextureFmt, Renderer, TgtColorFmt, TgtDepthStencilFmt, WinColorFmt, - WinDepthFmt, + LodColorFmt, LodTextureFmt, Renderer, ShadowDepthStencilFmt, TgtColorFmt, + TgtDepthStencilFmt, WinColorFmt, WinDepthFmt, }, texture::Texture, }; @@ -84,3 +85,11 @@ pub enum FluidMode { Cheap, Shiny, } + +/// Lighting modes +#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)] +pub enum LightingMode { + Ashikmin, + BlinnPhong, + Lambertian, +} diff --git a/voxygen/src/render/pipelines/figure.rs b/voxygen/src/render/pipelines/figure.rs index adc2597247..e2e22a972d 100644 --- a/voxygen/src/render/pipelines/figure.rs +++ b/voxygen/src/render/pipelines/figure.rs @@ -38,6 +38,8 @@ gfx_defines! { lights: gfx::ConstantBuffer = "u_lights", shadows: gfx::ConstantBuffer = "u_shadows", + shadow_maps: gfx::TextureSampler = "t_shadow_maps", + map: gfx::TextureSampler<[f32; 4]> = "t_map", horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon", diff --git a/voxygen/src/render/pipelines/fluid.rs b/voxygen/src/render/pipelines/fluid.rs index 5edabcc4c0..30057c63ba 100644 --- a/voxygen/src/render/pipelines/fluid.rs +++ b/voxygen/src/render/pipelines/fluid.rs @@ -23,6 +23,9 @@ gfx_defines! { globals: gfx::ConstantBuffer = "u_globals", lights: gfx::ConstantBuffer = "u_lights", shadows: gfx::ConstantBuffer = "u_shadows", + + shadow_maps: gfx::TextureSampler = "t_shadow_maps", + map: gfx::TextureSampler<[f32; 4]> = "t_map", horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon", diff --git a/voxygen/src/render/pipelines/mod.rs b/voxygen/src/render/pipelines/mod.rs index ad20262c52..214800f2db 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 lod_terrain; pub mod postprocess; +pub mod shadow; pub mod skybox; pub mod sprite; pub mod terrain; @@ -32,6 +33,8 @@ gfx_defines! { view_distance: [f32; 4] = "view_distance", time_of_day: [f32; 4] = "time_of_day", // TODO: Make this f64. tick: [f32; 4] = "tick", + /// x, y represent the resolution of the screen; + /// w, z represent the near and far planes of the shadow map. screen_res: [f32; 4] = "screen_res", light_shadow_count: [u32; 4] = "light_shadow_count", medium: [u32; 4] = "medium", @@ -64,6 +67,7 @@ impl Globals { time_of_day: f64, tick: f64, screen_res: Vec2, + shadow_planes: Vec2, light_count: usize, shadow_count: usize, medium: BlockKind, @@ -81,7 +85,13 @@ impl Globals { view_distance: [view_distance, tgt_detail, map_bounds.x, map_bounds.y], time_of_day: [time_of_day as f32; 4], tick: [tick as f32; 4], - screen_res: Vec4::from(screen_res.map(|e| e as f32)).into_array(), + // Provide the shadow map far plane as well. + screen_res: [ + screen_res.x as f32, + screen_res.y as f32, + shadow_planes.x, + shadow_planes.y, + ], light_shadow_count: [light_count as u32, shadow_count as u32, 0, 0], medium: [if medium.is_fluid() { 1 } else { 0 }; 4], select_pos: select_pos @@ -108,6 +118,7 @@ impl Default for Globals { 0.0, 0.0, Vec2::new(800, 500), + Vec2::new(1.0, 25.0), 0, 0, BlockKind::Air, diff --git a/voxygen/src/render/pipelines/shadow.rs b/voxygen/src/render/pipelines/shadow.rs new file mode 100644 index 0000000000..8274b215e8 --- /dev/null +++ b/voxygen/src/render/pipelines/shadow.rs @@ -0,0 +1,52 @@ +use super::{ + super::{util::arr_to_mat, Pipeline, ShadowDepthStencilFmt, TerrainLocals}, + terrain::Vertex, + Globals, Light, Shadow, +}; +use gfx::{ + self, gfx_constant_struct_meta, gfx_defines, gfx_impl_struct_meta, gfx_pipeline, + gfx_pipeline_inner, +}; +use vek::*; + +gfx_defines! { + constant Locals { + shadow_matrices: [[f32; 4]; 4] = "shadowMatrices", + } + + pipeline pipe { + // Terrain vertex stuff + vbuf: gfx::VertexBuffer = (), + + locals: gfx::ConstantBuffer = "u_locals", + globals: gfx::ConstantBuffer = "u_globals", + lights: gfx::ConstantBuffer = "u_lights", + shadows: gfx::ConstantBuffer = "u_shadows", + + map: gfx::TextureSampler<[f32; 4]> = "t_map", + horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon", + + noise: gfx::TextureSampler = "t_noise", + + // Shadow stuff + light_shadows: gfx::ConstantBuffer = "u_light_shadows", + + tgt_depth_stencil: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_TEST,//,Stencil::new(Comparison::Always,0xff,(StencilOp::Keep,StencilOp::Keep,StencilOp::Keep))), + } +} + +impl Locals { + pub fn new(shadow_mat: Mat4) -> Self { + Self { + shadow_matrices: arr_to_mat(shadow_mat.into_col_array()), + } + } + + pub fn default() -> Self { Self::new(Mat4::identity()) } +} + +pub struct ShadowPipeline; + +impl Pipeline for ShadowPipeline { + type Vertex = Vertex; +} diff --git a/voxygen/src/render/pipelines/skybox.rs b/voxygen/src/render/pipelines/skybox.rs index e6cbd95649..ead0d4b627 100644 --- a/voxygen/src/render/pipelines/skybox.rs +++ b/voxygen/src/render/pipelines/skybox.rs @@ -23,6 +23,9 @@ gfx_defines! { locals: gfx::ConstantBuffer = "u_locals", globals: gfx::ConstantBuffer = "u_globals", + map: gfx::TextureSampler<[f32; 4]> = "t_map", + horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon", + noise: gfx::TextureSampler = "t_noise", tgt_color: gfx::RenderTarget = "tgt_color", diff --git a/voxygen/src/render/pipelines/sprite.rs b/voxygen/src/render/pipelines/sprite.rs index f30304eaf4..6544988ec7 100644 --- a/voxygen/src/render/pipelines/sprite.rs +++ b/voxygen/src/render/pipelines/sprite.rs @@ -37,6 +37,8 @@ gfx_defines! { lights: gfx::ConstantBuffer = "u_lights", shadows: gfx::ConstantBuffer = "u_shadows", + shadow_maps: gfx::TextureSampler = "t_shadow_maps", + map: gfx::TextureSampler<[f32; 4]> = "t_map", horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon", diff --git a/voxygen/src/render/pipelines/terrain.rs b/voxygen/src/render/pipelines/terrain.rs index 396abae531..1da19b8080 100644 --- a/voxygen/src/render/pipelines/terrain.rs +++ b/voxygen/src/render/pipelines/terrain.rs @@ -29,6 +29,8 @@ gfx_defines! { lights: gfx::ConstantBuffer = "u_lights", shadows: gfx::ConstantBuffer = "u_shadows", + shadow_maps: gfx::TextureSampler = "t_shadow_maps", + map: gfx::TextureSampler<[f32; 4]> = "t_map", horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon", diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 9e9cf6614f..70e3b9bc87 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -5,11 +5,11 @@ use super::{ mesh::Mesh, model::{DynamicModel, Model}, pipelines::{ - figure, fluid, lod_terrain, postprocess, skybox, sprite, terrain, ui, Globals, Light, - Shadow, + figure, fluid, lod_terrain, postprocess, shadow, skybox, sprite, terrain, ui, Globals, + Light, Shadow, }, texture::Texture, - AaMode, CloudMode, FilterMethod, FluidMode, Pipeline, RenderError, WrapMode, + AaMode, CloudMode, FilterMethod, FluidMode, LightingMode, Pipeline, RenderError, WrapMode, }; use common::assets::{self, watch::ReloadIndicator}; use gfx::{ @@ -23,7 +23,7 @@ use log::error; use vek::*; /// Represents the format of the pre-processed color target. -pub type TgtColorFmt = gfx::format::Srgba8; +pub type TgtColorFmt = gfx::format::Rgba16F; /// Represents the format of the pre-processed depth and stencil target. pub type TgtDepthStencilFmt = gfx::format::DepthStencil; @@ -32,6 +32,9 @@ pub type WinColorFmt = gfx::format::Srgba8; /// Represents the format of the window's depth target. pub type WinDepthFmt = gfx::format::Depth; +/// Represents the format of the pre-processed shadow depth target. +pub type ShadowDepthStencilFmt = gfx::format::Depth32F; + /// A handle to a pre-processed color target. pub type TgtColorView = gfx::handle::RenderTargetView; /// A handle to a pre-processed depth target. @@ -49,12 +52,33 @@ pub type LodTextureFmt = (gfx::format::R8_G8_B8_A8, gfx::format::Unorm); //[gfx: /// Represents the format of LOD map color targets. pub type LodColorFmt = (gfx::format::R8_G8_B8_A8, gfx::format::Srgb); //[gfx::format::U8Norm; 4]; +/// A handle to a shadow depth target. +pub type ShadowDepthStencilView = + gfx::handle::DepthStencilView; +/// A handle to a shadow depth target as a resource. +pub type ShadowResourceView = gfx::handle::ShaderResourceView< + gfx_backend::Resources, + ::View, +>; + /// A handle to a render color target as a resource. pub type TgtColorRes = gfx::handle::ShaderResourceView< gfx_backend::Resources, ::View, >; +/// A type that holds shadow map data. Since shadow mapping may not be +/// supported on all platforms, we try to keep it separate. +pub struct ShadowMapRenderer { + encoder: gfx::Encoder, + + depth_stencil_view: ShadowDepthStencilView, + res: ShadowResourceView, + sampler: Sampler, + + pipeline: GfxPipeline>, +} + /// A type that encapsulates rendering state. `Renderer` is central to Voxygen's /// rendering subsystem and contains any state necessary to interact with the /// GPU, along with pipeline state objects (PSOs) needed to renderer different @@ -74,6 +98,8 @@ pub struct Renderer { sampler: Sampler, + shadow_map: Option, + skybox_pipeline: GfxPipeline>, figure_pipeline: GfxPipeline>, terrain_pipeline: GfxPipeline>, @@ -91,6 +117,7 @@ pub struct Renderer { aa_mode: AaMode, cloud_mode: CloudMode, fluid_mode: FluidMode, + lighting_mode: LightingMode, } impl Renderer { @@ -104,6 +131,7 @@ impl Renderer { aa_mode: AaMode, cloud_mode: CloudMode, fluid_mode: FluidMode, + lighting_mode: LightingMode, ) -> Result { let mut shader_reload_indicator = ReloadIndicator::new(); @@ -117,11 +145,13 @@ impl Renderer { lod_terrain_pipeline, postprocess_pipeline, player_shadow_pipeline, + shadow_pipeline, ) = create_pipelines( &mut factory, aa_mode, cloud_mode, fluid_mode, + lighting_mode, &mut shader_reload_indicator, )?; @@ -129,6 +159,24 @@ impl Renderer { let (tgt_color_view, tgt_depth_stencil_view, tgt_color_res) = Self::create_rt_views(&mut factory, (dims.0, dims.1), aa_mode)?; + let shadow_map = shadow_pipeline.and_then(|pipeline| { + match Self::create_shadow_views(&mut factory, dims.0.max(dims.1)) { + Ok((depth_stencil_view, res, sampler)) => Some(ShadowMapRenderer { + encoder: factory.create_command_buffer().into(), + + depth_stencil_view, + res, + sampler, + + pipeline, + }), + Err(err) => { + log::warn!("Could not create shadow map views: {:?}", err); + None + }, + } + }); + let sampler = factory.create_sampler_linear(); let noise_tex = Texture::new( @@ -151,8 +199,11 @@ impl Renderer { tgt_depth_stencil_view, tgt_color_res, + sampler, + shadow_map, + skybox_pipeline, figure_pipeline, terrain_pipeline, @@ -170,6 +221,7 @@ impl Renderer { aa_mode, cloud_mode, fluid_mode, + lighting_mode, }) } @@ -240,6 +292,19 @@ impl Renderer { Ok(()) } + /// Change the lighting mode. + pub fn set_lighting_mode(&mut self, lighting_mode: LightingMode) -> Result<(), RenderError> { + self.lighting_mode = lighting_mode; + + // Recreate render target + self.on_resize()?; + + // Recreate pipelines with the new lighting mode + self.recreate_pipelines(); + + Ok(()) + } + /// Resize internal render targets to match window render target dimensions. pub fn on_resize(&mut self) -> Result<(), RenderError> { let dims = self.win_color_view.get_dimensions(); @@ -311,6 +376,87 @@ impl Renderer { Ok((tgt_color_view, tgt_depth_stencil_view, tgt_color_res)) } + /// Create textures and views for shadow maps. + fn create_shadow_views( + factory: &mut gfx_device_gl::Factory, + size: u16, + ) -> Result< + ( + ShadowDepthStencilView, + ShadowResourceView, + Sampler, + ), + RenderError, + > { + let levels = 1; + + /* let color_cty = <::Channel as gfx::format::ChannelTyped + >::get_channel_type(); + let tgt_color_tex = factory.create_texture( + kind, + levels, + gfx::memory::Bind::SHADER_RESOURCE | gfx::memory::Bind::RENDER_TARGET, + gfx::memory::Usage::Data, + Some(color_cty), + )?; + let tgt_color_res = factory.view_texture_as_shader_resource::( + &tgt_color_tex, + (0, levels - 1), + gfx::format::Swizzle::new(), + )?; + let tgt_color_view = factory.view_texture_as_render_target(&tgt_color_tex, 0, None)?; + + let depth_stencil_cty = <::Channel as gfx::format::ChannelTyped>::get_channel_type(); + let tgt_depth_stencil_tex = factory.create_texture( + kind, + levels, + gfx::memory::Bind::DEPTH_STENCIL, + gfx::memory::Usage::Data, + Some(depth_stencil_cty), + )?; + let tgt_depth_stencil_view = + factory.view_texture_as_depth_stencil_trivial(&tgt_depth_stencil_tex)?; */ + let depth_stencil_cty = <::Channel as gfx::format::ChannelTyped>::get_channel_type(); + let shadow_tex = factory + .create_texture( + gfx::texture::Kind::CubeArray(size / 4, 32), + 1 as gfx::texture::Level, + gfx::memory::Bind::SHADER_RESOURCE | gfx::memory::Bind::DEPTH_STENCIL, + gfx::memory::Usage::Data, + Some(depth_stencil_cty), + /* Some(<::Channel as + * gfx::format::ChannelTyped>::get_channel_type()), */ + ) + .map_err(|err| RenderError::CombinedError(gfx::CombinedError::Texture(err)))?; + + let mut sampler_info = gfx::texture::SamplerInfo::new( + gfx::texture::FilterMethod::Bilinear, + gfx::texture::WrapMode::Border, + ); + sampler_info.comparison = Some(Comparison::LessEqual); + sampler_info.border = [1.0; 4].into(); + let shadow_tex_sampler = factory.create_sampler(sampler_info); + + let tgt_shadow_view = factory.view_texture_as_depth_stencil_trivial(&shadow_tex)?; + /* let tgt_shadow_res = factory.view_texture_as_shader_resource::( + &tgt_color_tex, + (0, levels - 1), + gfx::format::Swizzle::new(), + )?; */ + + // let tgt_shadow_view = + // factory.view_texture_as_depth_stencil_trivial(&tgt_color_tex)?; + // let tgt_shadow_view = factory.view_texture_as_shader_resource(&tgt_color_tex, + // 0, None)?; + let tgt_shadow_res = factory.view_texture_as_shader_resource::( + &shadow_tex, + (0, levels - 1), + gfx::format::Swizzle::new(), + )?; + + Ok((tgt_shadow_view, tgt_shadow_res, shadow_tex_sampler)) + } + /// Get the resolution of the render target. pub fn get_resolution(&self) -> Vec2 { Vec2::new( @@ -322,14 +468,29 @@ impl Renderer { /// Queue the clearing of the depth target ready for a new frame to be /// rendered. pub fn clear(&mut self) { + if let Some(shadow_map) = self.shadow_map.as_mut() { + shadow_map + .encoder + .clear_depth(&shadow_map.depth_stencil_view, 1.0); + } self.encoder.clear_depth(&self.tgt_depth_stencil_view, 1.0); self.encoder.clear_stencil(&self.tgt_depth_stencil_view, 0); self.encoder.clear_depth(&self.win_depth_view, 1.0); } + /// Perform all queued draw calls for shadows. + pub fn flush_shadows(&mut self) { + if let Some(shadow_map) = self.shadow_map.as_mut() { + shadow_map.encoder.flush(&mut self.device); + } + } + /// Perform all queued draw calls for this frame and clean up discarded /// items. pub fn flush(&mut self) { + if let Some(shadow_map) = self.shadow_map.as_mut() { + shadow_map.encoder.flush(&mut self.device); + } self.encoder.flush(&mut self.device); self.device.cleanup(); @@ -346,6 +507,7 @@ impl Renderer { self.aa_mode, self.cloud_mode, self.fluid_mode, + self.lighting_mode, &mut self.shader_reload_indicator, ) { Ok(( @@ -358,6 +520,7 @@ impl Renderer { lod_terrain_pipeline, postprocess_pipeline, player_shadow_pipeline, + shadow_pipeline, )) => { self.skybox_pipeline = skybox_pipeline; self.figure_pipeline = figure_pipeline; @@ -368,6 +531,11 @@ impl Renderer { self.lod_terrain_pipeline = lod_terrain_pipeline; self.postprocess_pipeline = postprocess_pipeline; self.player_shadow_pipeline = player_shadow_pipeline; + if let (Some(pipeline), Some(shadow_map)) = + (shadow_pipeline, self.shadow_map.as_mut()) + { + shadow_map.pipeline = pipeline; + } }, Err(e) => error!( "Could not recreate shaders from assets due to an error: {:#?}", @@ -516,6 +684,8 @@ impl Renderer { model: &Model, globals: &Consts, locals: &Consts, + map: &Texture, + horizon: &Texture, ) { self.encoder.draw( &gfx::Slice { @@ -531,6 +701,8 @@ impl Renderer { locals: locals.buf.clone(), globals: globals.buf.clone(), noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), + map: (map.srv.clone(), map.sampler.clone()), + horizon: (horizon.srv.clone(), horizon.sampler.clone()), tgt_color: self.tgt_color_view.clone(), tgt_depth_stencil: (self.tgt_depth_stencil_view.clone(), (1, 1)), }, @@ -549,6 +721,12 @@ impl Renderer { map: &Texture, horizon: &Texture, ) { + let shadow_maps = if let Some(shadow_map) = &mut self.shadow_map { + (shadow_map.res.clone(), shadow_map.sampler.clone()) + } else { + (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()) + }; + self.encoder.draw( &gfx::Slice { start: model.vertex_range().start, @@ -565,6 +743,7 @@ impl Renderer { bones: bones.buf.clone(), lights: lights.buf.clone(), shadows: shadows.buf.clone(), + shadow_maps, noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), map: (map.srv.clone(), map.sampler.clone()), horizon: (horizon.srv.clone(), horizon.sampler.clone()), @@ -586,6 +765,12 @@ impl Renderer { map: &Texture, horizon: &Texture, ) { + let shadow_maps = if let Some(shadow_map) = &mut self.shadow_map { + (shadow_map.res.clone(), shadow_map.sampler.clone()) + } else { + (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()) + }; + self.encoder.draw( &gfx::Slice { start: model.vertex_range().start, @@ -602,6 +787,7 @@ impl Renderer { bones: bones.buf.clone(), lights: lights.buf.clone(), shadows: shadows.buf.clone(), + shadow_maps, noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), map: (map.srv.clone(), map.sampler.clone()), horizon: (horizon.srv.clone(), horizon.sampler.clone()), @@ -623,6 +809,12 @@ impl Renderer { map: &Texture, horizon: &Texture, ) { + let shadow_maps = if let Some(shadow_map) = &mut self.shadow_map { + (shadow_map.res.clone(), shadow_map.sampler.clone()) + } else { + (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()) + }; + self.encoder.draw( &gfx::Slice { start: model.vertex_range().start, @@ -639,6 +831,7 @@ impl Renderer { bones: bones.buf.clone(), lights: lights.buf.clone(), shadows: shadows.buf.clone(), + shadow_maps, noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), map: (map.srv.clone(), map.sampler.clone()), horizon: (horizon.srv.clone(), horizon.sampler.clone()), @@ -660,6 +853,12 @@ impl Renderer { map: &Texture, horizon: &Texture, ) { + let shadow_maps = if let Some(shadow_map) = &mut self.shadow_map { + (shadow_map.res.clone(), shadow_map.sampler.clone()) + } else { + (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()) + }; + self.encoder.draw( &gfx::Slice { start: model.vertex_range().start, @@ -675,6 +874,7 @@ impl Renderer { globals: globals.buf.clone(), lights: lights.buf.clone(), shadows: shadows.buf.clone(), + shadow_maps, noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), map: (map.srv.clone(), map.sampler.clone()), horizon: (horizon.srv.clone(), horizon.sampler.clone()), @@ -684,6 +884,53 @@ impl Renderer { ); } + /// Queue the rendering of the player silhouette in the upcoming frame. + pub fn render_shadow( + &mut self, + model: &Model, + globals: &Consts, + terrain_locals: &Consts, + locals: &Consts, + lights: &Consts, + shadows: &Consts, + map: &Texture, + horizon: &Texture, + ) { + // NOTE: Don't render shadows if the shader is not supported. + let shadow_map = if let Some(shadow_map) = &mut self.shadow_map { + shadow_map + } else { + return; + }; + shadow_map.encoder.draw( + &gfx::Slice { + start: model.vertex_range().start, + end: model.vertex_range().end, + base_vertex: 0, + instances: None, + buffer: gfx::IndexBuffer::Auto, + }, + &shadow_map.pipeline.pso, + &shadow::pipe::Data { + // Terrain vertex stuff + vbuf: model.vbuf.clone(), + locals: terrain_locals.buf.clone(), + globals: globals.buf.clone(), + lights: lights.buf.clone(), + shadows: shadows.buf.clone(), + noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), + map: (map.srv.clone(), map.sampler.clone()), + horizon: (horizon.srv.clone(), horizon.sampler.clone()), + + // Shadow stuff + light_shadows: locals.buf.clone(), + tgt_depth_stencil: shadow_map.depth_stencil_view.clone(), + /* tgt_depth_stencil: (self.shadow_depth_stencil_view.clone(), (1, 1)), + * shadow_tex: (self.shadow_res.clone(), self.shadow_sampler.clone()), */ + }, + ); + } + /// Queue the rendering of the provided terrain chunk model in the upcoming /// frame. pub fn render_fluid_chunk( @@ -697,6 +944,11 @@ impl Renderer { horizon: &Texture, waves: &Texture, ) { + let shadow_maps = if let Some(shadow_map) = &mut self.shadow_map { + (shadow_map.res.clone(), shadow_map.sampler.clone()) + } else { + (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()) + }; self.encoder.draw( &gfx::Slice { start: model.vertex_range().start, @@ -712,6 +964,7 @@ impl Renderer { globals: globals.buf.clone(), lights: lights.buf.clone(), shadows: shadows.buf.clone(), + shadow_maps, map: (map.srv.clone(), map.sampler.clone()), horizon: (horizon.srv.clone(), horizon.sampler.clone()), noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), @@ -734,6 +987,11 @@ impl Renderer { map: &Texture, horizon: &Texture, ) { + let shadow_maps = if let Some(shadow_map) = &mut self.shadow_map { + (shadow_map.res.clone(), shadow_map.sampler.clone()) + } else { + (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()) + }; self.encoder.draw( &gfx::Slice { start: model.vertex_range().start, @@ -749,6 +1007,7 @@ impl Renderer { globals: globals.buf.clone(), lights: lights.buf.clone(), shadows: shadows.buf.clone(), + shadow_maps, noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), map: (map.srv.clone(), map.sampler.clone()), horizon: (horizon.srv.clone(), horizon.sampler.clone()), @@ -867,6 +1126,7 @@ fn create_pipelines( aa_mode: AaMode, cloud_mode: CloudMode, fluid_mode: FluidMode, + lighting_mode: LightingMode, shader_reload_indicator: &mut ReloadIndicator, ) -> Result< ( @@ -879,9 +1139,15 @@ fn create_pipelines( GfxPipeline>, GfxPipeline>, GfxPipeline>, + Option>>, ), RenderError, > { + let constants = assets::load_watched::( + "voxygen.shaders.include.constants", + shader_reload_indicator, + ) + .unwrap(); let globals = assets::load_watched::("voxygen.shaders.include.globals", shader_reload_indicator) .unwrap(); @@ -901,6 +1167,35 @@ fn create_pipelines( assets::load_watched::("voxygen.shaders.include.lod", shader_reload_indicator) .unwrap(); + // We dynamically add extra configuration settings to the constants file. + let constants = format!( + r#" +{} + +#define VOXYGEN_COMPUTATION_PREERENCE {} +#define FLUID_MODE {} +#define CLOUD_MODE {} +#define LIGHTING_ALGORITHM {} + +"#, + constants, + // TODO: Configurable vertex/fragment shader preference. + "VOXYGEN_COMPUTATION_PREERENCE_FRAGMENT", + match fluid_mode { + FluidMode::Cheap => "FLUID_MODE_CHEAP", + FluidMode::Shiny => "FLUID_MODE_SHINY", + }, + match cloud_mode { + CloudMode::None => "CLOUD_MODE_NONE", + CloudMode::Regular => "CLOUD_MODE_REGULAR", + }, + match lighting_mode { + LightingMode::Ashikmin => "LIGHTING_ALGORITHM_ASHIKHMIN", + LightingMode::BlinnPhong => "LIGHTING_ALGORITHM_BLINN_PHONG", + LightingMode::Lambertian => "CLOUD_MODE_NONE", + }, + ); + let anti_alias = assets::load_watched::( &["voxygen.shaders.antialias.", match aa_mode { AaMode::None | AaMode::SsaaX4 => "none", @@ -925,6 +1220,7 @@ fn create_pipelines( .unwrap(); let mut include_ctx = IncludeContext::new(); + include_ctx.include("constants.glsl", &constants); include_ctx.include("globals.glsl", &globals); include_ctx.include("sky.glsl", &sky); include_ctx.include("light.glsl", &light); @@ -1074,6 +1370,35 @@ fn create_pipelines( gfx::state::CullFace::Back, )?; + // Construct a pipeline for rendering shadow maps. + let shadow_pipeline = match create_shadow_pipeline( + factory, + shadow::pipe::new(), + &assets::load_watched::( + "voxygen.shaders.light-shadows-vert", + shader_reload_indicator, + ) + .unwrap(), + &assets::load_watched::( + "voxygen.shaders.light-shadows-geom", + shader_reload_indicator, + ) + .unwrap(), + &assets::load_watched::( + "voxygen.shaders.light-shadows-frag", + shader_reload_indicator, + ) + .unwrap(), + &include_ctx, + gfx::state::CullFace::Back, + ) { + Ok(pipe) => Some(pipe), + Err(err) => { + log::warn!("Could not load shadow map pipeline: {:?}", err); + None + }, + }; + Ok(( skybox_pipeline, figure_pipeline, @@ -1084,11 +1409,12 @@ fn create_pipelines( lod_terrain_pipeline, postprocess_pipeline, player_shadow_pipeline, + shadow_pipeline, )) } /// Create a new pipeline from the provided vertex shader and fragment shader. -fn create_pipeline<'a, P: gfx::pso::PipelineInit>( +fn create_pipeline( factory: &mut gfx_backend::Factory, pipe: P, vs: &str, @@ -1118,3 +1444,45 @@ fn create_pipeline<'a, P: gfx::pso::PipelineInit>( result } + +/// Create a new shadow map pipeline. +fn create_shadow_pipeline( + factory: &mut gfx_backend::Factory, + pipe: P, + vs: &str, + gs: &str, + fs: &str, + ctx: &IncludeContext, + cull_face: gfx::state::CullFace, +) -> Result, RenderError> { + let vs = ctx.expand(vs)?; + let gs = ctx.expand(gs)?; + let fs = ctx.expand(fs)?; + + let shader_set = + factory.create_shader_set_geometry(vs.as_bytes(), gs.as_bytes(), fs.as_bytes())?; + + let result = Ok(GfxPipeline { + pso: factory.create_pipeline_state( + &shader_set, + gfx::Primitive::TriangleList, + gfx::state::Rasterizer { + front_face: gfx::state::FrontFace::CounterClockwise, + // Second-depth shadow mapping: should help reduce z-fighting provided all objects + // are "watertight" (every triangle edge is shared with at most one other + // triangle); this *should* be true for Veloren. + cull_face: /*cull_face*//*gfx::state::CullFace::Nothing*/match cull_face { + gfx::state::CullFace::Front => gfx::state::CullFace::Back, + gfx::state::CullFace::Back => gfx::state::CullFace::Front, + gfx::state::CullFace::Nothing => gfx::state::CullFace::Nothing, + }, + method: gfx::state::RasterMethod::Fill, + offset: Some(gfx::state::Offset(4, /*10*/10)), + samples: None,//Some(gfx::state::MultiSample), + }, + pipe, + )?, + }); + + result +} diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 7cf671d271..0cd40b99a5 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -15,7 +15,7 @@ use crate::{ audio::{music::MusicMgr, sfx::SfxMgr, AudioFrontend}, render::{ create_pp_mesh, create_skybox_mesh, Consts, Globals, Light, Model, PostProcessLocals, - PostProcessPipeline, Renderer, Shadow, SkyboxLocals, SkyboxPipeline, + PostProcessPipeline, Renderer, Shadow, ShadowLocals, SkyboxLocals, SkyboxPipeline, }, settings::Settings, window::{AnalogGameInput, Event}, @@ -39,6 +39,12 @@ const LIGHT_DIST_RADIUS: f32 = 64.0; // The distance beyond which lights may not const SHADOW_DIST_RADIUS: f32 = 8.0; const SHADOW_MAX_DIST: f32 = 96.0; // The distance beyond which shadows may not be visible +// const NEAR_PLANE: f32 = 0.5; +// const FAR_PLANE: f32 = 100000.0; + +const SHADOW_NEAR: f32 = 0.5; //0.5;//1.0; // Near plane for shadow map rendering. +const SHADOW_FAR: f32 = 512.0; //100000.0;//25.0; // Far plane for shadow map rendering. + /// Above this speed is considered running /// Used for first person camera effects const RUNNING_THRESHOLD: f32 = 0.7; @@ -56,6 +62,7 @@ struct PostProcess { pub struct Scene { globals: Consts, lights: Consts, + shadow_mats: Consts, shadows: Consts, camera: Camera, camera_input_state: Vec2, @@ -102,6 +109,9 @@ impl Scene { shadows: renderer .create_consts(&[Shadow::default(); MAX_SHADOW_COUNT]) .unwrap(), + shadow_mats: renderer + .create_consts(&[ShadowLocals::default(); MAX_LIGHT_COUNT * 6]) + .unwrap(), camera: Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson), camera_input_state: Vec2::zero(), @@ -344,6 +354,41 @@ impl Scene { .update_consts(&mut self.shadows, &shadows) .expect("Failed to update light constants"); + // Update light projection matrices for the shadow map. + // NOTE: The aspect ratio is currently always 1 for our cube maps, since they + // are equal on all sides. + let shadow_aspect = 1.0; + // First, create a perspective projection matrix at 90 degrees (to cover a whole + // face of the cube map we're using). + let shadow_proj = + Mat4::perspective_rh_no(90.0f32.to_radians(), shadow_aspect, SHADOW_NEAR, SHADOW_FAR); + // Next, construct the 6 orientations we'll use for the six faces, in terms of + // their (forward, up) vectors. + let orientations = [ + (Vec3::new(1.0, 0.0, 0.0), Vec3::new(0.0, -1.0, 0.0)), + (Vec3::new(-1.0, 0.0, 0.0), Vec3::new(0.0, -1.0, 0.0)), + (Vec3::new(0.0, 1.0, 0.0), Vec3::new(0.0, 0.0, 1.0)), + (Vec3::new(0.0, -1.0, 0.0), Vec3::new(0.0, 0.0, -1.0)), + (Vec3::new(0.0, 0.0, 1.0), Vec3::new(0.0, -1.0, 0.0)), + (Vec3::new(0.0, 0.0, -1.0), Vec3::new(0.0, -1.0, 0.0)), + ]; + // NOTE: We could create the shadow map collection at the same time as the + // lights, but then we'd have to sort them both, which wastes time. + let shadow_mats = lights + .iter() + .flat_map(|light| { + // Now, construct the full projection matrix by making the light look at each + // cube face. + let eye = Vec3::new(light.pos[0], light.pos[1], light.pos[2]); + orientations.iter().map(move |&(forward, up)| { + ShadowLocals::new(shadow_proj * Mat4::look_at_rh(eye, eye + forward, up)) + }) + }) + .collect::>(); + renderer + .update_consts(&mut self.shadow_mats, &shadow_mats) + .expect("Failed to update light constants"); + // Update global constants. renderer .update_consts(&mut self.globals, &[Globals::new( @@ -357,6 +402,7 @@ impl Scene { scene_data.state.get_time_of_day(), scene_data.state.get_time(), renderer.get_resolution(), + Vec2::new(SHADOW_NEAR, SHADOW_FAR), lights.len(), shadows.len(), scene_data @@ -413,6 +459,7 @@ impl Scene { &self.globals, &self.lights, &self.shadows, + &self.shadow_mats, self.lod.get_data(), self.camera.get_focus_pos(), ); @@ -431,7 +478,14 @@ impl Scene { self.lod.render(renderer, &self.globals); // Render the skybox. - renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals); + let lod = self.lod.get_data(); + renderer.render_skybox( + &self.skybox.model, + &self.globals, + &self.skybox.locals, + &lod.map, + &lod.horizon, + ); self.figure_mgr.render_player( renderer, @@ -441,7 +495,7 @@ impl Scene { &self.globals, &self.lights, &self.shadows, - self.lod.get_data(), + lod, &self.camera, scene_data.figure_lod_render_distance, ); @@ -451,7 +505,7 @@ impl Scene { &self.globals, &self.lights, &self.shadows, - self.lod.get_data(), + lod, self.camera.get_focus_pos(), scene_data.sprite_render_distance, ); diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index 4173889e02..df106582f3 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -206,6 +206,8 @@ impl Scene { const VD: f32 = 115.0; // View Distance // const MAP_BOUNDS: Vec2 = Vec2::new(140.0, 2048.0); const TIME: f64 = 10.0 * 60.0 * 60.0; //43200.0; // 12 hours*3600 seconds + const SHADOW_NEAR: f32 = 1.0; + const SHADOW_FAR: f32 = 25.0; if let Err(err) = renderer.update_consts(&mut self.globals, &[Globals::new( view_mat, @@ -218,6 +220,7 @@ impl Scene { TIME, scene_data.time, renderer.get_resolution(), + Vec2::new(SHADOW_NEAR, SHADOW_FAR), 0, 0, BlockKind::Air, @@ -265,7 +268,13 @@ impl Scene { body: Option, loadout: Option<&Loadout>, ) { - renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals); + renderer.render_skybox( + &self.skybox.model, + &self.globals, + &self.skybox.locals, + &self.lod.map, + &self.lod.horizon, + ); if let Some(body) = body { let model = &self diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 009843052b..0b4c092d16 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -2,7 +2,7 @@ use crate::{ mesh::Meshable, render::{ Consts, FluidPipeline, Globals, Instances, Light, Mesh, Model, Renderer, Shadow, - SpriteInstance, SpritePipeline, TerrainLocals, TerrainPipeline, Texture, + ShadowLocals, SpriteInstance, SpritePipeline, TerrainLocals, TerrainPipeline, Texture, }, }; @@ -2191,6 +2191,7 @@ impl Terrain { globals: &Consts, lights: &Consts, shadows: &Consts, + shadow_mats: &Consts, lod: &LodData, focus_pos: Vec3, ) { @@ -2205,8 +2206,28 @@ impl Terrain { }) .take(self.chunks.len()); - // Opaque + // Shadows for (_, chunk) in chunk_iter.clone() { + /* if chunk.visible */ + { + renderer.render_shadow( + &chunk.opaque_model, + globals, + &chunk.locals, + shadow_mats, + lights, + shadows, + &lod.map, + &lod.horizon, + ); + } + } + + // Flush shadows. + renderer.flush_shadows(); + + // Terrain + for (_, chunk) in chunk_iter { if chunk.visible { renderer.render_terrain_chunk( &chunk.opaque_model, diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 364c4a3828..060fb43c86 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -700,6 +700,16 @@ impl PlayState for SessionState { localized_strings.log_missing_entries(); self.hud.update_language(localized_strings.clone()); }, + HudEvent::ChangeLightingMode(new_lighting_mode) => { + // Do this first so if it crashes the setting isn't saved :) + global_state + .window + .renderer_mut() + .set_lighting_mode(new_lighting_mode) + .unwrap(); + global_state.settings.graphics.lighting_mode = new_lighting_mode; + global_state.settings.save_to_file_warn(); + }, HudEvent::ToggleFullscreen => { global_state .window @@ -751,6 +761,10 @@ impl PlayState for SessionState { } let renderer = global_state.window.renderer_mut(); + + // Flush renderer to synchronize commands sent on the main encoder with the + // start of the shadow encoder. + renderer.flush(); // Clear the screen renderer.clear(); // Render the screen using the global renderer diff --git a/voxygen/src/settings.rs b/voxygen/src/settings.rs index 72d7b63395..a32876432c 100644 --- a/voxygen/src/settings.rs +++ b/voxygen/src/settings.rs @@ -1,7 +1,7 @@ use crate::{ hud::{BarNumbers, CrosshairType, Intro, PressBehavior, ShortcutNumbers, XpBar}, i18n, - render::{AaMode, CloudMode, FluidMode}, + render::{AaMode, CloudMode, FluidMode, LightingMode}, ui::ScaleMode, window::{GameInput, KeyMouse}, }; @@ -556,6 +556,7 @@ pub struct GraphicsSettings { pub aa_mode: AaMode, pub cloud_mode: CloudMode, pub fluid_mode: FluidMode, + pub lighting_mode: LightingMode, pub window_size: [u16; 2], pub fullscreen: bool, pub lod_detail: u32, @@ -573,6 +574,7 @@ impl Default for GraphicsSettings { aa_mode: AaMode::Fxaa, cloud_mode: CloudMode::Regular, fluid_mode: FluidMode::Shiny, + lighting_mode: LightingMode::Ashikmin, window_size: [1920, 1080], fullscreen: false, lod_detail: 500, diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index c43ab6a05f..92e783c0cc 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -451,6 +451,7 @@ impl Window { settings.graphics.aa_mode, settings.graphics.cloud_mode, settings.graphics.fluid_mode, + settings.graphics.lighting_mode, )?, window, cursor_grabbed: false,