From ec34fcf9c8ac2df5e1aa4941f211e09d6456440b Mon Sep 17 00:00:00 2001 From: Tesseract Date: Sat, 3 Aug 2019 19:55:45 +1000 Subject: [PATCH 1/4] Optimised fragment and vertex shaders. Framebuffer depth target changed from DEPTH24_STENCIL8 to DEPTH24 for faster depth writing and reading (no bitwise operations needed). --- voxygen/shaders/figure.frag | 11 +---- voxygen/shaders/figure.vert | 19 ++++--- voxygen/shaders/include/light.glsl | 35 ++++++++----- voxygen/shaders/include/sky.glsl | 79 ++++++++++++++++-------------- voxygen/shaders/terrain.frag | 14 +----- voxygen/shaders/terrain.vert | 16 ++++-- voxygen/shaders/ui.vert | 2 +- voxygen/src/render/renderer.rs | 4 +- 8 files changed, 98 insertions(+), 82 deletions(-) diff --git a/voxygen/shaders/figure.frag b/voxygen/shaders/figure.frag index bdf8c644d2..a142b4c2ab 100644 --- a/voxygen/shaders/figure.frag +++ b/voxygen/shaders/figure.frag @@ -3,9 +3,8 @@ #include in vec3 f_pos; -in vec3 f_norm; in vec3 f_col; -flat in uint f_bone_idx; +flat in vec3 f_norm; layout (std140) uniform u_locals { @@ -28,13 +27,7 @@ uniform u_bones { out vec4 tgt_color; void main() { - vec3 world_norm = ( - model_mat * - bones[f_bone_idx].bone_mat * - vec4(f_norm, 0.0) - ).xyz; - - vec3 light = get_sun_diffuse(world_norm, time_of_day.x) + light_at(f_pos, world_norm); + vec3 light = get_sun_diffuse(f_norm, time_of_day.x) + light_at(f_pos, f_norm); vec3 surf_color = model_col.rgb * f_col * 2.0 * light; float fog_level = fog(f_pos.xy, focus_pos.xy); diff --git a/voxygen/shaders/figure.vert b/voxygen/shaders/figure.vert index a33dc8004c..4617826e08 100644 --- a/voxygen/shaders/figure.vert +++ b/voxygen/shaders/figure.vert @@ -23,17 +23,24 @@ uniform u_bones { }; out vec3 f_pos; -out vec3 f_norm; out vec3 f_col; -flat out uint f_bone_idx; +flat out vec3 f_norm; void main() { - f_pos = (model_mat * - bones[v_bone_idx].bone_mat * + // Pre-calculate bone matrix + mat4 combined_mat = model_mat * bones[v_bone_idx].bone_mat; + + f_pos = ( + combined_mat * vec4(v_pos, 1)).xyz; - f_norm = v_norm; + f_col = v_col; - f_bone_idx = v_bone_idx; + + // Calculate normal here rather than for each pixel in the fragment shader + f_norm = ( + combined_mat * + vec4(v_norm, 0.0) + ).xyz; gl_Position = proj_mat * view_mat * vec4(f_pos, 1); } diff --git a/voxygen/shaders/include/light.glsl b/voxygen/shaders/include/light.glsl index 826f38612e..ebdc3beaec 100644 --- a/voxygen/shaders/include/light.glsl +++ b/voxygen/shaders/include/light.glsl @@ -16,19 +16,32 @@ vec3 light_at(vec3 wpos, vec3 wnorm) { const float LIGHT_AMBIENCE = 0.025; vec3 light = vec3(0); - for (uint i = 0u; i < light_count.x; i ++) { - vec3 light_pos = lights[i].light_pos.xyz; - float strength = attenuation_strength(wpos - light_pos); - vec3 color = strength - * lights[i].light_col.rgb - * lights[i].light_col.a; + for (uint i = 0u; i < light_count.x; i++) { - if (max(max(color.r, color.g), color.b) < 0.002) { - continue; - } + // Only access the array once + Light L = lights[i]; - light += color * clamp(dot(normalize(light_pos - wpos), wnorm), LIGHT_AMBIENCE, 1.0); + vec3 light_pos = L.light_pos.xyz; + + // Pre-calculate difference between light and fragment + vec3 difference = light_pos - wpos; + + float strength = attenuation_strength(difference); + + // Multiply the vec3 only once + vec3 color = L.light_col.rgb * (strength * L.light_col.a); + + // This is commented out to avoid conditional branching. See here: https://community.khronos.org/t/glsl-float-multiply-by-zero/104391 + // if (max(max(color.r, color.g), color.b) < 0.002) { + // continue; + // } + + // Old: light += color * clamp(dot(normalize(difference), wnorm), LIGHT_AMBIENCE, 1.0); + + // The dot product cannot be greater than one, so no need to clamp max value + // Also, rather than checking if it is smaller than LIGHT_AMBIENCE, add LIGHT_AMBIENCE instead + light += color * (max(0, dot(normalize(difference), wnorm)) + LIGHT_AMBIENCE); } return light; -} +} \ No newline at end of file diff --git a/voxygen/shaders/include/sky.glsl b/voxygen/shaders/include/sky.glsl index 86c6dd4e00..8886add0a0 100644 --- a/voxygen/shaders/include/sky.glsl +++ b/voxygen/shaders/include/sky.glsl @@ -37,17 +37,20 @@ vec3 get_sun_diffuse(vec3 norm, float time_of_day) { float sun_light = get_sun_brightness(sun_dir); + // clamp() changed to max() as sun_dir.z is produced from a cos() function and therefore never greater than 1 + vec3 sun_color = normalize(mix( mix( DUSK_LIGHT, NIGHT_LIGHT, - clamp(sun_dir.z, 0, 1) + max(sun_dir.z, 0) ), DAY_LIGHT, - clamp(-sun_dir.z, 0, 1) + max(-sun_dir.z, 0) )); - vec3 diffuse_light = (SUN_AMBIANCE + max(dot(-norm, sun_dir), 0.0) * sun_color) * sun_light + PERSISTENT_AMBIANCE; + // Multiply floats together before multiplying with sun_color (1 multiplication vs 3) + vec3 diffuse_light = sun_color * (max(dot(-norm, sun_dir), 0.0) * sun_light + SUN_AMBIANCE) + PERSISTENT_AMBIANCE; return diffuse_light; } @@ -56,73 +59,74 @@ vec3 rand_offs(vec3 pos) { return sin(pos * vec3(1473.7 * pos.z + 472.3, 8891.1 * pos.x + 723.1, 3813.3 * pos.y + 982.5)); } -vec3 get_sky_color(vec3 dir, float time_of_day) { - +// The loop has been removed as the result was always 1, not an accumulation of values +float is_star_at(vec3 dir) { // Stars - float star_scale = 30.0; - float star = 0.0; - for (int i = 0; i < 2; i ++) { - for (int j = 0; j < 2; j ++) { - for (int k = 0; k < 2; k ++) { - // Star positions - vec3 pos = (floor(dir * star_scale) + vec3(i, j, k) - vec3(0.5)) / star_scale; + float star_scale = 15.0; - // Noisy offsets - pos += 3.0 * rand_offs(pos) / star_scale; + // Star positions + vec3 pos = floor(dir * star_scale) / star_scale; - // Find distance to fragment - float dist = length(normalize(pos) - dir); + pos += rand_offs(pos) / star_scale; - // Star threshold - if (dist < 0.0015) { - star = 1.0; - } - } - } + // Find distance to fragment + float dist = length(normalize(pos) - dir); + + // Star threshold + if (dist < 0.0015) { + return 1.0; } - // Sky color + return 0.0; +} +vec3 get_sky_color(vec3 dir, float time_of_day) { + // Sky color vec3 sun_dir = get_sun_dir(time_of_day); + // Add white dots for stars. Note these flicker and jump due to FXAA + float star = is_star_at(dir); + + // Replaced all clamp(sun_dir, 0, 1) with max(sun_dir, 0) because sun_dir is calculated from sin and cos, which are never > 1 + vec3 sky_top = mix( mix( SKY_DUSK_TOP, SKY_NIGHT_TOP, - clamp(sun_dir.z, 0, 1) - ) + star, + max(sun_dir.z, 0) + ), SKY_DAY_TOP, - clamp(-sun_dir.z, 0, 1) - ); + max(-sun_dir.z, 0) + ) + star; vec3 sky_mid = mix( mix( SKY_DUSK_MID, SKY_NIGHT_MID, - clamp(sun_dir.z, 0, 1) + max(sun_dir.z, 0) ), SKY_DAY_MID, - clamp(-sun_dir.z, 0, 1) + max(-sun_dir.z, 0) ); vec3 sky_bot = mix( mix( SKY_DUSK_BOT, SKY_NIGHT_BOT, - clamp(sun_dir.z, 0, 1) + max(sun_dir.z, 0) ), SKY_DAY_BOT, - clamp(-sun_dir.z, 0, 1) + max(-sun_dir.z, 0) ); vec3 sky_color = mix( mix( sky_mid, sky_bot, - pow(clamp(-dir.z, 0, 1), 0.4) + pow(max(-dir.z, 0), 0.4) ), sky_top, - pow(clamp(dir.z, 0, 1), 1.0) + max(dir.z, 0) ); // Sun @@ -139,8 +143,9 @@ vec3 get_sky_color(vec3 dir, float time_of_day) { float fog(vec2 f_pos, vec2 focus_pos) { float dist = distance(f_pos, focus_pos) / view_distance.x; - float min_fog = 0.5; - float max_fog = 1.0; + const float min_fog = 0.5; + const float max_fog = 1.0; + const float diff_fog = 0.5; // max - min - return pow(clamp((dist - min_fog) / (max_fog - min_fog), 0.0, 1.0), 1.7); -} + return pow(clamp((dist - min_fog) / (diff_fog), 0.0, 1.0), 1.7); +} \ No newline at end of file diff --git a/voxygen/shaders/terrain.frag b/voxygen/shaders/terrain.frag index 75bc338d6f..cb0f75cf71 100644 --- a/voxygen/shaders/terrain.frag +++ b/voxygen/shaders/terrain.frag @@ -3,7 +3,7 @@ #include in vec3 f_pos; -flat in uint f_pos_norm; +flat in vec3 f_norm; in vec3 f_col; in float f_light; @@ -18,18 +18,6 @@ out vec4 tgt_color; #include void main() { - // Calculate normal from packed data - vec3 f_norm; - uint norm_axis = (f_pos_norm >> 30) & 0x3u; - float norm_dir = float((f_pos_norm >> 29) & 0x1u) * 2.0 - 1.0; - if (norm_axis == 0u) { - f_norm = vec3(1.0, 0.0, 0.0) * norm_dir; - } else if (norm_axis == 1u) { - f_norm = vec3(0.0, 1.0, 0.0) * norm_dir; - } else { - f_norm = vec3(0.0, 0.0, 1.0) * norm_dir; - } - vec3 light = get_sun_diffuse(f_norm, time_of_day.x) * f_light + light_at(f_pos, f_norm); vec3 surf_color = f_col * light; diff --git a/voxygen/shaders/terrain.vert b/voxygen/shaders/terrain.vert index 7b1d416925..3011d5a238 100644 --- a/voxygen/shaders/terrain.vert +++ b/voxygen/shaders/terrain.vert @@ -11,10 +11,13 @@ uniform u_locals { }; out vec3 f_pos; -flat out uint f_pos_norm; +flat out vec3 f_norm; out vec3 f_col; out float f_light; +// 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) ); + void main() { f_pos = vec3( float((v_pos_norm >> 0) & 0x00FFu), @@ -22,7 +25,14 @@ void main() { float((v_pos_norm >> 16) & 0x1FFFu) ) + model_offs; - f_pos_norm = v_pos_norm; + // 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 = (v_pos_norm >> 30) & 0x3u; + + // Increase array access by 3 to access positive values + uint norm_dir = ((v_pos_norm >> 29) & 0x1u) * 3u; + + // Use an array to avoid conditional branching + f_norm = normals[norm_axis + norm_dir]; f_col = vec3( float((v_col_light >> 8) & 0xFFu), @@ -36,4 +46,4 @@ void main() { proj_mat * view_mat * vec4(f_pos, 1); -} +} \ No newline at end of file diff --git a/voxygen/shaders/ui.vert b/voxygen/shaders/ui.vert index 2411525756..5083761641 100644 --- a/voxygen/shaders/ui.vert +++ b/voxygen/shaders/ui.vert @@ -24,7 +24,7 @@ void main() { if (w_pos.w == 1.0) { // In-game element - gl_Position = proj_mat * (view_mat * w_pos + vec4(v_pos, 0.0, 0.0)); + gl_Position = proj_mat * view_mat * w_pos + vec4(v_pos, 0.0, 0.0); } else { // Interface element gl_Position = vec4(v_pos, 0.0, 1.0); diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 9151a66fb3..52766dc3cf 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -18,12 +18,12 @@ use vek::*; /// Represents the format of the pre-processed color target. pub type TgtColorFmt = gfx::format::Rgba16F; /// Represents the format of the pre-processed depth target. -pub type TgtDepthFmt = gfx::format::DepthStencil; +pub type TgtDepthFmt = gfx::format::Depth; /// Represents the format of the window's color target. pub type WinColorFmt = gfx::format::Rgba8; /// Represents the format of the window's depth target. -pub type WinDepthFmt = gfx::format::DepthStencil; +pub type WinDepthFmt = gfx::format::Depth; /// A handle to a pre-processed color target. pub type TgtColorView = gfx::handle::RenderTargetView; From c36c78252cf59ef589b14533a06f3eb128859de8 Mon Sep 17 00:00:00 2001 From: Tesseract Date: Sun, 4 Aug 2019 20:32:50 +1000 Subject: [PATCH 2/4] Reverted to old star shader --- voxygen/shaders/include/sky.glsl | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/voxygen/shaders/include/sky.glsl b/voxygen/shaders/include/sky.glsl index 8886add0a0..5ef09e0a91 100644 --- a/voxygen/shaders/include/sky.glsl +++ b/voxygen/shaders/include/sky.glsl @@ -59,22 +59,28 @@ vec3 rand_offs(vec3 pos) { return sin(pos * vec3(1473.7 * pos.z + 472.3, 8891.1 * pos.x + 723.1, 3813.3 * pos.y + 982.5)); } -// The loop has been removed as the result was always 1, not an accumulation of values +// This has been extracted into a function to allow quick exit when detecting a star. float is_star_at(vec3 dir) { - // Stars - float star_scale = 15.0; + float star_scale = 30.0; - // Star positions - vec3 pos = floor(dir * star_scale) / star_scale; + for (int i = 0; i < 2; i ++) { + for (int j = 0; j < 2; j ++) { + for (int k = 0; k < 2; k ++) { + // Star positions + vec3 pos = (floor(dir * star_scale) + vec3(i, j, k) - vec3(0.5)) / star_scale; - pos += rand_offs(pos) / star_scale; + // Noisy offsets + pos += (3.0 / star_scale) * rand_offs(pos); - // Find distance to fragment - float dist = length(normalize(pos) - dir); + // Find distance to fragment + float dist = length(normalize(pos) - dir); - // Star threshold - if (dist < 0.0015) { - return 1.0; + // Star threshold + if (dist < 0.0015) { + return 1.0; + } + } + } } return 0.0; From 8abfd2e10fcb1c0deb32684def075feb7863fe4d Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 4 Aug 2019 12:24:56 +0100 Subject: [PATCH 3/4] Reverted sun diffuse change --- voxygen/shaders/include/sky.glsl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/voxygen/shaders/include/sky.glsl b/voxygen/shaders/include/sky.glsl index 5ef09e0a91..fcc627ac22 100644 --- a/voxygen/shaders/include/sky.glsl +++ b/voxygen/shaders/include/sky.glsl @@ -49,8 +49,7 @@ vec3 get_sun_diffuse(vec3 norm, float time_of_day) { max(-sun_dir.z, 0) )); - // Multiply floats together before multiplying with sun_color (1 multiplication vs 3) - vec3 diffuse_light = sun_color * (max(dot(-norm, sun_dir), 0.0) * sun_light + SUN_AMBIANCE) + PERSISTENT_AMBIANCE; + vec3 diffuse_light = (SUN_AMBIANCE + max(dot(-norm, sun_dir), 0.0) * sun_color) * sun_light + PERSISTENT_AMBIANCE; return diffuse_light; } @@ -60,7 +59,7 @@ vec3 rand_offs(vec3 pos) { } // This has been extracted into a function to allow quick exit when detecting a star. -float is_star_at(vec3 dir) { +float is_star_at(vec3 dir) { float star_scale = 30.0; for (int i = 0; i < 2; i ++) { @@ -154,4 +153,4 @@ float fog(vec2 f_pos, vec2 focus_pos) { const float diff_fog = 0.5; // max - min return pow(clamp((dist - min_fog) / (diff_fog), 0.0, 1.0), 1.7); -} \ No newline at end of file +} From 783e8dbfc00dd4a5e111e7902af0649534486e6c Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 4 Aug 2019 12:35:03 +0100 Subject: [PATCH 4/4] Reverted parenthesis removal --- voxygen/shaders/ui.vert | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voxygen/shaders/ui.vert b/voxygen/shaders/ui.vert index 5083761641..2411525756 100644 --- a/voxygen/shaders/ui.vert +++ b/voxygen/shaders/ui.vert @@ -24,7 +24,7 @@ void main() { if (w_pos.w == 1.0) { // In-game element - gl_Position = proj_mat * view_mat * w_pos + vec4(v_pos, 0.0, 0.0); + gl_Position = proj_mat * (view_mat * w_pos + vec4(v_pos, 0.0, 0.0)); } else { // Interface element gl_Position = vec4(v_pos, 0.0, 1.0);