From a4d87e1875ca543436e6bbbeb20348facc5a52d7 Mon Sep 17 00:00:00 2001 From: Joshua Yanovski Date: Sun, 17 May 2020 05:59:00 +0200 Subject: [PATCH] Shadow maps work for lantern. --- assets/voxygen/shaders/figure-frag.glsl | 2 +- assets/voxygen/shaders/fluid-frag/cheap.glsl | 2 +- assets/voxygen/shaders/fluid-frag/shiny.glsl | 2 +- assets/voxygen/shaders/include/globals.glsl | 1 + assets/voxygen/shaders/include/light.glsl | 96 +++++++++++++++---- assets/voxygen/shaders/include/sky.glsl | 4 +- .../voxygen/shaders/light-shadows-frag.glsl | 23 +++-- .../voxygen/shaders/light-shadows-geom.glsl | 89 +++++++++++++---- .../voxygen/shaders/light-shadows-vert.glsl | 3 +- assets/voxygen/shaders/sprite-frag.glsl | 2 +- assets/voxygen/shaders/terrain-frag.glsl | 31 ++++-- voxygen/src/render/pipelines/mod.rs | 21 +++- voxygen/src/render/pipelines/shadow.rs | 2 +- voxygen/src/render/renderer.rs | 59 +++++++++--- voxygen/src/scene/mod.rs | 68 +++++++++---- voxygen/src/scene/simple.rs | 1 + 16 files changed, 319 insertions(+), 87 deletions(-) diff --git a/assets/voxygen/shaders/figure-frag.glsl b/assets/voxygen/shaders/figure-frag.glsl index 9221658add..70bbb183c0 100644 --- a/assets/voxygen/shaders/figure-frag.glsl +++ b/assets/voxygen/shaders/figure-frag.glsl @@ -1,4 +1,4 @@ -#version 400 core +#version 330 core #include diff --git a/assets/voxygen/shaders/fluid-frag/cheap.glsl b/assets/voxygen/shaders/fluid-frag/cheap.glsl index 2ab5f37561..e57fbdb6e6 100644 --- a/assets/voxygen/shaders/fluid-frag/cheap.glsl +++ b/assets/voxygen/shaders/fluid-frag/cheap.glsl @@ -1,4 +1,4 @@ -#version 400 core +#version 330 core #include diff --git a/assets/voxygen/shaders/fluid-frag/shiny.glsl b/assets/voxygen/shaders/fluid-frag/shiny.glsl index 105da5a917..2cb0565bb4 100644 --- a/assets/voxygen/shaders/fluid-frag/shiny.glsl +++ b/assets/voxygen/shaders/fluid-frag/shiny.glsl @@ -1,4 +1,4 @@ -#version 400 core +#version 330 core #include diff --git a/assets/voxygen/shaders/include/globals.glsl b/assets/voxygen/shaders/include/globals.glsl index 895492a23a..69450dadb2 100644 --- a/assets/voxygen/shaders/include/globals.glsl +++ b/assets/voxygen/shaders/include/globals.glsl @@ -10,6 +10,7 @@ uniform u_globals { vec4 tick; vec4 screen_res; uvec4 light_shadow_count; + vec4 shadow_proj_factors; uvec4 medium; ivec4 select_pos; vec4 gamma; diff --git a/assets/voxygen/shaders/include/light.glsl b/assets/voxygen/shaders/include/light.glsl index cceadae608..43b1d7dc89 100644 --- a/assets/voxygen/shaders/include/light.glsl +++ b/assets/voxygen/shaders/include/light.glsl @@ -3,6 +3,7 @@ struct Light { vec4 light_pos; vec4 light_col; + // mat4 light_proj; }; layout (std140) @@ -26,27 +27,86 @@ float attenuation_strength(vec3 rpos) { } #ifdef HAS_SHADOW_MAPS -uniform samplerCubeArrayShadow t_shadow_maps; +// uniform samplerCubeArrayShadow t_shadow_maps; +// uniform samplerCubeArray t_shadow_maps; +uniform samplerCubeShadow t_shadow_maps; +// uniform samplerCube t_shadow_maps; -float ShadowCalculation(uint lightIndex, vec3 fragToLight, float currentDepth) +float VectorToDepth (vec3 Vec) { - // return 1.0; + vec3 AbsVec = abs(Vec); + float LocalZcomp = max(AbsVec.x, max(AbsVec.y, AbsVec.z)); + + // Replace f and n with the far and near plane values you used when + // you drew your cube map. + // const float f = 2048.0; + // const float n = 1.0; + + // float NormZComp = (screen_res.w+screen_res.z) / (screen_res.w-screen_res.z) - (2*screen_res.w*screen_res.z)/(screen_res.w-screen_res.z)/LocalZcomp; + float NormZComp = shadow_proj_factors.x - shadow_proj_factors.y / LocalZcomp; + return (NormZComp + 1.0) * 0.5; +} + +const vec3 sampleOffsetDirections[20] = vec3[] +( + vec3( 1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1), + vec3( 1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1), + vec3( 1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0), + vec3( 1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1), + vec3( 0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1) + // vec3(0, 0, 0) +); + +float ShadowCalculation(uint lightIndex, vec3 fragToLight, /*float currentDepth*/vec3 fragPos) +{ + // float shadow = 0.0; + float bias = 0.0;//-0.1;//0.0;//0.1 + // int samples = 20; + // float lightDistance = length(fragToLight); + // float viewDistance = length(cam_pos.xyz - fragPos); + // // float diskRadius = 0.00001; + // // float diskRadius = 1.0; + // float diskRadius = (1.0 + (/*viewDistance*/viewDistance / screen_res.w)) / 2.0; + // // float diskRadius = lightDistance; + // for(int i = 0; i < samples; ++i) + // { + // float currentDepth = VectorToDepth(fragToLight + sampleOffsetDirections[i] * diskRadius) + bias; + // // float closestDepth = texture(depthMap, fragToLight).r; + // // closestDepth *= far_plane; // Undo mapping [0;1] + // /* if(currentDepth - bias > closestDepth) + // shadow += 1.0;*/ + // float visibility = texture(t_shadow_maps, vec4(fragToLight, currentDepth)); + // shadow += visibility; + // } + // shadow /= float(samples); + // // shadow = shadow * shadow * (3.0 - 2.0 * shadow); + // 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 bias = 0.0;///*0.05*/0.01;//0.05;// 0.05; + // float closestDepth = texture(t_shadow_maps, /*vec4*/vec3(fragToLight/*, (lightIndex + 1)*//* * 6*/)/*, 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 = (closestDepth + 0.0) * 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*/); + // float visibility = texture(t_shadow_maps, vec4(fragToLight, lightIndex + 1), -(currentDepth/* + screen_res.z*/) / screen_res.w);// / (screen_res.w/* - screen_res.z*/)/*1.0 -bias*//*-(currentDepth - bias) / screen_res.w*//*-screen_res.w*/); + // currentDepth += bias; + // currentDepth = -1000.0 / (currentDepth + 10000.0); + // currentDepth /= screen_res.w; + float currentDepth = VectorToDepth(fragToLight) + bias; + if (lightIndex != 0u) { + return 1.0; + }; + + float visibility = texture(t_shadow_maps, vec4(fragToLight, currentDepth));// / (screen_res.w/* - screen_res.z*/)/*1.0 -bias*//*-(currentDepth - bias) / screen_res.w*//*-screen_res.w*/); return visibility; + // return shadow; } #else -float ShadowCalculation(uint lightIndex, vec3 fragToLight, float currentDepth) +float ShadowCalculation(uint lightIndex, vec3 fragToLight, /*float currentDepth*/vec3 fragPos) { return 1.0; } @@ -164,7 +224,7 @@ float lights_at(vec3 wpos, vec3 wnorm, vec3 /*cam_to_frag*/view_dir, vec3 mu, ve // Multiply the vec3 only once const float PI = 3.1415926535897932384626433832795; const float PI_2 = 2 * PI; - float square_factor = /*2.0 * PI_2 * */2.0 * L.light_col.a; + float square_factor = /*2.0 * PI_2 * *//*2.0 * */L.light_col.a; vec3 color = /*srgb_to_linear*/L.light_col.rgb; // // Only access the array once @@ -199,9 +259,11 @@ float lights_at(vec3 wpos, vec3 wnorm, vec3 /*cam_to_frag*/view_dir, vec3 mu, ve 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; + float computed_shadow = ShadowCalculation(i, -difference, wpos/*, light_distance*/); + // directed_light += /*is_direct ? */max(computed_shadow, /*LIGHT_AMBIENCE*/0.0) * direct_light * square_factor/* : vec3(0.0)*/; + directed_light += is_direct ? mix(/*LIGHT_AMBIENCE*/0.0, 1.0, computed_shadow) * direct_light * square_factor : vec3(0.0); + // ambient_light += is_direct ? vec3(0.0) : vec3(0.0); // direct_light * square_factor * LIGHT_AMBIENCE; + // ambient_light += direct_light * (1.0 - 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; diff --git a/assets/voxygen/shaders/include/sky.glsl b/assets/voxygen/shaders/include/sky.glsl index 276d58ffe1..5559eedf0b 100644 --- a/assets/voxygen/shaders/include/sky.glsl +++ b/assets/voxygen/shaders/include/sky.glsl @@ -513,8 +513,8 @@ vec3 illuminate(float max_light, vec3 view_dir, /*vec3 max_light, */vec3 emitted // vec3 c = sqrt(col_adjusted) * T; // vec3 c = /*col_adjusted * */col_adjusted * T; - return color; - // return c; + // return color; + return c; // float sum_col = color.r + color.g + color.b; // return /*srgb_to_linear*/(/*0.5*//*0.125 * */vec3(pow(color.x, gamma), pow(color.y, gamma), pow(color.z, gamma))); } diff --git a/assets/voxygen/shaders/light-shadows-frag.glsl b/assets/voxygen/shaders/light-shadows-frag.glsl index a9619fc528..e80693442f 100644 --- a/assets/voxygen/shaders/light-shadows-frag.glsl +++ b/assets/voxygen/shaders/light-shadows-frag.glsl @@ -3,6 +3,7 @@ // However, in the future we might apply some depth transforms here. #version 330 core +// #extension ARB_texture_storage : enable #include @@ -25,17 +26,23 @@ // Currently, we only need lights for the light position #include -in vec4 FragPos; // FragPos from GS (output per emitvertex) -flat in int FragLayer; +// in vec3 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); + // Only need to do anything with point lights, since sun and moon should already have nonlinear + // distance. + /*if (FragLayer > 0) */{ + // get distance between fragment and light source + // float lightDistance = length(FragPos - lights[((FragLayer - 1) & 31)].light_pos.xyz); - // map to [0;1] range by dividing by far_plane - lightDistance = lightDistance / /*FragPos.w;*/screen_res.w; + // 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; + // write this as modified depth + // lightDistance = -1000.0 / (lightDistance + 10000.0); + // lightDistance /= screen_res.w; + // gl_FragDepth = lightDistance;// / /*FragPos.w;*/screen_res.w;//-1000.0 / (lightDistance + 1000.0);//lightDistance + } } diff --git a/assets/voxygen/shaders/light-shadows-geom.glsl b/assets/voxygen/shaders/light-shadows-geom.glsl index b1b8d92dfb..5ccd7140db 100644 --- a/assets/voxygen/shaders/light-shadows-geom.glsl +++ b/assets/voxygen/shaders/light-shadows-geom.glsl @@ -2,10 +2,30 @@ // NOTE: We only technically need this for cube map arrays and geometry shader // instancing. -#version 400 core +#version 330 core +// #extension ARB_texture_storage : enable -// Currently, we only need globals for the max light count (light_shadow_count.x). +#include + +#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY + +#if (FLUID_MODE == FLUID_MODE_CHEAP) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE +#elif (FLUID_MODE == FLUID_MODE_SHINY) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE +#endif + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + +// Currently, we only need globals for the max light count (light_shadow_count.x) +// and the far plane (scene_res.z). #include +// Currently, we only need lights for the light position +#include // Since our output primitive is a triangle strip, we have to render three vertices // each. @@ -140,14 +160,14 @@ // 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 +#define MAX_POINT_LIGHTS 31 // 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 (triangles/*, invocations = 6*/) in; layout (triangle_strip, max_vertices = /*MAX_LAYER_VERTICES_PER_FACE*/96) out; @@ -166,33 +186,70 @@ uniform u_light_shadows { // 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 +// out vec3 FragPos; // FragPos from GS (output per emitvertex) +// flat out int FragLayer; // Current layer + +// const 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)); void main() { + // return; // 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; + // int face = gl_InvocationID; - for (int layer = 0; layer < light_shadow_count.x; ++layer) + // Part 1: emit directed lights. + /* if (face <= light_shadow_count.z) { + // Directed light. + 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 = 0; // 0 is the directed light layer. + // vec4 FragPos = gl_in[i].gl_Position; + gl_Layer = i; // built-in variable that specifies to which face we render. + gl_Position = shadowMats[i].shadowMatrices * FragPos; + EmitVertex(); + } + EndPrimitive(); + } */ + + // Part 2: emit point lights. + /* if (light_shadow_count.x == 1) { + return; + } */ + for (int layer = 1; layer <= /*light_shadow_count.x*/1; ++layer) { + int layer_base = layer * FACES_PER_POINT_LIGHT; // 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 face = 0; face < FACES_PER_POINT_LIGHT; ++face) + { + // int layer_face = layer * 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; + vec3 FragPos = gl_in[i].gl_Position.xyz; + // FragPos = gl_in[i].gl_Position.xyz; + // FragLayer = layer; + // float lightDistance = length(FragPos - lights[((layer - 1) & 31)].light_pos.xyz); + // lightDistance /= screen_res.w; + // 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; + // NOTE: Our normals map to the same thing as cube map normals, *except* that their normal direction is + // swapped; we can fix this by doing normal ^ 0x1u. However, we also want to cull back faces, not front + // faces, so we only care about the shadow cast by the *back* of the triangle, which means we ^ 0x1u + // again and cancel it out. + // int face = int(((floatBitsToUint(gl_Position.w) >> 29) & 0x7u) ^ 0x1u); + int layer_face = layer_base + face; + gl_Layer = face;//layer_face; // built-in variable that specifies to which face we render. + gl_Position = shadowMats[layer_face].shadowMatrices * vec4(FragPos, 1.0); + // lightDistance = -(lightDistance + screen_res.z) / (screen_res.w - screen_res.z); + // gl_Position.z = lightDistance; EmitVertex(); } EndPrimitive(); - // } + } } } diff --git a/assets/voxygen/shaders/light-shadows-vert.glsl b/assets/voxygen/shaders/light-shadows-vert.glsl index 5dc64d717e..e7f5e6054b 100644 --- a/assets/voxygen/shaders/light-shadows-vert.glsl +++ b/assets/voxygen/shaders/light-shadows-vert.glsl @@ -1,4 +1,5 @@ #version 330 core +// #extension ARB_texture_storage : enable #include @@ -45,7 +46,7 @@ void main() { // f_pos = v_pos; vec3 f_pos = f_chunk_pos + model_offs; - gl_Position = /*all_mat * */vec4(f_pos, 1.0); + gl_Position = /*all_mat * */vec4(f_pos/*, 1.0*/, /*float(((f_pos_norm >> 29) & 0x7u) ^ 0x1)*/uintBitsToFloat(v_pos_norm)/*1.0*/); // shadowMapCoord = lights[gl_InstanceID].light_pos * gl_Vertex; // vec4(v_pos, 0.0, 1.0); } diff --git a/assets/voxygen/shaders/sprite-frag.glsl b/assets/voxygen/shaders/sprite-frag.glsl index 1eec83683e..4b27cb9c54 100644 --- a/assets/voxygen/shaders/sprite-frag.glsl +++ b/assets/voxygen/shaders/sprite-frag.glsl @@ -1,4 +1,4 @@ -#version 400 core +#version 330 core #include diff --git a/assets/voxygen/shaders/terrain-frag.glsl b/assets/voxygen/shaders/terrain-frag.glsl index d8513874e2..4db0caed30 100644 --- a/assets/voxygen/shaders/terrain-frag.glsl +++ b/assets/voxygen/shaders/terrain-frag.glsl @@ -1,4 +1,5 @@ -#version 400 core +#version 330 core +// #extension GL_ARB_texture_storage : require #include @@ -38,34 +39,50 @@ out vec4 tgt_color; void main() { // tgt_color = vec4(0.0, 0.0, 0.0, 1.0); - // for (uint i = 0u; i < light_shadow_count.x; i ++) { + // float sum = 0.0; + // for (uint i = 0u; i < /* 6 * */light_shadow_count.x; i ++) { // // uint i = 1u; - // Light L = lights[i]; + // Light L = lights[i/* / 6*/]; - // vec4 light_col = vec4( + // /* 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_col = vec3(1.0);//L.light_col.rgb; + // float light_strength = L.light_col.a / 255.0; + // // float light_strength = 1.0 / light_shadow_count.x; // vec3 light_pos = L.light_pos.xyz; // // Pre-calculate difference between light and fragment // vec3 fragToLight = f_pos - light_pos; + // // vec3 f_norm = normals[(f_pos_norm >> 29) & 0x7u]; + // // 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*/); + // float closestDepth = texture(t_shadow_maps, vec4(fragToLight, i + 1)/*, bias*/).r; + // // float visibility = texture(t_shadow_maps, vec4(fragToLight, i + 1), -(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); + // // tgt_color += light_col * vec4(vec3(/*closestDepth*/visibility/* + bias*//* / screen_res.w */) * 1.0 / light_shadow_count.x, 0.0); + // tgt_color.rgb += light_col * vec3(closestDepth + 0.05 / screen_res.w) * 1.0 /*/ light_shadow_count.x*/ * light_strength; + // sum += light_strength; + // } + + // /* if (light_shadow_count.x == 1) { + // tgt_color.rgb = vec3(0.0); + // } */ + // if (sum > 0.0) { + // tgt_color.rgb /= sum; // } // return; diff --git a/voxygen/src/render/pipelines/mod.rs b/voxygen/src/render/pipelines/mod.rs index 214800f2db..15305bbd2e 100644 --- a/voxygen/src/render/pipelines/mod.rs +++ b/voxygen/src/render/pipelines/mod.rs @@ -14,6 +14,10 @@ use common::terrain::BlockKind; use gfx::{self, gfx_constant_struct_meta, gfx_defines, gfx_impl_struct_meta}; use vek::*; +pub const MAX_POINT_LIGHT_COUNT: usize = 32; +pub const MAX_FIGURE_SHADOW_COUNT: usize = 24; +pub const MAX_DIRECTED_LIGHT_COUNT: usize = 6; + gfx_defines! { constant Globals { view_mat: [[f32; 4]; 4] = "view_mat", @@ -37,6 +41,7 @@ gfx_defines! { /// 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", + shadow_proj_factors: [f32; 4] = "shadow_proj_factors", medium: [u32; 4] = "medium", select_pos: [i32; 4] = "select_pos", gamma: [f32; 4] = "gamma", @@ -47,6 +52,7 @@ gfx_defines! { constant Light { pos: [f32; 4] = "light_pos", col: [f32; 4] = "light_col", + // proj: [[f32; 4]; 4] = "light_proj"; } constant Shadow { @@ -70,6 +76,7 @@ impl Globals { shadow_planes: Vec2, light_count: usize, shadow_count: usize, + directed_light_count: usize, medium: BlockKind, select_pos: Option>, gamma: f32, @@ -92,7 +99,18 @@ impl Globals { shadow_planes.x, shadow_planes.y, ], - light_shadow_count: [light_count as u32, shadow_count as u32, 0, 0], + light_shadow_count: [ + (light_count % MAX_POINT_LIGHT_COUNT) as u32, + (shadow_count % MAX_FIGURE_SHADOW_COUNT) as u32, + (directed_light_count % MAX_DIRECTED_LIGHT_COUNT) as u32, + 0, + ], + shadow_proj_factors: [ + (shadow_planes.y + shadow_planes.x) / (shadow_planes.y - shadow_planes.x), + (2.0 * shadow_planes.y * shadow_planes.x) / (shadow_planes.y - shadow_planes.x), + 0.0, + 0.0, + ], medium: [if medium.is_fluid() { 1 } else { 0 }; 4], select_pos: select_pos .map(|sp| Vec4::from(sp) + Vec4::unit_w()) @@ -121,6 +139,7 @@ impl Default for Globals { Vec2::new(1.0, 25.0), 0, 0, + 0, BlockKind::Air, None, 1.0, diff --git a/voxygen/src/render/pipelines/shadow.rs b/voxygen/src/render/pipelines/shadow.rs index 8274b215e8..07ed4ecba7 100644 --- a/voxygen/src/render/pipelines/shadow.rs +++ b/voxygen/src/render/pipelines/shadow.rs @@ -31,7 +31,7 @@ gfx_defines! { // Shadow stuff light_shadows: gfx::ConstantBuffer = "u_light_shadows", - tgt_depth_stencil: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_TEST,//,Stencil::new(Comparison::Always,0xff,(StencilOp::Keep,StencilOp::Keep,StencilOp::Keep))), + tgt_depth_stencil: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE,//,Stencil::new(Comparison::Always,0xff,(StencilOp::Keep,StencilOp::Keep,StencilOp::Keep))), } } diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 70e3b9bc87..1d685cf45f 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -419,7 +419,7 @@ impl Renderer { let depth_stencil_cty = <::Channel as gfx::format::ChannelTyped>::get_channel_type(); let shadow_tex = factory .create_texture( - gfx::texture::Kind::CubeArray(size / 4, 32), + gfx::texture::Kind::/*CubeArray*/Cube(size / 4 /* size * 2*//*, 32 */), 1 as gfx::texture::Level, gfx::memory::Bind::SHADER_RESOURCE | gfx::memory::Bind::DEPTH_STENCIL, gfx::memory::Usage::Data, @@ -436,7 +436,12 @@ impl Renderer { 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::( + &shadow_tex, + 0, + Some(1), + gfx::texture::DepthStencilFlags::empty(), + )?; */ let tgt_shadow_view = factory.view_texture_as_depth_stencil_trivial(&shadow_tex)?; /* let tgt_shadow_res = factory.view_texture_as_shader_resource::( &tgt_color_tex, @@ -454,7 +459,24 @@ impl Renderer { gfx::format::Swizzle::new(), )?; - Ok((tgt_shadow_view, tgt_shadow_res, shadow_tex_sampler)) + /* let tgt_sun_res = factory.view_texture_as_depth_stencil::( + &shadow_tex, + 0, + Some(0), + gfx::texture::DepthStencilFlags::RO_DEPTH, + )?; + let tgt_moon_res = factory.view_texture_as_depth_stencil::( + &shadow_tex, + 0, + Some(1), + gfx::texture::DepthStencilFlags::RO_DEPTH, + )?; */ + + Ok(( + tgt_shadow_view, + tgt_shadow_res, + /* tgt_directed_res, */ shadow_tex_sampler, + )) } /// Get the resolution of the render target. @@ -465,13 +487,23 @@ impl Renderer { ) } + /// Get the resolution of the shadow render target. + pub fn get_shadow_resolution(&self) -> Vec2 { + if let Some(shadow_map) = &self.shadow_map { + let dims = shadow_map.depth_stencil_view.get_dimensions(); + Vec2::new(dims.0, dims.1) + } else { + Vec2::new(1, 1) + } + } + /// 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); + let encoder = &mut shadow_map.encoder; + encoder.clear_depth(&shadow_map.depth_stencil_view, 1.0); + // encoder.clear_stencil(&shadow_map.depth_stencil_view, 0); } self.encoder.clear_depth(&self.tgt_depth_stencil_view, 1.0); self.encoder.clear_stencil(&self.tgt_depth_stencil_view, 0); @@ -481,7 +513,8 @@ impl Renderer { /// 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); + let encoder = &mut shadow_map.encoder; + encoder.flush(&mut self.device); } } @@ -489,7 +522,8 @@ impl Renderer { /// items. pub fn flush(&mut self) { if let Some(shadow_map) = self.shadow_map.as_mut() { - shadow_map.encoder.flush(&mut self.device); + let encoder = &mut shadow_map.encoder; + encoder.flush(&mut self.device); } self.encoder.flush(&mut self.device); self.device.cleanup(); @@ -902,7 +936,8 @@ impl Renderer { } else { return; }; - shadow_map.encoder.draw( + let encoder = &mut shadow_map.encoder; + encoder.draw( &gfx::Slice { start: model.vertex_range().start, end: model.vertex_range().end, @@ -1471,14 +1506,14 @@ fn create_shadow_pipeline( // 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 { + 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), + offset: None,//Some(gfx::state::Offset(4, /*10*/-10)), + samples:None,//Some(gfx::state::MultiSample), }, pipe, )?, diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 442d08acae..33a1e477f0 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -35,6 +35,7 @@ const CURSOR_PAN_SCALE: f32 = 0.005; const MAX_LIGHT_COUNT: usize = 32; const MAX_SHADOW_COUNT: usize = 24; +const NUM_DIRECTED_LIGHTS: usize = 2; const LIGHT_DIST_RADIUS: f32 = 64.0; // The distance beyond which lights may not emit light from their origin const SHADOW_DIST_RADIUS: f32 = 8.0; const SHADOW_MAX_DIST: f32 = 96.0; // The distance beyond which shadows may not be visible @@ -42,8 +43,8 @@ const SHADOW_MAX_DIST: f32 = 96.0; // The distance beyond which shadows may not // 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. +const SHADOW_NEAR: f32 = 1.0; //1.0; //0.5;//1.0; // Near plane for shadow map rendering. +const SHADOW_FAR: f32 = 128.0; //25.0; //100000.0;//25.0; // Far plane for shadow map rendering. /// Above this speed is considered running /// Used for first person camera effects @@ -110,7 +111,7 @@ impl Scene { .create_consts(&[Shadow::default(); MAX_SHADOW_COUNT]) .unwrap(), shadow_mats: renderer - .create_consts(&[ShadowLocals::default(); MAX_LIGHT_COUNT * 6]) + .create_consts(&[ShadowLocals::default(); MAX_LIGHT_COUNT * 6 + 2]) .unwrap(), camera: Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson), camera_input_state: Vec2::zero(), @@ -358,9 +359,36 @@ impl Scene { .expect("Failed to update light constants"); // Update light projection matrices for the shadow map. + let time_of_day = scene_data.state.get_time_of_day(); + let shadow_res = renderer.get_shadow_resolution(); // NOTE: The aspect ratio is currently always 1 for our cube maps, since they // are equal on all sides. - let shadow_aspect = 1.0; + let shadow_aspect = shadow_res.x as f32 / shadow_res.y as f32; + // First, add a projected matrix for our directed hard lights. + let directed_view_proj = Mat4::orthographic_rh_no(FrustumPlanes { + left: -(shadow_res.x as f32) / 2.0, + right: shadow_res.x as f32 / 2.0, + bottom: -(shadow_res.y as f32) / 2.0, + top: shadow_res.y as f32 / 2.0, + near: SHADOW_NEAR, + far: SHADOW_FAR, + }); + // Construct matrices to transform from world space to light space for the sun + // and moon. + const TIME_FACTOR: f32 = (std::f32::consts::PI * 2.0) / (3600.0 * 24.0); + let angle_rad = time_of_day as f32 * TIME_FACTOR; + let sun_dir = Vec3::new(angle_rad.sin(), 0.0, angle_rad.cos()); + let moon_dir = Vec3::new(-angle_rad.sin(), 0.0, angle_rad.cos() - 0.5); + let sun_view_mat = Mat4::model_look_at_rh(-sun_dir, Vec3::zero(), Vec3::up()); + let moon_view_mat = Mat4::model_look_at_rh(-moon_dir, Vec3::zero(), Vec3::up()); + // Now, construct the full projection matrices in the first two directed light + // slots. + let mut shadow_mats = Vec::with_capacity(6 * (lights.len() + 1)); + shadow_mats.push(ShadowLocals::new(directed_view_proj * sun_view_mat)); + shadow_mats.push(ShadowLocals::new(directed_view_proj * moon_view_mat)); + // This leaves us with four dummy slots, which we push as defaults. + shadow_mats.extend_from_slice(&[ShadowLocals::default(); 6 - NUM_DIRECTED_LIGHTS] as _); + // Now, we tackle point lights. // First, create a perspective projection matrix at 90 degrees (to cover a whole // face of the cube map we're using). let shadow_proj = @@ -376,18 +404,22 @@ impl Scene { (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)) - }) + // lights, but then we'd have to sort them both, which wastes time. Plus, we + // want to prepend our directed lights. + shadow_mats.extend(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::>(); + })); + /* shadow_mats.push( + Mat4::orthographic_rh_no + float near_plane = 1.0f, far_plane = 7.5f; + glm::mat4 lightProjection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane); + + ); */ renderer .update_consts(&mut self.shadow_mats, &shadow_mats) .expect("Failed to update light constants"); @@ -402,12 +434,13 @@ impl Scene { self.loaded_distance, self.lod.get_data().tgt_detail as f32, self.map_bounds, - scene_data.state.get_time_of_day(), + time_of_day, scene_data.state.get_time(), renderer.get_resolution(), Vec2::new(SHADOW_NEAR, SHADOW_FAR), lights.len(), shadows.len(), + NUM_DIRECTED_LIGHTS, scene_data .state .terrain() @@ -422,8 +455,7 @@ impl Scene { .expect("Failed to update global constants"); // Maintain LoD. - self.lod - .maintain(renderer, scene_data.state.get_time_of_day()); + self.lod.maintain(renderer, time_of_day); // Maintain the terrain. self.terrain.maintain( diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index df106582f3..5e62e6f2f7 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -223,6 +223,7 @@ impl Scene { Vec2::new(SHADOW_NEAR, SHADOW_FAR), 0, 0, + 0, BlockKind::Air, None, scene_data.gamma,