From 560501df05ca725409b0f2e4eb31bdfdc15fd0c7 Mon Sep 17 00:00:00 2001 From: Joshua Yanovski Date: Tue, 19 May 2020 17:22:06 +0200 Subject: [PATCH] Greedy messhing for shadows. --- assets/voxygen/shaders/figure-vert.glsl | 1 + assets/voxygen/shaders/fluid-vert.glsl | 1 + assets/voxygen/shaders/include/light.glsl | 71 +++--- .../voxygen/shaders/light-shadows-frag.glsl | 14 +- .../voxygen/shaders/light-shadows-geom.glsl | 6 +- .../voxygen/shaders/light-shadows-vert.glsl | 10 +- assets/voxygen/shaders/lod-terrain-frag.glsl | 8 +- assets/voxygen/shaders/lod-terrain-vert.glsl | 1 + assets/voxygen/shaders/sprite-vert.glsl | 2 + assets/voxygen/shaders/terrain-frag.glsl | 19 +- assets/voxygen/shaders/terrain-vert.glsl | 2 + voxygen/src/mesh/mod.rs | 9 +- voxygen/src/mesh/segment.rs | 22 +- voxygen/src/mesh/terrain.rs | 237 +++++++++++++++++- voxygen/src/render/pipelines/shadow.rs | 42 +++- voxygen/src/render/renderer.rs | 38 +-- voxygen/src/scene/mod.rs | 4 +- voxygen/src/scene/terrain.rs | 31 ++- 18 files changed, 435 insertions(+), 83 deletions(-) diff --git a/assets/voxygen/shaders/figure-vert.glsl b/assets/voxygen/shaders/figure-vert.glsl index 34e5baae57..db433b0748 100644 --- a/assets/voxygen/shaders/figure-vert.glsl +++ b/assets/voxygen/shaders/figure-vert.glsl @@ -76,6 +76,7 @@ void main() { // f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy)); gl_Position = all_mat * vec4(f_pos, 1); + // gl_Position.z = -gl_Position.z / gl_Position.w; // gl_Position.z = -gl_Position.z / 100.0; gl_Position.z = -1000.0 / (gl_Position.z + 10000.0); } diff --git a/assets/voxygen/shaders/fluid-vert.glsl b/assets/voxygen/shaders/fluid-vert.glsl index 9800f3e147..0f6c9f7c31 100644 --- a/assets/voxygen/shaders/fluid-vert.glsl +++ b/assets/voxygen/shaders/fluid-vert.glsl @@ -62,6 +62,7 @@ void main() { gl_Position = all_mat * vec4(f_pos, 1); + // gl_Position.z = -gl_Position.z / gl_Position.w; // gl_Position.z = -gl_Position.z / 100.0; gl_Position.z = -1000.0 / (gl_Position.z + 10000.0); } diff --git a/assets/voxygen/shaders/include/light.glsl b/assets/voxygen/shaders/include/light.glsl index 43b1d7dc89..8e10deaa0a 100644 --- a/assets/voxygen/shaders/include/light.glsl +++ b/assets/voxygen/shaders/include/light.glsl @@ -32,10 +32,13 @@ float attenuation_strength(vec3 rpos) { uniform samplerCubeShadow t_shadow_maps; // uniform samplerCube t_shadow_maps; +// uniform sampler2DArray t_directed_shadow_maps; + float VectorToDepth (vec3 Vec) { vec3 AbsVec = abs(Vec); float LocalZcomp = max(AbsVec.x, max(AbsVec.y, AbsVec.z)); + // float LocalZcomp = length(Vec); // Replace f and n with the far and near plane values you used when // you drew your cube map. @@ -43,8 +46,15 @@ float VectorToDepth (vec3 Vec) // 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 = 1.0 - shadow_proj_factors.y / shadow_proj_factors.x / LocalZcomp; float NormZComp = shadow_proj_factors.x - shadow_proj_factors.y / LocalZcomp; + // NormZComp = -1000.0 / (NormZComp + 10000.0); return (NormZComp + 1.0) * 0.5; + + // float NormZComp = length(LocalZcomp); + // NormZComp = -NormZComp / screen_res.w; + // // return (NormZComp + 1.0) * 0.5; + // return NormZComp; } const vec3 sampleOffsetDirections[20] = vec3[] @@ -59,27 +69,34 @@ const vec3 sampleOffsetDirections[20] = vec3[] 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; + if (lightIndex != 0u) { + return 1.0; + }; + + float shadow = 0.0; + float bias = -0.015;//-0.05;//-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); + float viewDistance = length(cam_pos.xyz - fragPos); + // float diskRadius = 0.00001; + // float diskRadius = 1.0; + // float diskRadius = 0.05; + float diskRadius = (1.0 + (/*viewDistance*/viewDistance / screen_res.w)) / 25.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)/*, -2.5*/); + shadow += visibility; + // float closestDepth = texture(t_shadow_maps, vec3(fragToLight)/*, -2.5*/).r; + // shadow += closestDepth > currentDepth ? 1.0 : 0.0; + } + 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*/0.01;//0.05;// 0.05; @@ -95,15 +112,11 @@ float ShadowCalculation(uint lightIndex, vec3 fragToLight, /*float currentDepth* // currentDepth += bias; // currentDepth = -1000.0 / (currentDepth + 10000.0); // currentDepth /= screen_res.w; - float currentDepth = VectorToDepth(fragToLight) + bias; - if (lightIndex != 0u) { - return 1.0; - }; + // float currentDepth = VectorToDepth(fragToLight) + bias; - 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; + // float visibility = texture(t_shadow_maps, vec4(fragToLight, 0.0), 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*/vec3 fragPos) @@ -284,7 +297,7 @@ float lights_at(vec3 wpos, vec3 wnorm, vec3 /*cam_to_frag*/view_dir, vec3 mu, ve // 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*/computed_shadow * 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. diff --git a/assets/voxygen/shaders/light-shadows-frag.glsl b/assets/voxygen/shaders/light-shadows-frag.glsl index e80693442f..1c954f97a6 100644 --- a/assets/voxygen/shaders/light-shadows-frag.glsl +++ b/assets/voxygen/shaders/light-shadows-frag.glsl @@ -26,7 +26,7 @@ // Currently, we only need lights for the light position #include -// in vec3 FragPos; // FragPos from GS (output per emitvertex) +in vec3 FragPos; // FragPos from GS (output per emitvertex) // flat in int FragLayer; void main() @@ -35,14 +35,14 @@ void main() // distance. /*if (FragLayer > 0) */{ // get distance between fragment and light source - // float lightDistance = length(FragPos - lights[((FragLayer - 1) & 31)].light_pos.xyz); + // float lightDistance = length(FragPos - lights[((/*FragLayer*/1 - 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 / screen_res.w;//FragPos.w;//screen_res.w; - // write this as modified depth - // lightDistance = -1000.0 / (lightDistance + 10000.0); - // lightDistance /= screen_res.w; + // // 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 5ccd7140db..8d18e190a9 100644 --- a/assets/voxygen/shaders/light-shadows-geom.glsl +++ b/assets/voxygen/shaders/light-shadows-geom.glsl @@ -169,7 +169,7 @@ layout (triangles/*, invocations = 6*/) in; -layout (triangle_strip, max_vertices = /*MAX_LAYER_VERTICES_PER_FACE*/96) out; +layout (triangle_strip, max_vertices = /*MAX_LAYER_VERTICES_PER_FACE*//*96*/18) out; struct ShadowLocals { mat4 shadowMatrices; @@ -245,6 +245,10 @@ void main() { 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); + // gl_Position.z = -((gl_Position.z + screen_res.z) / (screen_res.w - screen_res.z)) * lightDistance; + // gl_Position.z = gl_Position.z / screen_res.w; + // gl_Position.z = gl_Position.z / gl_Position.w; + // gl_Position.z = -1000.0 / (gl_Position.z + 10000.0); // lightDistance = -(lightDistance + screen_res.z) / (screen_res.w - screen_res.z); // gl_Position.z = lightDistance; EmitVertex(); diff --git a/assets/voxygen/shaders/light-shadows-vert.glsl b/assets/voxygen/shaders/light-shadows-vert.glsl index e7f5e6054b..5e2bc31004 100644 --- a/assets/voxygen/shaders/light-shadows-vert.glsl +++ b/assets/voxygen/shaders/light-shadows-vert.glsl @@ -27,7 +27,8 @@ * */ in uint v_pos_norm; -in uint v_col_light; +// in uint v_col_light; +// in vec4 v_pos; // Light projection matrices. layout (std140) @@ -42,11 +43,12 @@ 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; + // f_pos = v_pos; + // vec3 f_pos = f_chunk_pos + model_offs; - gl_Position = /*all_mat * */vec4(f_pos/*, 1.0*/, /*float(((f_pos_norm >> 29) & 0x7u) ^ 0x1)*/uintBitsToFloat(v_pos_norm)/*1.0*/); + // gl_Position = v_pos + vec4(model_offs, 0.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/lod-terrain-frag.glsl b/assets/voxygen/shaders/lod-terrain-frag.glsl index fee0977e85..40602613cd 100644 --- a/assets/voxygen/shaders/lod-terrain-frag.glsl +++ b/assets/voxygen/shaders/lod-terrain-frag.glsl @@ -298,9 +298,13 @@ void main() { // 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; + + // vec3 ao_pos2 = min(fract(f_pos), 1.0 - fract(f_pos)); + // f_ao = sqrt(dot(ao_pos2, ao_pos2)); + // // 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. // Idea: the closer we are to facing top-down, the more the norm should tend towards up-z. diff --git a/assets/voxygen/shaders/lod-terrain-vert.glsl b/assets/voxygen/shaders/lod-terrain-vert.glsl index 9b62d6e490..80ecefa48c 100644 --- a/assets/voxygen/shaders/lod-terrain-vert.glsl +++ b/assets/voxygen/shaders/lod-terrain-vert.glsl @@ -95,6 +95,7 @@ void main() { proj_mat * view_mat * vec4(f_pos/*newRay*/, 1); + // gl_Position.z = -gl_Position.z / gl_Position.w; // gl_Position.z = -gl_Position.z / 100.0; gl_Position.z = -1000.0 / (gl_Position.z + 10000.0); } diff --git a/assets/voxygen/shaders/sprite-vert.glsl b/assets/voxygen/shaders/sprite-vert.glsl index 6581fe4811..c6a14126a8 100644 --- a/assets/voxygen/shaders/sprite-vert.glsl +++ b/assets/voxygen/shaders/sprite-vert.glsl @@ -70,6 +70,8 @@ void main() { gl_Position = all_mat * vec4(f_pos, 1); + // gl_Position.z = -gl_Position.z / gl_Position.w; + // gl_Position.z = -gl_Position.z / 100.0; // gl_Position.z = -gl_Position.z / 100.0; gl_Position.z = -1000.0 / (gl_Position.z + 10000.0); } diff --git a/assets/voxygen/shaders/terrain-frag.glsl b/assets/voxygen/shaders/terrain-frag.glsl index 4db0caed30..6d04158ced 100644 --- a/assets/voxygen/shaders/terrain-frag.glsl +++ b/assets/voxygen/shaders/terrain-frag.glsl @@ -38,6 +38,15 @@ out vec4 tgt_color; #include void main() { + // vec4 light_col = vec4( + // hash(floor(vec4(f_pos.x, 0, 0, 0))), + // hash(floor(vec4(0, f_pos.y, 0, 1))), + // hash(floor(vec4(0, 0, f_pos.z, 2))), + // 1.0 + // ); + // vec3 f_col = light_col.rgb;//vec4(1.0, 0.0, 0.0, 1.0); + // tgt_color = vec4(f_col, 1.0); + // return; // tgt_color = vec4(0.0, 0.0, 0.0, 1.0); // float sum = 0.0; // for (uint i = 0u; i < /* 6 * */light_shadow_count.x; i ++) { @@ -62,10 +71,13 @@ void main() { // // 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 bias = 0.0;//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 closestDepth = texture(t_shadow_maps, vec4(fragToLight, i + 1)/*, bias*/).r; + // // float closestDepth = texture(t_shadow_maps, vec4(fragToLight, i + 1)/*, bias*/).r; + // float currentDepth = VectorToDepth(fragToLight) + bias; + // float closestDepth = texture(t_shadow_maps, vec3(fragToLight)/*, -2.5*/).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 @@ -74,7 +86,8 @@ void main() { // // 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.rgb += light_col * vec3(closestDepth + 0.05 / screen_res.w) * 1.0 /*/ light_shadow_count.x*/ * light_strength; + // // tgt_color.rgb += light_col * vec3(closestDepth + 0.05 / screen_res.w) * 1.0 /*/ light_shadow_count.x*/ * light_strength; + // tgt_color.rgb += light_col * vec3(closestDepth) * 1.0 / screen_res.w /*/ light_shadow_count.x*/ * light_strength; // sum += light_strength; // } diff --git a/assets/voxygen/shaders/terrain-vert.glsl b/assets/voxygen/shaders/terrain-vert.glsl index 8f44fa7492..abe04eff1d 100644 --- a/assets/voxygen/shaders/terrain-vert.glsl +++ b/assets/voxygen/shaders/terrain-vert.glsl @@ -99,6 +99,8 @@ void main() { gl_Position = all_mat * vec4(f_pos/*newRay*/, 1); + // gl_Position.z = -gl_Position.z / gl_Position.w; + // gl_Position.z = -gl_Position.z / 100.0; // gl_Position.z = -gl_Position.z / 100.0; gl_Position.z = -1000.0 / (gl_Position.z + 10000.0); } diff --git a/voxygen/src/mesh/mod.rs b/voxygen/src/mesh/mod.rs index 695c1e617b..4dc067ab1c 100644 --- a/voxygen/src/mesh/mod.rs +++ b/voxygen/src/mesh/mod.rs @@ -7,11 +7,16 @@ use crate::render::{self, Mesh}; pub trait Meshable<'a, P: render::Pipeline, T: render::Pipeline> { type Pipeline: render::Pipeline; type TranslucentPipeline: render::Pipeline; + type ShadowPipeline: render::Pipeline; type Supplement; - // Generate meshes - one opaque, one translucent + // Generate meshes - one opaque, one translucent, one shadow fn generate_mesh( &'a self, supp: Self::Supplement, - ) -> (Mesh, Mesh); + ) -> ( + Mesh, + Mesh, + Mesh, + ); } diff --git a/voxygen/src/mesh/segment.rs b/voxygen/src/mesh/segment.rs index dcc27bacf2..4e55f49430 100644 --- a/voxygen/src/mesh/segment.rs +++ b/voxygen/src/mesh/segment.rs @@ -20,13 +20,20 @@ where * &'a V: BaseVol, */ { type Pipeline = FigurePipeline; + type ShadowPipeline = FigurePipeline; type Supplement = (Vec3, Vec3); type TranslucentPipeline = FigurePipeline; + // TODO: Make sprites cast shadows? + fn generate_mesh( &'a self, (offs, scale): Self::Supplement, - ) -> (Mesh, Mesh) { + ) -> ( + Mesh, + Mesh, + Mesh, + ) { let mut mesh = Mesh::new(); let vol_iter = (self.lower_bound().x..self.upper_bound().x) @@ -74,7 +81,7 @@ where } } - (mesh, Mesh::new()) + (mesh, Mesh::new(), Mesh::new()) } } @@ -86,13 +93,20 @@ where * &'a V: BaseVol, */ { type Pipeline = SpritePipeline; + type ShadowPipeline = SpritePipeline; type Supplement = (Vec3, Vec3); type TranslucentPipeline = SpritePipeline; + // TODO: Make sprites cast shadows? + fn generate_mesh( &'a self, (offs, scale): Self::Supplement, - ) -> (Mesh, Mesh) { + ) -> ( + Mesh, + Mesh, + Mesh, + ) { let mut mesh = Mesh::new(); let vol_iter = (self.lower_bound().x..self.upper_bound().x) @@ -139,7 +153,7 @@ where } } - (mesh, Mesh::new()) + (mesh, Mesh::new(), Mesh::new()) } } diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index 654800604d..71dde406ab 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -1,6 +1,6 @@ use crate::{ mesh::{vol, Meshable}, - render::{self, FluidPipeline, Mesh, TerrainPipeline}, + render::{self, mesh::Quad, FluidPipeline, Mesh, ShadowPipeline, TerrainPipeline}, }; use common::{ terrain::{Block, BlockKind}, @@ -12,6 +12,7 @@ use vek::*; type TerrainVertex = ::Vertex; type FluidVertex = ::Vertex; +type ShadowVertex = ::Vertex; trait Blendable { fn is_blended(&self) -> bool; @@ -202,13 +203,18 @@ impl<'a, V: RectRasterableVol + ReadVol + Debug> Meshable<'a, TerrainPipeline, FluidPipeline> for VolGrid2d { type Pipeline = TerrainPipeline; + type ShadowPipeline = ShadowPipeline; type Supplement = Aabb; type TranslucentPipeline = FluidPipeline; fn generate_mesh( &'a self, range: Self::Supplement, - ) -> (Mesh, Mesh) { + ) -> ( + Mesh, + Mesh, + Mesh, + ) { let mut light = calc_light(range, self); let mut lowest_opaque = range.size().d; @@ -463,7 +469,84 @@ impl<'a, V: RectRasterableVol + ReadVol + Debug> // opaque_mesh // }); - (opaque_mesh, fluid_mesh) + let mut shadow_mesh = Mesh::new(); + + let x_size = (range.size().w - 2) as usize; + let y_size = (range.size().h - 2) as usize; + let z_size = (z_end - z_start + 1) as usize; + let draw_delta = Vec3::new(1, 1, z_start); + let mesh_delta = Vec3::new(0, 0, z_start + range.min.z); + + // x (u = y, v = z) + greedy_mesh_cross_section( + Vec3::new(y_size, z_size, x_size), + |pos| { + should_draw_greedy( + Vec3::new(pos.z, pos.x, pos.y), + draw_delta, + Vec3::unit_x(), /* , pos.z, 0, x_size */ + |pos| flat_get(pos), + ) + }, + |pos, dim, faces_forward| { + shadow_mesh.push_quad(create_quad_greedy( + Vec3::new(pos.z, pos.x, pos.y), + mesh_delta, + dim, + Vec2::new(Vec3::unit_y(), Vec3::unit_z()), + Vec3::unit_x(), + faces_forward, + )); + }, + ); + + // y (u = z, v = x) + greedy_mesh_cross_section( + Vec3::new(z_size, x_size, y_size), + |pos| { + should_draw_greedy( + Vec3::new(pos.y, pos.z, pos.x), + draw_delta, + Vec3::unit_y(), /* , pos.z, 0, y_size */ + |pos| flat_get(pos), + ) + }, + |pos, dim, faces_forward| { + shadow_mesh.push_quad(create_quad_greedy( + Vec3::new(pos.y, pos.z, pos.x), + mesh_delta, + dim, + Vec2::new(Vec3::unit_z(), Vec3::unit_x()), + Vec3::unit_y(), + faces_forward, + )); + }, + ); + + // z (u = x, v = y) + greedy_mesh_cross_section( + Vec3::new(x_size, y_size, z_size), + |pos| { + should_draw_greedy( + Vec3::new(pos.x, pos.y, pos.z), + draw_delta, + Vec3::unit_z(), /* , pos.z, 0, z_size */ + |pos| flat_get(pos), + ) + }, + |pos, dim, faces_forward| { + shadow_mesh.push_quad(create_quad_greedy( + Vec3::new(pos.x, pos.y, pos.z), + mesh_delta, + dim, + Vec2::new(Vec3::unit_x(), Vec3::unit_y()), + Vec3::unit_z(), + faces_forward, + )); + }, + ); + + (opaque_mesh, fluid_mesh, shadow_mesh) } } @@ -493,6 +576,154 @@ fn faces_to_make( ] } +// Greedy meshing. +fn greedy_mesh_cross_section( + /* mask: &mut [bool], */ + dims: Vec3, + // Should we draw a face here (below this vertex)? If so, is it front or back facing? + draw_face: impl Fn(Vec3) -> Option, + // Vertex, width and height, and whether it's front facing (face is implicit from the cross + // section). + mut push_quads: impl FnMut(Vec3, Vec2, bool), +) { + // mask represents which faces are either set while the other is unset, or unset + // while the other is set. + let mut mask = vec![None; dims.y * dims.x]; + (0..dims.z + 1).for_each(|d| { + // Compute mask + mask.iter_mut().enumerate().for_each(|(posi, mask)| { + let i = posi % dims.x; + let j = posi / dims.x; + *mask = draw_face(Vec3::new(i, j, d)); + }); + + (0..dims.y).for_each(|j| { + let mut i = 0; + while i < dims.x { + // Compute width (number of set x bits for this row and layer, starting at the + // current minimum column). + if let Some(ori) = mask[j * dims.x + i] { + let width = 1 + mask[j * dims.x + i + 1..j * dims.x + dims.x] + .iter() + .take_while(move |&&mask| mask == Some(ori)) + .count(); + let max_x = i + width; + // Compute height (number of rows having w set x bits for this layer, starting + // at the current minimum column and row). + let height = 1 + + (j + 1..dims.y) + .take_while(|h| { + mask[h * dims.x + i..h * dims.x + max_x] + .iter() + .all(|&mask| mask == Some(ori)) + }) + .count(); + let max_y = j + height; + // Add quad. + push_quads(Vec3::new(i, j, d /* + 1 */), Vec2::new(width, height), ori); + // Unset mask bits in drawn region, so we don't try to re-draw them. + (j..max_y).for_each(|l| { + mask[l * dims.x + i..l * dims.x + max_x] + .iter_mut() + .for_each(|mask| { + *mask = None; + }); + }); + // Update x value. + i = max_x; + } else { + i += 1; + } + } + }); + }); +} + +fn create_quad_greedy( + origin: Vec3, + mesh_delta: Vec3, + dim: Vec2, + uv: Vec2>, + norm: Vec3, + faces_forward: bool, +) -> Quad { + let origin = origin.map(|e| e as i32) + mesh_delta; + // let origin = (uv.x * origin.x + uv.y * origin.y + norm * origin.z) + + // Vec3::new(0, 0, z_start + range.min.z - 1);//Vec3::new(-1, -1, z_start + + // range.min.z - 1); + let origin = origin.map(|e| e as f32); // + orientation.z; + // let origin = uv.x * origin.x + uv.y * origin.y + norm * origin.z + + // Vec3::new(0.0, 0.0, (z_start + range.min.z - 1) as f32); + /* if (origin.x < 0.0 || origin.y < 0.0) { + return; + } */ + // let ori = if faces_forward { Vec3::new(u, v, norm) } else { Vec3::new(uv.y, + // uv.x, -norm) }; + let dim = uv.map2(dim.map(|e| e as f32), |e, f| e * f); + let (dim, norm) = if faces_forward { + (dim, norm) + } else { + (Vec2::new(dim.y, dim.x), -norm) + }; + // let (uv, norm, origin) = if faces_forward { (uv, norm, origin) } else { + // (Vec2::new(uv.y, uv.x), -norm, origin) }; let (uv, norm, origin) = if + // faces_forward { (uv, norm, origin) } else { (Vec2::new(uv.y, uv.x), -norm, + // origin/* - norm*/) }; let origin = Vec3::new(origin.x as f32., origin.y + // as f32, (origin.z + z_start) as f32); let norm = norm.map(|e| e as f32); + Quad::new( + ShadowVertex::new(origin, norm), + ShadowVertex::new(origin + dim.x, norm), + ShadowVertex::new(origin + dim.x + dim.y, norm), + ShadowVertex::new(origin + dim.y, norm), + ) +} + +fn should_draw_greedy( + pos: Vec3, + draw_delta: Vec3, + delta: Vec3, + /* depth, min_depth, max_depth, */ flat_get: impl Fn(Vec3) -> Block, +) -> Option { + let pos = pos.map(|e| e as i32) + draw_delta; // - delta; + // + /* if (depth as isize) <= min_depth { + // let to = flat_get(pos).is_opaque(); + debug_assert!(depth <= max_depth); + /* if depth >= max_depth - 1 { + let from = flat_get(pos - delta).is_opaque(); + } else { + None + } */ + if flat_get(pos + delta).is_opaque() { + Some(true) + } else { + None + } + } else */ + { + let from = flat_get(pos - delta).is_opaque(); // map(|v| v.is_opaque()).unwrap_or(false); + // + /* if depth > max_depth { + if from { + // Backward-facing + Some(false) + } else { + None + } + } else */ + { + let to = flat_get(pos).is_opaque(); //map(|v| v.is_opaque()).unwrap_or(false); + if from == to { + None + } else { + // If going from transparent to opaque, forward facing; otherwise, backward + // facing. + Some(from) + } + } + } +} + /* impl + ReadVol + Debug> Meshable for VolGrid3d { type Pipeline = TerrainPipeline; diff --git a/voxygen/src/render/pipelines/shadow.rs b/voxygen/src/render/pipelines/shadow.rs index 07ed4ecba7..0f8d23e4b4 100644 --- a/voxygen/src/render/pipelines/shadow.rs +++ b/voxygen/src/render/pipelines/shadow.rs @@ -1,15 +1,20 @@ 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, + gfx_pipeline_inner, gfx_vertex_struct_meta, }; use vek::*; gfx_defines! { + vertex Vertex { + // pos: [f32; 4] = "v_pos", + pos_norm: u32 = "v_pos_norm", + // col_light: u32 = "v_col_light", + } + constant Locals { shadow_matrices: [[f32; 4]; 4] = "shadowMatrices", } @@ -35,6 +40,39 @@ gfx_defines! { } } +impl Vertex { + pub fn new(pos: Vec3, norm: Vec3) -> Self { + let norm_bits = if norm.x != 0.0 { + if norm.x < 0.0 { 0 } else { 1 } + } else if norm.y != 0.0 { + if norm.y < 0.0 { 2 } else { 3 } + } else { + if norm.z < 0.0 { 4 } else { 5 } + }; + // let ao = 0xFFu32; + // let light = 0xFFu32; + // let col = Rgb::new(1.0f32, 0.0, 0.0); + let meta = true; + + const EXTRA_NEG_Z: f32 = 32768.0; + + Self { + pos_norm: 0 + | ((pos.x as u32) & 0x003F) << 0 + | ((pos.y as u32) & 0x003F) << 6 + | (((pos + EXTRA_NEG_Z).z.max(0.0).min((1 << 16) as f32) as u32) & 0xFFFF) << 12 + | if meta { 1 } else { 0 } << 28 + | (norm_bits & 0x7) << 29, + /* col_light: 0 + | (((col.r * 255.0) as u32) & 0xFF) << 8 + | (((col.g * 255.0) as u32) & 0xFF) << 16 + | (((col.b * 255.0) as u32) & 0xFF) << 24 + | (ao >> 6) << 6 + | ((light >> 2) & 0x3F) << 0, */ + } + } +} + impl Locals { pub fn new(shadow_mat: Mat4) -> Self { Self { diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 1d685cf45f..eee5335b5d 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -388,7 +388,7 @@ impl Renderer { ), RenderError, > { - let levels = 1; + let levels = 1; //10; /* let color_cty = <::Channel as gfx::format::ChannelTyped >::get_channel_type(); @@ -420,7 +420,7 @@ impl Renderer { let shadow_tex = factory .create_texture( gfx::texture::Kind::/*CubeArray*/Cube(size / 4 /* size * 2*//*, 32 */), - 1 as gfx::texture::Level, + levels as gfx::texture::Level, gfx::memory::Bind::SHADER_RESOURCE | gfx::memory::Bind::DEPTH_STENCIL, gfx::memory::Usage::Data, Some(depth_stencil_cty), @@ -431,18 +431,21 @@ impl Renderer { let mut sampler_info = gfx::texture::SamplerInfo::new( gfx::texture::FilterMethod::Bilinear, - gfx::texture::WrapMode::Border, + gfx::texture::WrapMode::Clamp, //Border, ); - sampler_info.comparison = Some(Comparison::LessEqual); + sampler_info.comparison = Some(Comparison::Less); + // sampler_info.lod_bias = (-3.0).into(); + // sampler_info.lod_range = (1.into(), (levels - 1).into()); 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::( + let tgt_shadow_view = factory.view_texture_as_depth_stencil::( &shadow_tex, - 0, - Some(1), + 0, // levels, + None, // Some(1), gfx::texture::DepthStencilFlags::empty(), - )?; */ - let tgt_shadow_view = factory.view_texture_as_depth_stencil_trivial(&shadow_tex)?; + )?; + // let tgt_shadow_view = + // factory.view_texture_as_depth_stencil_trivial(&shadow_tex)?; /* let tgt_shadow_res = factory.view_texture_as_shader_resource::( &tgt_color_tex, (0, levels - 1), @@ -879,6 +882,7 @@ impl Renderer { /// frame. pub fn render_terrain_chunk( &mut self, + // model: &Model, model: &Model, globals: &Consts, locals: &Consts, @@ -921,7 +925,7 @@ impl Renderer { /// Queue the rendering of the player silhouette in the upcoming frame. pub fn render_shadow( &mut self, - model: &Model, + model: &Model, globals: &Consts, terrain_locals: &Consts, locals: &Consts, @@ -1506,14 +1510,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: /*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, - }, + 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: None,//Some(gfx::state::Offset(4, /*10*/-10)), - samples:None,//Some(gfx::state::MultiSample), + offset: None, //Some(gfx::state::Offset(2, 10)), + samples: None, // Some(gfx::state::MultiSample), }, pipe, )?, diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 33a1e477f0..0b82822be0 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -43,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 = 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. +const SHADOW_NEAR: f32 = 0.25; //1.0; //0.5;//1.0; // Near plane for shadow map rendering. +const SHADOW_FAR: f32 = 128.0; //100000.0;//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 diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 0b4c092d16..4bec55d70d 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -2,7 +2,8 @@ use crate::{ mesh::Meshable, render::{ Consts, FluidPipeline, Globals, Instances, Light, Mesh, Model, Renderer, Shadow, - ShadowLocals, SpriteInstance, SpritePipeline, TerrainLocals, TerrainPipeline, Texture, + ShadowLocals, ShadowPipeline, SpriteInstance, SpritePipeline, TerrainLocals, + TerrainPipeline, Texture, }, }; @@ -27,10 +28,12 @@ struct TerrainChunkData { load_time: f32, opaque_model: Model, fluid_model: Option>, + shadow_model: Model, sprite_instances: HashMap<(BlockKind, usize), Instances>, locals: Consts, visible: bool, + can_shadow: bool, z_bounds: (f32, f32), frustum_last_plane_index: u8, } @@ -48,6 +51,7 @@ struct MeshWorkerResponse { z_bounds: (f32, f32), opaque_mesh: Mesh, fluid_mesh: Mesh, + shadow_mesh: Mesh, sprite_instances: HashMap<(BlockKind, usize), Vec>, started_tick: u64, } @@ -254,12 +258,13 @@ fn mesh_worker + RectRasterableVol + ReadVol + Debug>( volume: as SampleVol>>::Sample, range: Aabb, ) -> MeshWorkerResponse { - let (opaque_mesh, fluid_mesh) = volume.generate_mesh(range); + let (opaque_mesh, fluid_mesh, shadow_mesh) = volume.generate_mesh(range); MeshWorkerResponse { pos, z_bounds, opaque_mesh, fluid_mesh, + shadow_mesh, // Extract sprite locations from volume sprite_instances: { let mut instances = HashMap::new(); @@ -2106,6 +2111,9 @@ impl Terrain { } else { None }, + shadow_model: renderer + .create_model(&response.shadow_mesh) + .expect("Failed to upload chunk mesh to the GPU!"), sprite_instances: response .sprite_instances .into_iter() @@ -2130,6 +2138,7 @@ impl Terrain { }]) .expect("Failed to upload chunk locals to the GPU!"), visible: false, + can_shadow: false, z_bounds: response.z_bounds, frustum_last_plane_index: 0, }); @@ -2155,8 +2164,8 @@ impl Terrain { // Limit focus_pos to chunk bounds and ensure the chunk is within the fog // boundary let nearest_in_chunk = Vec2::from(focus_pos).clamped(chunk_pos, chunk_pos + chunk_sz); - let in_range = Vec2::::from(focus_pos).distance_squared(nearest_in_chunk) - < loaded_distance.powf(2.0); + let distance_2 = Vec2::::from(focus_pos).distance_squared(nearest_in_chunk); + let in_range = distance_2 < loaded_distance.powf(2.0); if !in_range { chunk.visible = in_range; @@ -2176,6 +2185,9 @@ impl Terrain { chunk.frustum_last_plane_index = last_plane_index; chunk.visible = in_frustum; + // FIXME: Hack that only works when only the lantern casts point shadows + // (and hardcodes the shadow distance). Should ideally exist per-light, too. + chunk.can_shadow = distance_2 < (128.0 * 128.0); } } @@ -2207,11 +2219,12 @@ impl Terrain { .take(self.chunks.len()); // Shadows + // let mut shadow_vertex_count = 0; for (_, chunk) in chunk_iter.clone() { - /* if chunk.visible */ - { + if chunk.can_shadow { + // shadow_vertex_count += chunk.shadow_model.vertex_range.len(); renderer.render_shadow( - &chunk.opaque_model, + &chunk.shadow_model, globals, &chunk.locals, shadow_mats, @@ -2227,10 +2240,13 @@ impl Terrain { renderer.flush_shadows(); // Terrain + // let mut terrain_vertex_count = 0; for (_, chunk) in chunk_iter { + // terrain_vertex_count += chunk.opaque_model.vertex_range.len(); if chunk.visible { renderer.render_terrain_chunk( &chunk.opaque_model, + // &chunk.shadow_model, globals, &chunk.locals, lights, @@ -2240,6 +2256,7 @@ impl Terrain { ); } } + // println!("Vertex count (shadow / terrain / ratio): {:?} / {:?} / {:?}", shadow_vertex_count, terrain_vertex_count, shadow_vertex_count as f64 / terrain_vertex_count as f64); } pub fn render_translucent(