Skip to content

Instantly share code, notes, and snippets.

@NathoSteveo
Last active August 23, 2023 13:50
Show Gist options
  • Save NathoSteveo/8746734c4428e6617f74b1bf1eedecb6 to your computer and use it in GitHub Desktop.
Save NathoSteveo/8746734c4428e6617f74b1bf1eedecb6 to your computer and use it in GitHub Desktop.
[ Shadow Outlines and Shadow Colour ]
/*
███╗░░██╗░█████╗░████████╗██╗░░██╗░█████╗░  ░██████╗████████╗███████╗██╗░░░██╗███████╗░█████╗░
████╗░██║██╔══██╗╚══██╔══╝██║░░██║██╔══██╗  ██╔════╝╚══██╔══╝██╔════╝██║░░░██║██╔════╝██╔══██╗
██╔██╗██║███████║░░░██║░░░███████║██║░░██║  ╚█████╗░░░░██║░░░█████╗░░╚██╗░██╔╝█████╗░░██║░░██║
██║╚████║██╔══██║░░░██║░░░██╔══██║██║░░██║  ░╚═══██╗░░░██║░░░██╔══╝░░░╚████╔╝░██╔══╝░░██║░░██║
██║░╚███║██║░░██║░░░██║░░░██║░░██║╚█████╔╝  ██████╔╝░░░██║░░░███████╗░░╚██╔╝░░███████╗╚█████╔╝
╚═╝░░╚══╝╚═╝░░╚═╝░░░╚═╝░░░╚═╝░░╚═╝░╚════╝░  ╚═════╝░░░░╚═╝░░░╚══════╝░░░╚═╝░░░╚══════╝░╚════╝░
*/
//-------------------------------------------------------------------------------[ OPEN WORLD ]
Shader"NATHO/SHADOW_OUTLINE"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_NormalMap ("Normal Map", 2D) = "bump" {}
_OutlineColor ("Outline color", Color) = (0, 0, 0, 1)
_ShadowColour("Shadow Color", Color) = (0, 0, 0, 1)
_ShadowStrength ("Shadow Strength", Range(0, 1)) = 0.2
_ShadowStep ("Shadow Amount", Range(0, 1)) = 0.1
_ShadowDilation ("Outline Size", Range(0, 10)) = 1
}
SubShader
{
Tags
{
"RenderType" = "Opaque"
"RenderPipeline" = "UniversalPipeline"
"UniversalMaterialType" = "Lit"
"IgnoreProjector" = "True"
}
LOD 300
//[ FORWARD LIT ]
Pass
{
Name "ForwardLit"
Tags
{
"LightMode" = "UniversalForward"
}
HLSLPROGRAM
#pragma target 3.0
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS
#pragma multi_compile _ _SHADOWS_SOFT
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
struct Attributes
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 posCS : SV_POSITION;
float3 posWS : TEXCOORD0;
float3 normalWS : TEXCOORD1;
float2 uv : TEXCOORD2;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float3 _ShadowColour;
Varyings vert(Attributes IN)
{
Varyings OUT;
VertexPositionInputs vertexInput = GetVertexPositionInputs(IN.vertex);
OUT.posCS = vertexInput.positionCS;
OUT.posWS = vertexInput.positionWS;
VertexNormalInputs normalInput = GetVertexNormalInputs(IN.normal);
OUT.normalWS = normalInput.normalWS;
OUT.uv = TRANSFORM_TEX(IN.uv, _MainTex);
return OUT;
}
float _ShadowStep, _ShadowStrength, _ShadowDilation;
float3 _OutlineColor;
static float2 sobelSamplePoints[9] =
{
float2(-1, 1), float2(0, 1), float2(1, 1),
float2(-1, 0), float2(0, 0), float2(1, 0),
float2(-1, -1), float2(0, -1), float2(1, -1)
};
static float sobelXKernel[9] =
{
1, 0, -1,
2, 0, -2,
1, 0, -1
};
static float sobelYKernel[9] =
{
1, 2, 1,
0, 0, 0,
-1, -2, -1
};
// Calculate the Sobel operator of the shadowmap
float ShadowSobelOperator(float4 shadowCoord, float dilation)
{
// Get the shadowmap texel size
ShadowSamplingData shadowSamplingData = GetMainLightShadowSamplingData();
float4 shadowMap_TexelSize = shadowSamplingData.shadowmapSize;
// Initialise results
float sobelX = 0;
float sobelY = 0;
// Loop over sample points
[unroll] for (int i = 0; i < 9; i++)
{
// Sample shadowmap
float shadowImage = MainLightRealtimeShadow(float4(shadowCoord.xy + sobelSamplePoints[i] * dilation * shadowMap_TexelSize.xy, shadowCoord.zw));
// Sum the convolution values
sobelX += shadowImage * sobelXKernel[i];
sobelY += shadowImage * sobelYKernel[i];
}
// Return the magnitude
return sqrt(sobelX * sobelX + sobelY * sobelY);
}
float3 Lambert(float3 lightColor, float3 lightDir, float3 normal)
{
float NdotL = saturate(dot(normal, lightDir));
return lightColor;
}
float4 _Colour;
//[ FRAG ]
float4 frag(Varyings IN) : SV_Target
{
float4 texColor = tex2D(_MainTex, IN.uv);
float4 colour = _Colour;
//[ Calculate light direction for the main light ]
float3 lightPos = _MainLightPosition.xyz;
//[ Lambertian lighting calculation for the main light ]
float3 lightCol = Lambert(_MainLightColor * unity_LightData.z, lightPos, IN.normalWS);
uint lightsCount = GetAdditionalLightsCount();
for (int j = 0; j < lightsCount; j++)
{
Light light = GetAdditionalLight(j, IN.posWS);
lightCol += Lambert(light.color * (light.distanceAttenuation * light.shadowAttenuation), light.direction, IN.normalWS);
}
float4 shadowCoord = TransformWorldToShadowCoord(IN.posWS);
float shadowMap = MainLightRealtimeShadow(shadowCoord);
float NdotL = saturate(dot(IN.normalWS, _MainLightPosition));
float combinedShadow = min(NdotL, shadowMap);
float shadowValue = saturate(combinedShadow + _ShadowStrength);
float shadowOutlineMask = ShadowSobelOperator(shadowCoord, _ShadowDilation / pow(2, shadowCoord.w));
shadowOutlineMask *= 1.0 - smoothstep(_ShadowStep - 0.1, _ShadowStep, shadowMap);
shadowOutlineMask *= step(_ShadowStep, NdotL);
float3 coloredShadow = _ShadowColour.xyz;
float3 col = texColor.rgb * shadowValue;
col += coloredShadow * (1.0 - shadowValue);
col = lerp(col, _OutlineColor.rgb, saturate(shadowOutlineMask));
float3 finalColor = col * lightCol;
return float4(finalColor, 1);
}
//[ FRAG ]
ENDHLSL
}
//[ FORWARD LIT ]
//[ SHADOW CASTER ]
pass
{
Name "ShadowCaster"
Tags { "LightMode" = "ShadowCaster" }
ZWrite On
ZTest LEqual
ColorMask 0
HLSLPROGRAM
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#pragma vertex vert
#pragma fragment frag
struct Attributes
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct Varyings
{
float4 posCS : SV_POSITION;
};
float3 _LightDirection;
Varyings vert(Attributes IN)
{
Varyings OUT = (Varyings) 0;
VertexPositionInputs vertexInput = GetVertexPositionInputs(IN.vertex.xyz);
float3 posWS = vertexInput.positionWS;
VertexNormalInputs normalInput = GetVertexNormalInputs(IN.normal);
float3 normalWS = normalInput.normalWS;
// Shadow biased ClipSpace position
float4 positionCS = TransformWorldToHClip(ApplyShadowBias(posWS, normalWS, _LightDirection));
#if UNITY_REVERSED_Z
positionCS.z = min(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE);
#else
positionCS.z = max(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE);
#endif
OUT.posCS = positionCS;
return OUT;
}
float4 frag(Varyings IN) : SV_Target
{
return 0;
}
ENDHLSL
}
//[ SHADOW CASTER ]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment