Shader "Unlit/Silhouette"
{
Properties
{
// Outline.
_OutlineColor("Outline Color", Color) = (0, 0, 0, 0)
_OutlineThickness("Outline Thickness", Float) = 0.1
// Dither.
_Color("Dither Color", Color) = (0, 0 ,0, 0)
_DitherAmount("Dither Amount", Float) = 1
_AlphaClipThreshold("Dither Alpha Clip Threshold", Float) = 1
}
SubShader
{
Tags { "RenderType" = "Transparent" "Queue" = "Transparent" "RenderPipeline" = "UniversalPipeline" }
ZWrite OFF // Alot of tranparency stuff.
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
CBUFFER_START(UnityPerMaterial)
//Outline.
float4 _OutlineColor;
float _OutlineThickness;
// Dither.
float4 _Color;
float _DitherAmount;
float _AlphaClipThreshold;
CBUFFER_END
// Unlit so no need for lighting etc, but you need the screen position and normal.
struct VertexInput
{
float4 position : POSITION;
float4 screenPosition : TEXCOORD1;
};
struct VertexOutput
{
float4 position : SV_POSITION;
float4 screenPosition : TEXCOORD1;
};
struct VertexInputOutline
{
float4 position : POSITION;
float3 normal : NORMAL;
};
struct VertexOutputOutline
{
float4 position : SV_POSITION;
};
ENDHLSL
// This is the pass for the dither.
Pass
{
Blend srcAlpha OneMinusSrcAlpha
Stencil
{
Ref 1
Comp Always
Pass Replace
}
HLSLPROGRAM
#pragma vertex vertex
#pragma fragment fragment
VertexOutput vertex(VertexInput input)
{
VertexOutput output;
output.position = TransformObjectToHClip(input.position.xyz);
output.screenPosition = ComputeScreenPos(output.position);
return output;
}
float Dither(float amount, float2 screenPosition) // Controls dither.
{
float2 uv = screenPosition.xy * _ScreenParams.xy; // UV.
// This is a matrix to control the dither shape.
float DITHER_THRESHOLDS[16] =
{
1.0 / 17.0, 9.0 / 17.0, 3.0 / 17.0, 11.0 / 17.0,
13.0 / 17.0, 5.0 / 17.0, 15.0 / 17.0, 7.0 / 17.0,
4.0 / 17.0, 12.0 / 17.0, 2.0 / 17.0, 10.0 / 17.0,
16.0 / 17.0, 8.0 / 17.0, 14.0 / 17.0, 6.0 / 17.0
};
// I have no idea what this does lmao.
uint index = (uint(uv.x) % 4) * 4 + uint(uv.y) % 4;
return amount - DITHER_THRESHOLDS[index];
}
float4 fragment(VertexOutput input) : SV_Target
{
float ditherAmount = Dither(_DitherAmount, input.screenPosition.xy / input.screenPosition.w);
clip(ditherAmount - _AlphaClipThreshold); // Sets clip to remove pixels that should be transparent.
return _Color;
}
ENDHLSL
}
// Pass for the outline.
Pass
{
ZTest ON
Stencil
{
Ref 1
Comp NotEqual
}
HLSLPROGRAM
#pragma vertex vertex
#pragma fragment fragment
VertexOutputOutline vertex(VertexInputOutline input)
{
VertexOutputOutline output;
float3 normal = normalize(input.normal) * _OutlineThickness;
float3 position = input.position.xyz + normal;
output.position = TransformObjectToHClip(position);
return output;
}
float4 fragment(VertexOutputOutline input) : SV_Target
{
return _OutlineColor;
}
ENDHLSL
}
}
}