Skip to content

Commit

Permalink
Very simple shadow mapping post processing effect.
Browse files Browse the repository at this point in the history
  • Loading branch information
przemyslawzaworski authored Oct 27, 2022
1 parent f156260 commit ee9cd9b
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 0 deletions.
59 changes: 59 additions & 0 deletions ShadowMapping.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
Very simple shadow mapping post processing effect.
In Unity Editor:
- Create New Scene;
- Add ShadowMapping component to Main Camera
- Assign "ShadowMapping" shader
- Add "3D Object/Sphere" to the hierarchy window and assign as Light in ShadowMapping component
- Add some geometry to the scene (for example terrain component)
- Play (shadows will be only visible in Game View)
- Light object now has added light camera component. Change light camera properties to change field of view etc. In scene view, see light camera frustum.
- Play with Shadow Bias parameter
*/

using UnityEngine;

public class ShadowMapping : MonoBehaviour
{
public Shader ShadowMappingShader;
public GameObject Light;
[Range(0.0f, 5.0f)] public float ShadowBias = 1.0f;
public bool InvertY = true;

private Camera _LightCamera;
private Camera _MainCamera;
private Material _Material;
private RenderTexture _RenderTexture;

void Start()
{
_LightCamera = Light.AddComponent<Camera>();
_LightCamera.renderingPath = RenderingPath.DeferredShading;
_MainCamera = this.gameObject.GetComponent<Camera>();
_MainCamera.depthTextureMode = _LightCamera.depthTextureMode = DepthTextureMode.Depth;
_Material = new Material(ShadowMappingShader);
_RenderTexture = new RenderTexture(4096, 4096, 32, RenderTextureFormat.Depth);
_RenderTexture.Create();
_LightCamera.targetTexture = _RenderTexture;
}

void OnRenderImage (RenderTexture source, RenderTexture destination)
{
_LightCamera.Render();
Matrix4x4 lightViewProjection = GL.GetGPUProjectionMatrix(_LightCamera.projectionMatrix, true) * _LightCamera.worldToCameraMatrix;
_Material.SetMatrix("_LightViewProjection", lightViewProjection);
_Material.SetFloat("_ShadowBias", ShadowBias);
_Material.SetFloat("_InvertY", System.Convert.ToSingle(InvertY));
Matrix4x4 m = GL.GetGPUProjectionMatrix(_MainCamera.projectionMatrix, false);
m[2, 3] = m[3, 2] = 0.0f; m[3, 3] = 1.0f;
Matrix4x4 projectionToWorld = Matrix4x4.Inverse(m * _MainCamera.worldToCameraMatrix) * Matrix4x4.TRS(new Vector3(0, 0, -m[2,2]), Quaternion.identity, Vector3.one);
_Material.SetMatrix("_ProjectionToWorld", projectionToWorld);
Graphics.Blit (source, destination, _Material);
}

void OnDestroy()
{
_RenderTexture.Release();
Destroy(_Material);
}
}
49 changes: 49 additions & 0 deletions ShadowMapping.shader
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
Shader "ShadowMapping"
{
Properties
{
[HideInInspector] _MainTex ("Texture", 2D) = "black" {}
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex VSMain
#pragma fragment PSMain
#pragma target 5.0

float4x4 _ProjectionToWorld, _LightViewProjection;
sampler2D _CameraDepthTexture, _LastCameraDepthTexture, _MainTex;
float _ShadowBias, _InvertY;

float4 VSMain (in float4 vertex : POSITION, inout float2 uv : TEXCOORD0, out float3 direction : TEXCOORD1) : SV_POSITION
{
float4 position = UnityObjectToClipPos(vertex);
direction = mul(_ProjectionToWorld, float4(position.xy, 0.0, 1.0)) - _WorldSpaceCameraPos;
return position;
}

void PSMain (float4 vertex : SV_POSITION, float2 uv : TEXCOORD0, float3 direction : TEXCOORD1, out float4 fragColor : SV_TARGET)
{
float sceneDepth = 1.0 / (_ZBufferParams.z * tex2D(_CameraDepthTexture, uv.xy) + _ZBufferParams.w);
float3 worldSpace = direction * sceneDepth + _WorldSpaceCameraPos;
float4 shadowCoord = mul(_LightViewProjection, float4(worldSpace, 1.0));
float2 projCoords = (shadowCoord.xy / shadowCoord.w) * 0.5 + 0.5;
float depth = (shadowCoord.z / shadowCoord.w);
if (_InvertY > 0.5f) projCoords.y = 1.0 - projCoords.y;
float closestDepth = 1.0 / (_ZBufferParams.z * tex2D(_LastCameraDepthTexture, projCoords.xy).r + _ZBufferParams.w);
float currentDepth = 1.0 / (_ZBufferParams.z * depth + _ZBufferParams.w);
float shadow = ((currentDepth - _ShadowBias) < closestDepth) || (depth > 0.5) ? 0.0 : 1.0;
float4 color = float4(1.0 - shadow.xxx, 1.0);
bool isLightFrustum = depth > 0.0;
isLightFrustum = isLightFrustum && projCoords.x >= 0.0 && projCoords.x <= 1.0;
isLightFrustum = isLightFrustum && projCoords.y >= 0.0 && projCoords.y <= 1.0;
isLightFrustum = isLightFrustum && sceneDepth <= (_ProjectionParams.z - _ProjectionParams.y);
float4 baseColor = tex2D(_MainTex, uv);
fragColor = isLightFrustum ? ((color.r > 0.5) ? baseColor * float4(1,1,1,1) : baseColor * float4(0,0,0,1)) : baseColor;
}
ENDCG
}
}
}

0 comments on commit ee9cd9b

Please sign in to comment.