From 025831d9a297cc05b907dc1c1d0171e370ebc277 Mon Sep 17 00:00:00 2001
From: Avi Weinstock <aweinstock314@gmail.com>
Date: Wed, 7 Jun 2023 15:39:57 -0400
Subject: [PATCH] Add `GradientSobel` experimental filter that adds object
 outlines based on the normal map.

---
 assets/voxygen/shaders/postprocess-frag.glsl | 25 ++++++++++++++++++++
 voxygen/src/render/mod.rs                    |  2 ++
 voxygen/src/render/pipelines/postprocess.rs  | 16 +++++++++++++
 voxygen/src/render/renderer/locals.rs        |  2 ++
 4 files changed, 45 insertions(+)

diff --git a/assets/voxygen/shaders/postprocess-frag.glsl b/assets/voxygen/shaders/postprocess-frag.glsl
index 40b4dc0845..6ff6c9aebb 100644
--- a/assets/voxygen/shaders/postprocess-frag.glsl
+++ b/assets/voxygen/shaders/postprocess-frag.glsl
@@ -34,6 +34,9 @@ uniform texture2D t_src_depth;
 layout(set = 1, binding = 3)
 uniform sampler s_src_depth;
 
+layout(set = 1, binding = 6)
+uniform utexture2D t_src_mat;
+
 layout(location = 0) in vec2 uv;
 
 layout (std140, set = 1, binding = 4)
@@ -165,6 +168,13 @@ vec3 aa_sample(vec2 uv, vec2 off) {
     return aa_apply(t_src_color, s_src_color, t_src_depth, s_src_depth, uv * screen_res.xy + off, screen_res.xy).rgb;
 }
 #endif
+#ifdef EXPERIMENTAL_GRADIENTSOBEL
+vec3 aa_sample_grad(vec2 uv, vec2 off) {
+    uvec2 mat_sz = textureSize(usampler2D(t_src_mat, s_src_depth), 0);
+    uvec4 mat = texelFetch(usampler2D(t_src_mat, s_src_depth), clamp(ivec2(uv * mat_sz + off), ivec2(0), ivec2(mat_sz) - 1), 0);
+    return vec3(mat.xyz) / 255.0;
+}
+#endif
 
 #ifdef EXPERIMENTAL_COLORDITHERING
     float dither(ivec2 p, float level) {
@@ -249,6 +259,21 @@ void main() {
         float mag = length(gx) + length(gy);
         aa_color.rgb = mix(vec3(0.9), aa_color.rgb * 0.8, clamp(1.0 - mag * 0.3, 0.0, 1.0));
     #endif
+    #ifdef EXPERIMENTAL_GRADIENTSOBEL
+        vec3 s2[8];
+        s2[0] = aa_sample_grad(uv, vec2(-1,  1));
+        s2[1] = aa_sample_grad(uv, vec2( 0,  1));
+        s2[2] = aa_sample_grad(uv, vec2( 1,  1));
+        s2[3] = aa_sample_grad(uv, vec2(-1,  0));
+        s2[4] = aa_sample_grad(uv, vec2( 1,  0));
+        s2[5] = aa_sample_grad(uv, vec2(-1, -1));
+        s2[6] = aa_sample_grad(uv, vec2( 0, -1));
+        s2[7] = aa_sample_grad(uv, vec2( 1, -1));
+        vec3 gx2 = s2[0] + s2[3] * 2.0 + s2[5] - s2[2] - s2[4] * 2 - s2[7];
+        vec3 gy2 = s2[0] + s2[1] * 2.0 + s2[2] - s2[5] - s2[6] * 2 - s2[7];
+        float mag2 = length(gx2) + length(gy2);
+        aa_color.rgb = mix(vec3(0.0), aa_color.rgb * 0.8, clamp(1.0 - mag2 * 0.3, 0.0, 1.0));
+    #endif
 
     // Bloom
     #ifdef BLOOM_FACTOR
diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs
index ff71457ca2..e1e9f19c77 100644
--- a/voxygen/src/render/mod.rs
+++ b/voxygen/src/render/mod.rs
@@ -490,6 +490,8 @@ pub enum ExperimentalShader {
     /// post-processing so there is potentially a significant performance
     /// impact especially with anti aliasing enabled.
     Sobel,
+    /// Like Sobel, but on the gradient texture instead of the color texture.
+    GradientSobel,
     /// Simulate a curved world.
     CurvedWorld,
     /// Adds extra detail to distant LoD (Level of Detail) terrain procedurally.
diff --git a/voxygen/src/render/pipelines/postprocess.rs b/voxygen/src/render/pipelines/postprocess.rs
index 4733a04690..714abb617d 100644
--- a/voxygen/src/render/pipelines/postprocess.rs
+++ b/voxygen/src/render/pipelines/postprocess.rs
@@ -84,6 +84,17 @@ impl PostProcessLayout {
                 },
                 count: None,
             },
+            // Material source
+            wgpu::BindGroupLayoutEntry {
+                binding: 6,
+                visibility: wgpu::ShaderStage::FRAGMENT,
+                ty: wgpu::BindingType::Texture {
+                    sample_type: wgpu::TextureSampleType::Uint,
+                    view_dimension: wgpu::TextureViewDimension::D2,
+                    multisampled: false,
+                },
+                count: None,
+            },
         ];
 
         if pipeline_modes.bloom.is_on() {
@@ -115,6 +126,7 @@ impl PostProcessLayout {
         device: &wgpu::Device,
         src_color: &wgpu::TextureView,
         src_depth: &wgpu::TextureView,
+        src_mat: &wgpu::TextureView,
         src_bloom: Option<&wgpu::TextureView>,
         sampler: &wgpu::Sampler,
         depth_sampler: &wgpu::Sampler,
@@ -141,6 +153,10 @@ impl PostProcessLayout {
                 binding: 4,
                 resource: locals.buf().as_entire_binding(),
             },
+            wgpu::BindGroupEntry {
+                binding: 6,
+                resource: wgpu::BindingResource::TextureView(src_mat),
+            },
         ];
         // Optional bloom source
         if let Some(src_bloom) = src_bloom {
diff --git a/voxygen/src/render/renderer/locals.rs b/voxygen/src/render/renderer/locals.rs
index 6134fbdd39..12276a44a7 100644
--- a/voxygen/src/render/renderer/locals.rs
+++ b/voxygen/src/render/renderer/locals.rs
@@ -50,6 +50,7 @@ impl Locals {
             device,
             tgt_color_pp_view,
             tgt_depth_view,
+            tgt_mat_view,
             bloom.as_ref().map(|b| b.final_tgt_view),
             sampler,
             depth_sampler,
@@ -99,6 +100,7 @@ impl Locals {
             device,
             tgt_color_pp_view,
             tgt_depth_view,
+            tgt_mat_view,
             bloom.as_ref().map(|b| b.final_tgt_view),
             sampler,
             depth_sampler,