﻿Shader "SnapshotProHDRP/Dither3D"
{
    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"

	// List of properties to control your post process effect
	TEXTURE2D_X(_InputTexture);
	sampler2D _NoiseTex;
	float4 _NoiseTex_TexelSize;
	float _NoiseSize;
	float _ThresholdOffset;
	float _Blend;

	float4 _LightColor;
	float4 _DarkColor;

	//sampler2D _CameraDepthNormalsTexture;

	//TEXTURE2D_X(_CameraDepthNormalsTexture);
	TEXTURE2D(_NormalTexture);

	float4x4 _ViewProjectInverse;

    struct Attributes
    {
        uint vertexID : SV_VertexID;
        UNITY_VERTEX_INPUT_INSTANCE_ID
    };

    struct Varyings
    {
        float4 positionCS : SV_POSITION;
        float2 texcoord   : TEXCOORD0;
		float3 worldDir : TEXCOORD1;
        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);

		float4 D = mul(_ViewProjectInverse, float4((output.texcoord.x) * 2 - 1, (output.texcoord.y) * 2 - 1, 0.5, 1));
		D.xyz /= D.w;
		D.xyz -= _WorldSpaceCameraPos;
		float4 D0 = mul(_ViewProjectInverse, float4(0, 0, 0.5, 1));
		D0.xyz /= D0.w;
		D0.xyz -= _WorldSpaceCameraPos;
		output.worldDir = D.xyz / length(D0.xyz);

        return output;
    }

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

        uint2 positionSS = input.texcoord * _ScreenSize.xy;
		float3 col = LOAD_TEXTURE2D_X(_InputTexture, positionSS).xyz;

		float depth = LOAD_TEXTURE2D_X(_CameraDepthTexture, positionSS).x;
		float eyeDepth = LinearEyeDepth(depth, _ZBufferParams);

		float3 normal = float3(1.0f, 0.0f, 0.0f);

		if (depth > 0.0f)
		{
			// Load normal and roughness.
			NormalData normalData;
			DecodeFromNormalBuffer(positionSS, normalData);
			normal = normalData.normalWS;
		}

		float3 camPosWS = GetCurrentViewPosition();
		float3 worldPos = input.worldDir * eyeDepth + camPosWS;

		float3 noiseUV = worldPos / _NoiseSize;

		float3 noiseX = tex2D(_NoiseTex, noiseUV.zy).rgb;
		float3 noiseY = tex2D(_NoiseTex, noiseUV.xz).rgb;
		float3 noiseZ = tex2D(_NoiseTex, noiseUV.xy).rgb;

		float3 blend = pow(abs(normal), _Blend);
		blend /= dot(blend, 1.0f);

		float lum = Luminance(col);

		float3 noiseCol = noiseX * blend.x + noiseY * blend.y + noiseZ * blend.z;
		float threshold = Luminance(noiseCol) + _ThresholdOffset;

		col = lum < threshold ? _DarkColor.xyz : _LightColor.xyz;

		return float4(col, 1.0f);
    }

    ENDHLSL

    SubShader
    {
        Pass
        {
            Name "Dither3D"

            ZWrite Off
            ZTest Always
            Blend Off
            Cull Off

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