├── .gitattributes ├── EdgeDetect-PostProcessingUnity.meta ├── EdgeDetect-PostProcessingUnity ├── EdgeDetectPostProcessing.cs ├── EdgeDetectPostProcessing.cs.meta ├── Editor.meta ├── Editor │ ├── EdgeDetectPostProcessing_Editor.cs │ └── EdgeDetectPostProcessing_Editor.cs.meta ├── Resources.meta └── Resources │ ├── EdgeDetectNormalsPostProcess.shader │ └── EdgeDetectNormalsPostProcess.shader.meta ├── README.md └── README.md.meta /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto -------------------------------------------------------------------------------- /EdgeDetect-PostProcessingUnity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ca39e78aeaceb2345aeab9ffaad295bd 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /EdgeDetect-PostProcessingUnity/EdgeDetectPostProcessing.cs: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------------------------------------------------------------------- 2 | // Port of the Legacy Unity "Edge Detect" image effect to Post Processing Stack v2 3 | // Jean Moreno, September 2017 4 | // Legacy Image Effect: https://docs.unity3d.com/550/Documentation/Manual/script-EdgeDetectEffectNormals.html 5 | // Post Processing Stack v2: https://github.com/Unity-Technologies/PostProcessing/tree/v2 6 | //-------------------------------------------------------------------------------------------------------------------------------- 7 | 8 | using System; 9 | using UnityEngine; 10 | using UnityEngine.Rendering.PostProcessing; 11 | using EdgeDetectMode = EdgeDetectPostProcessing.EdgeDetectMode; 12 | 13 | //-------------------------------------------------------------------------------------------------------------------------------- 14 | 15 | [System.Serializable] 16 | [PostProcess(typeof(EdgeDetectPostProcessingRenderer), PostProcessEvent.BeforeTransparent, "Unity Legacy/Edge Detection")] 17 | public sealed class EdgeDetectPostProcessing : PostProcessEffectSettings 18 | { 19 | public enum EdgeDetectMode 20 | { 21 | TriangleDepthNormals = 0, 22 | RobertsCrossDepthNormals = 1, 23 | SobelDepth = 2, 24 | SobelDepthThin = 3, 25 | TriangleLuminance = 4, 26 | } 27 | 28 | [Serializable] 29 | public sealed class EdgeDetectModeParameter : ParameterOverride 30 | { 31 | public override void Interp(EdgeDetectMode from, EdgeDetectMode to, float t) 32 | { 33 | base.Interp(from, to, t); 34 | } 35 | } 36 | 37 | public EdgeDetectModeParameter mode = new EdgeDetectModeParameter() { value = EdgeDetectMode.SobelDepthThin }; 38 | public FloatParameter sensitivityDepth = new FloatParameter() { value = 1.0f }; 39 | public FloatParameter sensitivityNormals = new FloatParameter() { value = 1.0f }; 40 | public FloatParameter lumThreshold = new FloatParameter() { value = 0.2f }; 41 | public FloatParameter edgeExp = new FloatParameter() { value = 1.0f }; 42 | public FloatParameter sampleDist = new FloatParameter() { value = 1.0f }; 43 | [Range(0f,1f)] 44 | public FloatParameter edgesOnly = new FloatParameter() { value = 0.0f }; 45 | public ColorParameter edgesOnlyBgColor = new ColorParameter() { value = Color.white }; 46 | } 47 | 48 | //-------------------------------------------------------------------------------------------------------------------------------- 49 | 50 | public sealed class EdgeDetectPostProcessingRenderer : PostProcessEffectRenderer 51 | { 52 | 53 | public override void Render(PostProcessRenderContext context) 54 | { 55 | var sheet = context.propertySheets.Get(Shader.Find("Hidden/EdgeDetect-PostProcess")); 56 | 57 | Vector2 sensitivity = new Vector2(settings.sensitivityDepth, settings.sensitivityNormals); 58 | sheet.properties.SetVector("_Sensitivity", new Vector4(sensitivity.x, sensitivity.y, 1.0f, sensitivity.y)); 59 | sheet.properties.SetFloat("_BgFade", settings.edgesOnly); 60 | sheet.properties.SetFloat("_SampleDistance", settings.sampleDist); 61 | sheet.properties.SetVector("_BgColor", settings.edgesOnlyBgColor.value); 62 | sheet.properties.SetFloat("_Exponent", settings.edgeExp); 63 | sheet.properties.SetFloat("_Threshold", settings.lumThreshold); 64 | 65 | context.command.BlitFullscreenTriangle(context.source, context.destination, sheet, (int)settings.mode.value); 66 | } 67 | 68 | public override DepthTextureMode GetCameraFlags() 69 | { 70 | if(settings.mode == EdgeDetectMode.SobelDepth || settings.mode == EdgeDetectMode.SobelDepthThin) 71 | return DepthTextureMode.Depth; 72 | else if(settings.mode == EdgeDetectMode.TriangleDepthNormals || settings.mode == EdgeDetectMode.RobertsCrossDepthNormals) 73 | return DepthTextureMode.DepthNormals; 74 | 75 | return base.GetCameraFlags(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /EdgeDetect-PostProcessingUnity/EdgeDetectPostProcessing.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9d855211644836f4782ecd611ffbc36f 3 | timeCreated: 1506497287 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /EdgeDetect-PostProcessingUnity/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ac19f53d83ca8234296964e36309e3fc 3 | folderAsset: yes 4 | timeCreated: 1506513993 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /EdgeDetect-PostProcessingUnity/Editor/EdgeDetectPostProcessing_Editor.cs: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------------------------------------------------------------------- 2 | // Port of the Legacy Unity "Edge Detect" image effect to Post Processing Stack v2 3 | // Jean Moreno, September 2017 4 | // Legacy Image Effect: https://docs.unity3d.com/550/Documentation/Manual/script-EdgeDetectEffectNormals.html 5 | // Post Processing Stack v2: https://github.com/Unity-Technologies/PostProcessing/tree/v2 6 | //-------------------------------------------------------------------------------------------------------------------------------- 7 | 8 | using UnityEngine; 9 | using UnityEditor; 10 | using UnityEngine.Rendering.PostProcessing; 11 | using UnityEditor.Rendering.PostProcessing; 12 | 13 | [PostProcessEditor(typeof(EdgeDetectPostProcessing))] 14 | public sealed class EdgeDetectPostProcessing_Editor : PostProcessEffectEditor 15 | { 16 | SerializedParameterOverride mode; 17 | SerializedParameterOverride sensitivityDepth; 18 | SerializedParameterOverride sensitivityNormals; 19 | SerializedParameterOverride lumThreshold; 20 | SerializedParameterOverride edgeExp; 21 | SerializedParameterOverride sampleDist; 22 | SerializedParameterOverride edgesOnly; 23 | SerializedParameterOverride edgesOnlyBgColor; 24 | 25 | GUIContent gc_mode = new GUIContent("Mode"); 26 | GUIContent gc_sensitivityDepth = new GUIContent(" Depth Sensitivity"); 27 | GUIContent gc_sensitivityNormals = new GUIContent(" Normals Sensitivity"); 28 | GUIContent gc_lumThreshold = new GUIContent(" Luminance Threshold"); 29 | GUIContent gc_edgeExp = new GUIContent(" Edge Exponent"); 30 | GUIContent gc_sampleDist = new GUIContent(" Sample Distance"); 31 | GUIContent gc_edgesOnly = new GUIContent(" Edges Only"); 32 | GUIContent gc_edgesOnlyBgColor = new GUIContent(" Color"); 33 | 34 | string gc_description = "Detects spatial differences and converts into black outlines\n\nLegacy image effect from previous Unity versions ported to Post Processing v2"; 35 | GUIContent gc_background = new GUIContent("Background Options"); 36 | 37 | public override void OnEnable() 38 | { 39 | mode = FindParameterOverride(x => x.mode); 40 | sensitivityDepth = FindParameterOverride(x => x.sensitivityDepth); 41 | sensitivityNormals = FindParameterOverride(x => x.sensitivityNormals); 42 | lumThreshold = FindParameterOverride(x => x.lumThreshold); 43 | edgeExp = FindParameterOverride(x => x.edgeExp); 44 | sampleDist = FindParameterOverride(x => x.sampleDist); 45 | edgesOnly = FindParameterOverride(x => x.edgesOnly); 46 | edgesOnlyBgColor = FindParameterOverride(x => x.edgesOnlyBgColor); 47 | } 48 | 49 | public override void OnInspectorGUI() 50 | { 51 | EditorGUILayout.HelpBox(gc_description, MessageType.None); 52 | 53 | PropertyField(mode, gc_mode); 54 | 55 | PropertyField(sampleDist, gc_sampleDist); 56 | 57 | if(mode.value.enumValueIndex < 2) 58 | { 59 | PropertyField(sensitivityDepth, gc_sensitivityDepth); 60 | PropertyField(sensitivityNormals, gc_sensitivityNormals); 61 | } 62 | else if(mode.value.enumValueIndex < 4) 63 | { 64 | PropertyField(edgeExp, gc_edgeExp); 65 | } 66 | else 67 | { 68 | // lum based mode 69 | PropertyField(lumThreshold, gc_lumThreshold); 70 | } 71 | 72 | EditorGUILayout.Space(); 73 | 74 | GUILayout.Label(gc_background); 75 | PropertyField(edgesOnly, gc_edgesOnly); 76 | PropertyField(edgesOnlyBgColor, gc_edgesOnlyBgColor); 77 | } 78 | } -------------------------------------------------------------------------------- /EdgeDetect-PostProcessingUnity/Editor/EdgeDetectPostProcessing_Editor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0a990cb83f3b22840995e112ed30b0cd 3 | timeCreated: 1506497287 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /EdgeDetect-PostProcessingUnity/Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 20e84f09f19d61f41adde35b69099bb7 3 | folderAsset: yes 4 | timeCreated: 1513170971 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /EdgeDetect-PostProcessingUnity/Resources/EdgeDetectNormalsPostProcess.shader: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------------------------------------------------------------------- 2 | // Port of the Legacy Unity "Edge Detect" image effect to Post Processing Stack v2 3 | // Jean Moreno, September 2017 4 | // Legacy Image Effect: https://docs.unity3d.com/550/Documentation/Manual/script-EdgeDetectEffectNormals.html 5 | // Post Processing Stack v2: https://github.com/Unity-Technologies/PostProcessing/tree/v2 6 | //-------------------------------------------------------------------------------------------------------------------------------- 7 | Shader "Hidden/EdgeDetect-PostProcess" 8 | { 9 | HLSLINCLUDE 10 | 11 | #include "PostProcessing/Shaders/StdLib.hlsl" 12 | 13 | //Functions and macros from UnityCG, because we can't include it here (causes duplicates from StdLib) 14 | //Copied from UnityCG.cginc v2017.1.0f3 15 | 16 | inline float DecodeFloatRG( float2 enc ) 17 | { 18 | float2 kDecodeDot = float2(1.0, 1/255.0); 19 | return dot( enc, kDecodeDot ); 20 | } 21 | 22 | #if !defined(SHADER_TARGET_GLSL) && !defined(SHADER_API_PSSL) && !defined(SHADER_API_GLES3) && !defined(SHADER_API_VULKAN) && !(defined(SHADER_API_METAL) && defined(UNITY_COMPILER_HLSLCC)) 23 | #define sampler2D_float sampler2D 24 | #endif 25 | 26 | #undef SAMPLE_DEPTH_TEXTURE 27 | #if defined(SHADER_API_PSP2) 28 | half4 SAMPLE_DEPTH_TEXTURE(sampler2D s, float4 uv) { return tex2D(s, (float3)uv); } 29 | half4 SAMPLE_DEPTH_TEXTURE(sampler2D s, float3 uv) { return tex2D(s, uv); } 30 | half4 SAMPLE_DEPTH_TEXTURE(sampler2D s, float2 uv) { return tex2D(s, uv); } 31 | #else 32 | #define SAMPLE_DEPTH_TEXTURE(sampler, uv) (tex2D(sampler, uv).r) 33 | #endif 34 | 35 | //-------------------------------------------------------------------------------------------------------------------------------- 36 | 37 | //Source image 38 | TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex); 39 | float4 _MainTex_ST; 40 | float4 _MainTex_TexelSize; 41 | 42 | //Camera depth/normals 43 | sampler2D _CameraDepthNormalsTexture; 44 | half4 _CameraDepthNormalsTexture_ST; 45 | sampler2D_float _CameraDepthTexture; 46 | half4 _CameraDepthTexture_ST; 47 | 48 | //Settings 49 | half4 _Sensitivity; 50 | half4 _BgColor; 51 | half _BgFade; 52 | half _SampleDistance; 53 | float _Exponent; 54 | float _Threshold; 55 | 56 | //-------------------------------------------------------------------------------------------------------------------------------- 57 | 58 | struct Varyings 59 | { 60 | float4 vertex : SV_POSITION; 61 | float2 texcoord[5] : TEXCOORD0; 62 | float2 texcoordStereo : TEXCOORD5; 63 | }; 64 | 65 | struct VaryingsD 66 | { 67 | float4 vertex : SV_POSITION; 68 | float2 texcoord[2] : TEXCOORD0; 69 | float2 texcoordStereo : TEXCOORD2; 70 | }; 71 | 72 | struct VaryingsLum 73 | { 74 | float4 vertex : SV_POSITION; 75 | float2 texcoord[3] : TEXCOORD0; 76 | float2 texcoordStereo : TEXCOORD3; 77 | }; 78 | 79 | //-------------------------------------------------------------------------------------------------------------------------------- 80 | 81 | inline half CheckSame (half2 centerNormal, float centerDepth, half4 theSample) 82 | { 83 | // difference in normals 84 | // do not bother decoding normals - there's no need here 85 | half2 diff = abs(centerNormal - theSample.xy) * _Sensitivity.y; 86 | int isSameNormal = (diff.x + diff.y) * _Sensitivity.y < 0.1; 87 | // difference in depth 88 | float sampleDepth = DecodeFloatRG (theSample.zw); 89 | float zdiff = abs(centerDepth-sampleDepth); 90 | // scale the required threshold by the distance 91 | int isSameDepth = zdiff * _Sensitivity.x < 0.09 * centerDepth; 92 | 93 | // return: 94 | // 1 - if normals and depth are similar enough 95 | // 0 - otherwise 96 | return isSameNormal * isSameDepth ? 1.0 : 0.0; 97 | } 98 | 99 | //-------------------------------------------------------------------------------------------------------------------------------- 100 | 101 | Varyings VertRobert(AttributesDefault v) 102 | { 103 | Varyings o; 104 | 105 | o.vertex = float4(v.vertex.xy, 0.0, 1.0); 106 | float2 texcoord = TransformTriangleVertexToUV(v.vertex.xy); 107 | 108 | #if UNITY_UV_STARTS_AT_TOP 109 | texcoord = texcoord * float2(1.0, -1.0) + float2(0.0, 1.0); 110 | #endif 111 | 112 | o.texcoordStereo = TransformStereoScreenSpaceTex(texcoord, 1.0); 113 | o.texcoord[0] = UnityStereoScreenSpaceUVAdjust(texcoord, _MainTex_ST); 114 | 115 | o.texcoord[1] = UnityStereoScreenSpaceUVAdjust(texcoord + _MainTex_TexelSize.xy * half2(1,1) * _SampleDistance, _MainTex_ST); 116 | o.texcoord[2] = UnityStereoScreenSpaceUVAdjust(texcoord + _MainTex_TexelSize.xy * half2(-1,-1) * _SampleDistance, _MainTex_ST); 117 | o.texcoord[3] = UnityStereoScreenSpaceUVAdjust(texcoord + _MainTex_TexelSize.xy * half2(-1,1) * _SampleDistance, _MainTex_ST); 118 | o.texcoord[4] = UnityStereoScreenSpaceUVAdjust(texcoord + _MainTex_TexelSize.xy * half2(1,-1) * _SampleDistance, _MainTex_ST); 119 | 120 | return o; 121 | } 122 | 123 | float4 FragRobert(Varyings i) : SV_Target 124 | { 125 | half4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord[0]); 126 | 127 | half4 sample1 = tex2D(_CameraDepthNormalsTexture, i.texcoord[1].xy); 128 | half4 sample2 = tex2D(_CameraDepthNormalsTexture, i.texcoord[2].xy); 129 | half4 sample3 = tex2D(_CameraDepthNormalsTexture, i.texcoord[3].xy); 130 | half4 sample4 = tex2D(_CameraDepthNormalsTexture, i.texcoord[4].xy); 131 | 132 | half edge = 1.0; 133 | edge *= CheckSame(sample1.xy, DecodeFloatRG(sample1.zw), sample2); 134 | edge *= CheckSame(sample3.xy, DecodeFloatRG(sample3.zw), sample4); 135 | 136 | return edge * lerp(color, _BgColor, _BgFade); 137 | } 138 | 139 | //-------------------------------------------------------------------------------------------------------------------------------- 140 | 141 | VaryingsLum VertThin(AttributesDefault v) 142 | { 143 | VaryingsLum o; 144 | 145 | o.vertex = float4(v.vertex.xy, 0.0, 1.0); 146 | float2 texcoord = TransformTriangleVertexToUV(v.vertex.xy); 147 | 148 | #if UNITY_UV_STARTS_AT_TOP 149 | texcoord = texcoord * float2(1.0, -1.0) + float2(0.0, 1.0); 150 | #endif 151 | 152 | o.texcoordStereo = TransformStereoScreenSpaceTex(texcoord, 1.0); 153 | o.texcoord[0] = UnityStereoScreenSpaceUVAdjust(texcoord, _MainTex_ST); 154 | 155 | // offsets for two additional samples 156 | o.texcoord[1] = UnityStereoScreenSpaceUVAdjust(texcoord + float2(-_MainTex_TexelSize.x, -_MainTex_TexelSize.y) * _SampleDistance, _MainTex_ST); 157 | o.texcoord[2] = UnityStereoScreenSpaceUVAdjust(texcoord + float2(+_MainTex_TexelSize.x, -_MainTex_TexelSize.y) * _SampleDistance, _MainTex_ST); 158 | 159 | return o; 160 | } 161 | 162 | float4 FragThin(VaryingsLum i) : SV_Target 163 | { 164 | half4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord[0]); 165 | 166 | half4 center = tex2D(_CameraDepthNormalsTexture, i.texcoord[0]); 167 | half4 sample1 = tex2D(_CameraDepthNormalsTexture, i.texcoord[1]); 168 | half4 sample2 = tex2D(_CameraDepthNormalsTexture, i.texcoord[2]); 169 | 170 | // encoded normal 171 | half2 centerNormal = center.xy; 172 | // decoded depth 173 | float centerDepth = DecodeFloatRG(center.zw); 174 | 175 | half edge = 1.0; 176 | edge *= CheckSame(centerNormal, centerDepth, sample1); 177 | edge *= CheckSame(centerNormal, centerDepth, sample2); 178 | 179 | return edge * lerp(color, _BgColor, _BgFade); 180 | } 181 | 182 | //-------------------------------------------------------------------------------------------------------------------------------- 183 | 184 | VaryingsD VertD(AttributesDefault v) 185 | { 186 | VaryingsD o; 187 | 188 | o.vertex = float4(v.vertex.xy, 0.0, 1.0); 189 | float2 texcoord = TransformTriangleVertexToUV(v.vertex.xy); 190 | 191 | #if UNITY_UV_STARTS_AT_TOP 192 | texcoord = texcoord * float2(1.0, -1.0) + float2(0.0, 1.0); 193 | #endif 194 | 195 | o.texcoordStereo = TransformStereoScreenSpaceTex(texcoord, 1.0); 196 | o.texcoord[0] = UnityStereoScreenSpaceUVAdjust(texcoord, _MainTex_ST); 197 | o.texcoord[1] = texcoord; 198 | 199 | return o; 200 | } 201 | 202 | float4 FragD(VaryingsD i) : SV_Target 203 | { 204 | half4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord[0]); 205 | 206 | // inspired by borderlands implementation of popular "sobel filter" 207 | 208 | #if defined(FRAGD_CHEAP) 209 | float centerDepth = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.texcoord[1])); 210 | #else 211 | float centerDepth = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, UnityStereoScreenSpaceUVAdjust(i.texcoord[1], _CameraDepthTexture_ST))); 212 | #endif 213 | 214 | float4 depthsDiag; 215 | float4 depthsAxis; 216 | 217 | float2 uvDist = _SampleDistance * _MainTex_TexelSize.xy; 218 | 219 | depthsDiag.x = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, UnityStereoScreenSpaceUVAdjust(i.texcoord[1]+uvDist, _CameraDepthTexture_ST))); // TR 220 | depthsDiag.y = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, UnityStereoScreenSpaceUVAdjust(i.texcoord[1]+uvDist*float2(-1,1), _CameraDepthTexture_ST))); // TL 221 | depthsDiag.z = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, UnityStereoScreenSpaceUVAdjust(i.texcoord[1]-uvDist*float2(-1,1), _CameraDepthTexture_ST))); // BR 222 | depthsDiag.w = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, UnityStereoScreenSpaceUVAdjust(i.texcoord[1]-uvDist, _CameraDepthTexture_ST))); // BL 223 | 224 | depthsAxis.x = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, UnityStereoScreenSpaceUVAdjust(i.texcoord[1]+uvDist*float2(0,1), _CameraDepthTexture_ST))); // T 225 | depthsAxis.y = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, UnityStereoScreenSpaceUVAdjust(i.texcoord[1]-uvDist*float2(1,0), _CameraDepthTexture_ST))); // L 226 | depthsAxis.z = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, UnityStereoScreenSpaceUVAdjust(i.texcoord[1]+uvDist*float2(1,0), _CameraDepthTexture_ST))); // R 227 | depthsAxis.w = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, UnityStereoScreenSpaceUVAdjust(i.texcoord[1]-uvDist*float2(0,1), _CameraDepthTexture_ST))); // B 228 | 229 | #if !defined(FRAGD_CHEAP) 230 | // make it work nicely with depth based image effects such as depth of field: 231 | depthsDiag = (depthsDiag > centerDepth.xxxx) ? depthsDiag : centerDepth.xxxx; 232 | depthsAxis = (depthsAxis > centerDepth.xxxx) ? depthsAxis : centerDepth.xxxx; 233 | #endif 234 | 235 | depthsDiag -= centerDepth; 236 | depthsAxis /= centerDepth; 237 | 238 | const float4 HorizDiagCoeff = float4(1,1,-1,-1); 239 | const float4 VertDiagCoeff = float4(-1,1,-1,1); 240 | const float4 HorizAxisCoeff = float4(1,0,0,-1); 241 | const float4 VertAxisCoeff = float4(0,1,-1,0); 242 | 243 | float4 SobelH = depthsDiag * HorizDiagCoeff + depthsAxis * HorizAxisCoeff; 244 | float4 SobelV = depthsDiag * VertDiagCoeff + depthsAxis * VertAxisCoeff; 245 | 246 | float SobelX = dot(SobelH, float4(1,1,1,1)); 247 | float SobelY = dot(SobelV, float4(1,1,1,1)); 248 | float Sobel = sqrt(SobelX * SobelX + SobelY * SobelY); 249 | 250 | Sobel = 1.0-pow(saturate(Sobel), _Exponent); 251 | return Sobel * lerp(color, _BgColor, _BgFade); 252 | } 253 | 254 | //-------------------------------------------------------------------------------------------------------------------------------- 255 | 256 | VaryingsLum VertLum(AttributesDefault v) 257 | { 258 | VaryingsLum o; 259 | 260 | o.vertex = float4(v.vertex.xy, 0.0, 1.0); 261 | float2 texcoord = TransformTriangleVertexToUV(v.vertex.xy); 262 | 263 | #if UNITY_UV_STARTS_AT_TOP 264 | texcoord = texcoord * float2(1.0, -1.0) + float2(0.0, 1.0); 265 | #endif 266 | 267 | o.texcoordStereo = TransformStereoScreenSpaceTex(texcoord, 1.0); 268 | 269 | o.texcoord[0] = UnityStereoScreenSpaceUVAdjust(texcoord, _MainTex_ST); 270 | o.texcoord[1] = UnityStereoScreenSpaceUVAdjust(texcoord + float2(-_MainTex_TexelSize.x, -_MainTex_TexelSize.y) * _SampleDistance, _MainTex_ST); 271 | o.texcoord[2] = UnityStereoScreenSpaceUVAdjust(texcoord + float2(+_MainTex_TexelSize.x, -_MainTex_TexelSize.y) * _SampleDistance, _MainTex_ST); 272 | 273 | return o; 274 | } 275 | 276 | float4 FragLum(VaryingsLum i) : SV_Target 277 | { 278 | half4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord[0]); 279 | 280 | // a very simple cross gradient filter 281 | half3 p1 = color.rgb; 282 | half3 p2 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord[1]).rgb; 283 | half3 p3 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord[2]).rgb; 284 | 285 | half3 diff = p1 * 2 - p2 - p3; 286 | half len = dot(diff, diff); 287 | len = step(len, _Threshold); 288 | //if(len >= _Threshold) 289 | // color.rgb = 0; 290 | 291 | return len * lerp(color, _BgColor, _BgFade); 292 | } 293 | 294 | ENDHLSL 295 | 296 | //-------------------------------------------------------------------------------------------------------------------------------- 297 | 298 | Subshader 299 | { 300 | Cull Off 301 | ZWrite Off 302 | ZTest Always 303 | 304 | Pass 305 | { 306 | HLSLPROGRAM 307 | #pragma vertex VertThin 308 | #pragma fragment FragThin 309 | ENDHLSL 310 | } 311 | 312 | Pass 313 | { 314 | HLSLPROGRAM 315 | #pragma vertex VertRobert 316 | #pragma fragment FragRobert 317 | ENDHLSL 318 | } 319 | 320 | Pass 321 | { 322 | HLSLPROGRAM 323 | #pragma multi_compile FRAGD_CHEAP 324 | #pragma vertex VertD 325 | #pragma fragment FragD 326 | ENDHLSL 327 | } 328 | 329 | Pass 330 | { 331 | HLSLPROGRAM 332 | #pragma vertex VertD 333 | #pragma fragment FragD 334 | ENDHLSL 335 | } 336 | 337 | Pass 338 | { 339 | HLSLPROGRAM 340 | #pragma vertex VertLum 341 | #pragma fragment FragLum 342 | ENDHLSL 343 | } 344 | } 345 | 346 | Fallback off 347 | } -------------------------------------------------------------------------------- /EdgeDetect-PostProcessingUnity/Resources/EdgeDetectNormalsPostProcess.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3e5635ce4055e6c4b93d391e2ca4a7ec 3 | ShaderImporter: 4 | userData: 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EdgeDetect-PostProcessingUnity 2 | 3 | Port of the legacy Unity "Edge Detect Normals" image effect to Post Processing Stack **v2** 4 | 5 | - [Edge Detect Effect Normals - Unity Documentation](https://docs.unity3d.com/550/Documentation/Manual/script-EdgeDetectEffectNormals.html) 6 | - [Post Processing Stack v2 - Unity Technologies GitHub](https://github.com/Unity-Technologies/PostProcessing/tree/v2) 7 | 8 | ![Screenshot](https://i.imgur.com/8SH535F.gif) 9 | 10 | ## Installation 11 | 12 | Place the `EdgeDetect-PostProcessingUnity` folder anywhere in your project, and make sure that [Post Processing Stack v2](https://github.com/Unity-Technologies/PostProcessing/tree/v2) is in the project as well. 13 | 14 | ## Usage 15 | 16 | The new effect should be available for a post processing profile under: 17 | `Add effect... > Unity Legacy > Edge Detection` -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5b651f01d38812a438f58b039bcefb8d 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------