﻿Shader "SnapshotProHDRP/Outline"
{
    HLSLINCLUDE

    #pragma target 4.5
    #pragma only_renderers d3d11 ps4 xboxone vulkan metal switch

    #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
    #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/FXAA.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/RTUpscale.hlsl"
	#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/NormalBuffer.hlsl"

    struct Attributes
    {
        uint vertexID : SV_VertexID;
        UNITY_VERTEX_INPUT_INSTANCE_ID
    };

    struct Varyings
    {
        float4 positionCS : SV_POSITION;
        float2 texcoord   : TEXCOORD0;
        UNITY_VERTEX_OUTPUT_STEREO
    };

    Varyings Vert(Attributes input)
    {
        Varyings output;
        UNITY_SETUP_INSTANCE_ID(input);
        UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
        output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID);
        output.texcoord = GetFullScreenTriangleTexCoord(input.vertexID);
        return output;
    }

    // List of properties to control your post process effect
	TEXTURE2D_X(_InputTexture);

	float _ColorSensitivity;
	float _ColorStrength;
	float _DepthSensitivity;
	float _DepthStrength;
	float _NormalsSensitivity;
	float _NormalsStrength;

	float _DepthThreshold;

    float4 CustomPostProcess(Varyings input) : SV_Target
    {
        UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);

        uint2 positionSS = input.texcoord * _ScreenSize.xy;

		float4 col = LOAD_TEXTURE2D_X(_InputTexture, positionSS);

		// Determine plus-shaped sampling positions.
		float2 leftUV = positionSS + float2(-1.0f, 0.0f);
		float2 rightUV = positionSS + float2(1.0f, 0.0f);
		float2 bottomUV = positionSS + float2(0.0f, -1.0f);
		float2 topUV = positionSS + float2(0.0f, 1.0f);

		// Calculate edges based on colour data.
		float3 col0 = LOAD_TEXTURE2D_X(_InputTexture, leftUV).rgb;
		float3 col1 = LOAD_TEXTURE2D_X(_InputTexture, rightUV).rgb;
		float3 col2 = LOAD_TEXTURE2D_X(_InputTexture, bottomUV).rgb;
		float3 col3 = LOAD_TEXTURE2D_X(_InputTexture, topUV).rgb;

		float3 c0 = col1 - col0;
		float3 c1 = col3 - col2;

		float edgeCol = sqrt(dot(c0, c0) + dot(c1, c1));
		edgeCol = edgeCol > _ColorSensitivity ? _ColorStrength : 0;

		// Calculate edges based on depth data.
		float depth0 = LOAD_TEXTURE2D_X(_CameraDepthTexture, leftUV).r;
		float depth1 = LOAD_TEXTURE2D_X(_CameraDepthTexture, rightUV).r;
		float depth2 = LOAD_TEXTURE2D_X(_CameraDepthTexture, bottomUV).r;
		float depth3 = LOAD_TEXTURE2D_X(_CameraDepthTexture, topUV).r;

		depth0 = Linear01Depth(depth0, _ZBufferParams);
		depth1 = Linear01Depth(depth1, _ZBufferParams);
		depth2 = Linear01Depth(depth2, _ZBufferParams);
		depth3 = Linear01Depth(depth3, _ZBufferParams);

		float d0 = depth1 - depth0;
		float d1 = depth3 - depth2;

		float edgeDepth = sqrt(d0 * d0 + d1 * d1);
		edgeDepth = edgeDepth > _DepthSensitivity ? _DepthStrength : 0;

		// Calculate edges based on normal data.
		NormalData normalData;

		DecodeFromNormalBuffer(leftUV, normalData);
		float3 normal0 = normalData.normalWS;
		DecodeFromNormalBuffer(rightUV, normalData);
		float3 normal1 = normalData.normalWS;
		DecodeFromNormalBuffer(bottomUV, normalData);
		float3 normal2 = normalData.normalWS;
		DecodeFromNormalBuffer(topUV, normalData);
		float3 normal3 = normalData.normalWS;

		float3 n0 = normal1 - normal0;
		float3 n1 = normal3 - normal2;

		float edgeNormal = sqrt(dot(n0, n0) + dot(n1, n1));
		edgeNormal = edgeNormal > _NormalsSensitivity ? _NormalsStrength : 0;

		// Combine edge data.
		float edge = max(max(edgeCol, edgeDepth), edgeNormal);

		float depth = LOAD_TEXTURE2D_X(_CameraDepthTexture, positionSS);
		depth = Linear01Depth(depth, _ZBufferParams);
		edge = depth > _DepthThreshold ? 0.0f : edge;

		return col * (1.0f - edge);
    }

    ENDHLSL

    SubShader
    {
        Pass
        {
            Name "Outline"

            ZWrite Off
            ZTest Always
            Blend Off
            Cull Off

            HLSLPROGRAM
                #pragma fragment CustomPostProcess
                #pragma vertex Vert
            ENDHLSL
        }
    }
    Fallback Off
}
