WIP: better graphics config, better LOD, shadow maps.

This commit is contained in:
Joshua Yanovski 2020-05-15 14:22:17 +02:00
parent 22ddbad3eb
commit 04382dc286
43 changed files with 1860 additions and 104 deletions

View File

@ -1,4 +1,18 @@
#version 330 core
#version 400 core
#include <constants.glsl>
#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 <globals.glsl>
@ -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;

View File

@ -1,5 +1,17 @@
#version 330 core
#include <constants.glsl>
#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 <globals.glsl>
#include <lod.glsl>

View File

@ -1,4 +1,22 @@
#version 330 core
#version 400 core
#include <constants.glsl>
#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 <globals.glsl>
#include <random.glsl>
@ -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);

View File

@ -1,4 +1,22 @@
#version 330 core
#version 400 core
#include <constants.glsl>
#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));

View File

@ -1,7 +1,24 @@
#version 330 core
#include <constants.glsl>
#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 <globals.glsl>
#include <srgb.glsl>
#include <random.glsl>
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),

View File

@ -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) {

View File

@ -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 <preference>
#define FLUID_MODE <mode>
#define CLOUD_MODE <mode>
#define LIGHTING_ALGORITHM <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 <type bitmask>
#define LIGHTING_REFLECTION_KIND <kind>
#define LIGHTING_TRANSPORT_MODE <mode>
#define LIGHTING_DISTRIBUTION_SCHEME <scheme>
#define LIGHTING_DISTRIBUTION <distribution>
*/

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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)));
}

View File

@ -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
}

View File

@ -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 <constants.glsl>
#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 <globals.glsl>
// Currently, we only need lights for the light position
#include <light.glsl>
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;
}

View File

@ -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 <globals.glsl>
// 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();
// }
}
}

View File

@ -0,0 +1,51 @@
#version 330 core
#include <constants.glsl>
#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 <globals.glsl>
/* 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);
}

View File

@ -1,5 +1,21 @@
#version 330 core
#include <constants.glsl>
#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 <globals.glsl>
#include <sky.glsl>
#include <lod.glsl>
@ -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);

View File

@ -1,5 +1,21 @@
#version 330 core
#include <constants.glsl>
#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 <globals.glsl>
#include <srgb.glsl>
#include <lod.glsl>

View File

@ -1,5 +1,17 @@
#version 330 core
#include <constants.glsl>
#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 <globals.glsl>
in vec3 f_pos;

View File

@ -1,8 +1,25 @@
#version 330 core
#include <constants.glsl>
#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 <globals.glsl>
// Note: The sampler uniform is declared here because it differs for MSAA
#include <anti-aliasing.glsl>
#include <srgb.glsl>
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;

View File

@ -1,5 +1,21 @@
#version 330 core
#include <constants.glsl>
#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 <globals.glsl>
in vec2 v_pos;

View File

@ -1,7 +1,24 @@
#version 330 core
#include <constants.glsl>
#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 <globals.glsl>
#include <sky.glsl>
#include <lod.glsl>
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);
}

View File

@ -1,5 +1,21 @@
#version 330 core
#include <constants.glsl>
#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 <globals.glsl>
in vec3 v_pos;

View File

@ -1,4 +1,18 @@
#version 330 core
#version 400 core
#include <constants.glsl>
#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 <globals.glsl>
@ -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);

View File

@ -1,5 +1,17 @@
#version 330 core
#include <constants.glsl>
#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 <globals.glsl>
#include <srgb.glsl>

View File

@ -1,4 +1,22 @@
#version 330 core
#version 400 core
#include <constants.glsl>
#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 <globals.glsl>
#include <random.glsl>
@ -19,13 +37,45 @@ out vec4 tgt_color;
#include <lod.glsl>
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;

View File

@ -1,5 +1,21 @@
#version 330 core
#include <constants.glsl>
#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 <globals.glsl>
#include <srgb.glsl>
#include <lod.glsl>

View File

@ -22,6 +22,7 @@ fn main() {
render::AaMode::SsaaX4,
render::CloudMode::Regular,
render::FluidMode::Shiny,
render::LightingMode::Ashikmin,
)
.unwrap();

View File

@ -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);
},

View File

@ -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);

View File

@ -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,
}

View File

@ -38,6 +38,8 @@ gfx_defines! {
lights: gfx::ConstantBuffer<Light> = "u_lights",
shadows: gfx::ConstantBuffer<Shadow> = "u_shadows",
shadow_maps: gfx::TextureSampler<f32> = "t_shadow_maps",
map: gfx::TextureSampler<[f32; 4]> = "t_map",
horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon",

View File

@ -23,6 +23,9 @@ gfx_defines! {
globals: gfx::ConstantBuffer<Globals> = "u_globals",
lights: gfx::ConstantBuffer<Light> = "u_lights",
shadows: gfx::ConstantBuffer<Shadow> = "u_shadows",
shadow_maps: gfx::TextureSampler<f32> = "t_shadow_maps",
map: gfx::TextureSampler<[f32; 4]> = "t_map",
horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon",

View File

@ -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<u16>,
shadow_planes: Vec2<f32>,
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,

View File

@ -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<Vertex> = (),
locals: gfx::ConstantBuffer<TerrainLocals> = "u_locals",
globals: gfx::ConstantBuffer<Globals> = "u_globals",
lights: gfx::ConstantBuffer<Light> = "u_lights",
shadows: gfx::ConstantBuffer<Shadow> = "u_shadows",
map: gfx::TextureSampler<[f32; 4]> = "t_map",
horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon",
noise: gfx::TextureSampler<f32> = "t_noise",
// Shadow stuff
light_shadows: gfx::ConstantBuffer<Locals> = "u_light_shadows",
tgt_depth_stencil: gfx::DepthTarget<ShadowDepthStencilFmt> = 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<f32>) -> 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;
}

View File

@ -23,6 +23,9 @@ gfx_defines! {
locals: gfx::ConstantBuffer<Locals> = "u_locals",
globals: gfx::ConstantBuffer<Globals> = "u_globals",
map: gfx::TextureSampler<[f32; 4]> = "t_map",
horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon",
noise: gfx::TextureSampler<f32> = "t_noise",
tgt_color: gfx::RenderTarget<TgtColorFmt> = "tgt_color",

View File

@ -37,6 +37,8 @@ gfx_defines! {
lights: gfx::ConstantBuffer<Light> = "u_lights",
shadows: gfx::ConstantBuffer<Shadow> = "u_shadows",
shadow_maps: gfx::TextureSampler<f32> = "t_shadow_maps",
map: gfx::TextureSampler<[f32; 4]> = "t_map",
horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon",

View File

@ -29,6 +29,8 @@ gfx_defines! {
lights: gfx::ConstantBuffer<Light> = "u_lights",
shadows: gfx::ConstantBuffer<Shadow> = "u_shadows",
shadow_maps: gfx::TextureSampler<f32> = "t_shadow_maps",
map: gfx::TextureSampler<[f32; 4]> = "t_map",
horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon",

View File

@ -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<gfx_backend::Resources, TgtColorFmt>;
/// 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<gfx_backend::Resources, ShadowDepthStencilFmt>;
/// A handle to a shadow depth target as a resource.
pub type ShadowResourceView = gfx::handle::ShaderResourceView<
gfx_backend::Resources,
<ShadowDepthStencilFmt as gfx::format::Formatted>::View,
>;
/// A handle to a render color target as a resource.
pub type TgtColorRes = gfx::handle::ShaderResourceView<
gfx_backend::Resources,
<TgtColorFmt as gfx::format::Formatted>::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<gfx_backend::Resources, gfx_backend::CommandBuffer>,
depth_stencil_view: ShadowDepthStencilView,
res: ShadowResourceView,
sampler: Sampler<gfx_backend::Resources>,
pipeline: GfxPipeline<shadow::pipe::Init<'static>>,
}
/// 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<gfx_backend::Resources>,
shadow_map: Option<ShadowMapRenderer>,
skybox_pipeline: GfxPipeline<skybox::pipe::Init<'static>>,
figure_pipeline: GfxPipeline<figure::pipe::Init<'static>>,
terrain_pipeline: GfxPipeline<terrain::pipe::Init<'static>>,
@ -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<Self, RenderError> {
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<gfx_backend::Resources>,
),
RenderError,
> {
let levels = 1;
/* let color_cty = <<TgtColorFmt as gfx::format::Formatted>::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::<TgtColorFmt>(
&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 = <<TgtDepthStencilFmt as gfx::format::Formatted>::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 = <<ShadowDepthStencilFmt as gfx::format::Formatted>::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(<<F as gfx::format::Formatted>::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::<TgtColorFmt>(
&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::<ShadowDepthStencilFmt>(
&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<u16> {
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<skybox::SkyboxPipeline>,
globals: &Consts<Globals>,
locals: &Consts<skybox::Locals>,
map: &Texture<LodColorFmt>,
horizon: &Texture<LodTextureFmt>,
) {
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<LodColorFmt>,
horizon: &Texture<LodTextureFmt>,
) {
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<LodColorFmt>,
horizon: &Texture<LodTextureFmt>,
) {
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<LodColorFmt>,
horizon: &Texture<LodTextureFmt>,
) {
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<LodColorFmt>,
horizon: &Texture<LodTextureFmt>,
) {
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<terrain::TerrainPipeline>,
globals: &Consts<Globals>,
terrain_locals: &Consts<terrain::Locals>,
locals: &Consts<shadow::Locals>,
lights: &Consts<Light>,
shadows: &Consts<Shadow>,
map: &Texture<LodColorFmt>,
horizon: &Texture<LodTextureFmt>,
) {
// 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<LodTextureFmt>,
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<LodColorFmt>,
horizon: &Texture<LodTextureFmt>,
) {
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<lod_terrain::pipe::Init<'static>>,
GfxPipeline<postprocess::pipe::Init<'static>>,
GfxPipeline<figure::pipe::Init<'static>>,
Option<GfxPipeline<shadow::pipe::Init<'static>>>,
),
RenderError,
> {
let constants = assets::load_watched::<String>(
"voxygen.shaders.include.constants",
shader_reload_indicator,
)
.unwrap();
let globals =
assets::load_watched::<String>("voxygen.shaders.include.globals", shader_reload_indicator)
.unwrap();
@ -901,6 +1167,35 @@ fn create_pipelines(
assets::load_watched::<String>("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::<String>(
&["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::<String>(
"voxygen.shaders.light-shadows-vert",
shader_reload_indicator,
)
.unwrap(),
&assets::load_watched::<String>(
"voxygen.shaders.light-shadows-geom",
shader_reload_indicator,
)
.unwrap(),
&assets::load_watched::<String>(
"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<P: gfx::pso::PipelineInit>(
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<P: gfx::pso::PipelineInit>(
factory: &mut gfx_backend::Factory,
pipe: P,
vs: &str,
gs: &str,
fs: &str,
ctx: &IncludeContext,
cull_face: gfx::state::CullFace,
) -> Result<GfxPipeline<P>, 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
}

View File

@ -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<Globals>,
lights: Consts<Light>,
shadow_mats: Consts<ShadowLocals>,
shadows: Consts<Shadow>,
camera: Camera,
camera_input_state: Vec2<f32>,
@ -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::<Vec<_>>();
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,
);

View File

@ -206,6 +206,8 @@ impl Scene {
const VD: f32 = 115.0; // View Distance
// const MAP_BOUNDS: Vec2<f32> = 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<humanoid::Body>,
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

View File

@ -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<V: RectRasterableVol> Terrain<V> {
globals: &Consts<Globals>,
lights: &Consts<Light>,
shadows: &Consts<Shadow>,
shadow_mats: &Consts<ShadowLocals>,
lod: &LodData,
focus_pos: Vec3<f32>,
) {
@ -2205,8 +2206,28 @@ impl<V: RectRasterableVol> Terrain<V> {
})
.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,

View File

@ -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

View File

@ -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,

View File

@ -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,