Shader "Hidden/Ilumisoft/PostProcessing/Outline" { HLSLINCLUDE #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareNormalsTexture.hlsl" float4 _OutlineColor; float4 _BackgroundColor; float _BackgroundColorOpacity; float _ReferenceHeight; int _OutlineThickness; int _IsFadeEnabled; float _FadeStart; float _FadeEnd; float2 _DepthEdge; float2 _NormalEdge; float _LuminancePower; float _LuminanceContrast; // Samples the scene normals remapped to [0,1] inline float3 SampleNormal(float2 uv) { return SampleSceneNormals(uv) * 0.5 + 0.5; } // Samples the scene color inline float3 SampleColor(float2 uv) { return SAMPLE_TEXTURE2D(_BlitTexture,sampler_LinearClamp, uv).rgb; } // Samples the scene depth linear01 inline float SampleDepthLinear01(float2 uv) { return Linear01Depth(SampleSceneDepth(uv),_ZBufferParams); } float GetNormalOutline(float3 topLeft, float3 bottomRight, float3 topRight, float3 bottomLeft) { float3 delta = abs(topLeft-bottomRight) + abs(topRight-bottomLeft); float normalOutline = saturate(max(delta.r, max(delta.g, delta.b))); return smoothstep(_NormalEdge.x, _NormalEdge.y, normalOutline); } float GetDepthOutline(float topLeft, float bottomRight, float topRight, float bottomLeft) { float result = abs(topLeft - bottomRight) + abs(topRight - bottomLeft); result /= max(topLeft, max(bottomRight, max(topRight, bottomLeft))); return smoothstep(_DepthEdge.x, _DepthEdge.y, saturate(result)); } inline float InverseLerp(float a, float b, float t) { return saturate((t-a)/(b-a)); } float LuminancePowerContrast(float3 color, float power, float contrast) { float luminance = pow(saturate(Luminance(color)), power); float midpoint = pow(0.5, 2.2); return saturate((luminance - midpoint) * contrast + midpoint); } float4 OutlineDepthOnly (Varyings input) : SV_Target { float2 offset = _OutlineThickness * _BlitTexture_TexelSize.xy*_ScreenParams.y/_ReferenceHeight; float2 centerUV = input.texcoord; // Sample color and depth of the current pixel float3 centerColor = SampleColor(centerUV); float centerDepth = SampleSceneDepth(centerUV); float distance = LinearEyeDepth(centerDepth,_ZBufferParams); centerDepth = Linear01Depth(centerDepth,_ZBufferParams); float cornerDepths[4]; float2 cornerUVs[4]; // Create corner UVs cornerUVs[0] = centerUV + float2(-offset.x, offset.y); cornerUVs[1] = centerUV - float2(-offset.x, offset.y); cornerUVs[2] = centerUV + offset; cornerUVs[3] = centerUV - offset; [unroll] for(int i=0; i<4; i++) { // depth cornerDepths[i] = SampleDepthLinear01(cornerUVs[i]); // Discard values with a lower depth cornerDepths[i] = (cornerDepths[i]>centerDepth) ? cornerDepths[i] : centerDepth; } // Compute outline float outline = GetDepthOutline(cornerDepths[0], cornerDepths[1], cornerDepths[2], cornerDepths[3]); // Apply distance fade outline *= 1.0 - InverseLerp(_FadeStart, _FadeEnd, distance) * _IsFadeEnabled; // Apply background color fill float3 color = LuminancePowerContrast(centerColor, _LuminancePower, _LuminanceContrast) * _BackgroundColor.rgb; color = lerp(centerColor, color, _BackgroundColorOpacity); // Apply outline color = lerp(color, _OutlineColor.rgb, outline*_OutlineColor.a); return float4(color, 1.0); } float4 OutlineDepthNormal (Varyings input) : SV_Target { float2 offset = _OutlineThickness * _BlitTexture_TexelSize.xy*_ScreenParams.y/_ReferenceHeight; float2 centerUV = input.texcoord; // Sample color, depth and normal of the current pixel float3 centerNormal = SampleNormal(centerUV); float3 centerColor = SampleColor(centerUV); float centerDepth = SampleSceneDepth(centerUV); float distance = LinearEyeDepth(centerDepth,_ZBufferParams); centerDepth = Linear01Depth(centerDepth,_ZBufferParams); float3 cornerNormals[4]; float cornerDepths[4]; float2 cornerUVs[4]; // Create corner UVs cornerUVs[0] = centerUV + float2(-offset.x, offset.y); cornerUVs[1] = centerUV - float2(-offset.x, offset.y); cornerUVs[2] = centerUV + offset; cornerUVs[3] = centerUV - offset; [unroll] for(int i=0; i<4; i++) { // sample normal and depth cornerNormals[i] = SampleNormal(cornerUVs[i]); cornerDepths[i] = SampleDepthLinear01(cornerUVs[i]); // Discard values with a lower depth cornerNormals[i] = (cornerDepths[i]>centerDepth) ? cornerNormals[i] : centerNormal; cornerDepths[i] = (cornerDepths[i]>centerDepth) ? cornerDepths[i] : centerDepth; } // Compute outline float normalOutline = GetNormalOutline(cornerNormals[0], cornerNormals[1], cornerNormals[2], cornerNormals[3]); float depthOutline = GetDepthOutline(cornerDepths[0], cornerDepths[1], cornerDepths[2], cornerDepths[3]); float outline = max(normalOutline, depthOutline); // Apply distance fade outline *= 1.0 - InverseLerp(_FadeStart, _FadeEnd, distance) * _IsFadeEnabled; // Apply background color fill float3 color = LuminancePowerContrast(centerColor, _LuminancePower, _LuminanceContrast) * _BackgroundColor.rgb; color = lerp(centerColor, color, _BackgroundColorOpacity); // Apply outline color = lerp(color, _OutlineColor.rgb, outline*_OutlineColor.a); return float4(color, 1.0); } ENDHLSL SubShader { Tags { "RenderType"="Opaque" "RenderPipeline" = "UniversalPipeline"} LOD 100 ZWrite Off Cull Off Pass { Name "OutlineDepthOnlyPass" HLSLPROGRAM #pragma vertex Vert #pragma fragment OutlineDepthOnly ENDHLSL } Pass { Name "OutlineDepthNormalPass" HLSLPROGRAM #pragma vertex Vert #pragma fragment OutlineDepthNormal ENDHLSL } } }