Forked from aras-p/ComputeOcclusionFromDepth.shader
Created
December 12, 2018 19:07
-
-
Save jjxtra/44a7d78683b4f20f4e349985e6d03ff0 to your computer and use it in GitHub Desktop.
Unity command buffer that modifies screenspace shadow mask
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Super small example of a command buffer based approach that modifies screenspace shadow mask. | |
1. computes (very crude & simple) SSAO from the depth buffer, after depth is rendered. | |
2. modifies screenspace shadow texture (from the main directional light), my multiplying in the SSAO term into regular shadow term. | |
3. now all objects that receive shadows also get illumination darkened by SSAO; it essentially becomes "part of the shadow" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Shader "Hidden/ComputeOcclusion" | |
{ | |
Properties | |
{ | |
_MainTex ("", 2D) = "white" {} | |
} | |
SubShader | |
{ | |
Pass | |
{ | |
Cull Off ZWrite Off ZTest Always | |
CGPROGRAM | |
#pragma vertex vert | |
#pragma fragment frag | |
#pragma target 3.0 | |
#include "UnityCG.cginc" | |
struct appdata_t { | |
float4 vertex : POSITION; | |
float2 uv : TEXCOORD0; | |
}; | |
struct v2f { | |
float4 vertex : SV_POSITION; | |
float2 uv : TEXCOORD0; | |
}; | |
v2f vert (appdata_t v) | |
{ | |
v2f o; | |
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); | |
o.uv = v.uv; | |
return o; | |
} | |
sampler2D_float _CameraDepthTexture; | |
// Fairly bad & noisy "SSAO" computation from the depth | |
// texture alone. | |
float3 normal_from_depth(float depth, float2 uv) | |
{ | |
float2 offset1 = float2(0.0,_ScreenParams.w-1); | |
float2 offset2 = float2(_ScreenParams.z-1,0.0); | |
float depth1 = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv + offset1); | |
depth1 = LinearEyeDepth (depth1); | |
float depth2 = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv + offset2); | |
depth2 = LinearEyeDepth (depth2); | |
float3 p1 = float3(offset1, depth1 - depth); | |
float3 p2 = float3(offset2, depth2 - depth); | |
float3 normal = cross(p1, p2); | |
normal.z = -normal.z; | |
return normalize(normal); | |
} | |
float rand(float2 co){ | |
return frac(sin(dot(co ,float2(12.9898,78.233))) * 43758.5453); | |
} | |
fixed4 frag (v2f i) : SV_Target | |
{ | |
const float base = 0.2; | |
const float falloff = 0.001; | |
const float radius = 0.3; | |
const int kSampleCount = 16; | |
float3 kSamples[kSampleCount] = { | |
float3( 0.5381, 0.1856,-0.4319), float3( 0.1379, 0.2486, 0.4430), | |
float3( 0.3371, 0.5679,-0.0057), float3(-0.6999,-0.0451,-0.0019), | |
float3( 0.0689,-0.1598,-0.8547), float3( 0.0560, 0.0069,-0.1843), | |
float3(-0.0146, 0.1402, 0.0762), float3( 0.0100,-0.1924,-0.0344), | |
float3(-0.3577,-0.5301,-0.4358), float3(-0.3169, 0.1063, 0.0158), | |
float3( 0.0103,-0.5869, 0.0046), float3(-0.0897,-0.4940, 0.3287), | |
float3( 0.7119,-0.0154,-0.0918), float3(-0.0533, 0.0596,-0.5411), | |
float3( 0.0352,-0.0631, 0.5460), float3(-0.4776, 0.2847,-0.0271) | |
}; | |
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv.xy); | |
depth = LinearEyeDepth (depth); | |
float3 position = float3(i.uv, depth); | |
float3 normal = normal_from_depth(depth, i.uv); | |
float3 random = normalize(float3(rand(i.uv), rand(i.uv.yx), 0)); | |
float r = radius/depth; | |
float occ = 0.0; | |
for(int i=0; i < kSampleCount; i++) | |
{ | |
float3 ray = r * reflect(kSamples[i], random); | |
float3 hemi_ray = position + sign(dot(ray,normal)) * ray; | |
float sd = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, saturate(hemi_ray.xy)); | |
sd = LinearEyeDepth (sd); | |
float diff = depth - sd; | |
occ += step(falloff, diff); | |
} | |
float ao = 1.0 - occ / kSampleCount; | |
ao += base; | |
ao *= ao; | |
return ao; | |
} | |
ENDCG | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEngine.Rendering; | |
using System.Collections.Generic; | |
public class LightCommandBufferSSAO : MonoBehaviour | |
{ | |
public Mesh m_Quad; | |
public Shader m_OcclusionShader; | |
private Material m_OcclusionMaterial; | |
public Shader m_ShadowMaskModulateShader; | |
private Material m_ShadowMaskModulateMaterial; | |
private CommandBuffer m_Buffer; | |
private CommandBuffer m_OcclusionBuffer; | |
private Light m_Light; | |
private Camera m_Camera; | |
private void Cleanup() | |
{ | |
if (m_Buffer != null) | |
m_Light.RemoveCommandBuffer (LightEvent.AfterScreenspaceMask, m_Buffer); | |
m_Buffer = null; | |
if (m_OcclusionBuffer != null && m_Camera != null) | |
m_Camera.RemoveCommandBuffer (CameraEvent.AfterDepthTexture, m_OcclusionBuffer); | |
m_OcclusionBuffer = null; | |
Object.DestroyImmediate (m_OcclusionMaterial); | |
Object.DestroyImmediate (m_ShadowMaskModulateMaterial); | |
} | |
void OnDisable() | |
{ | |
Cleanup(); | |
} | |
void OnEnable () | |
{ | |
Cleanup(); | |
m_Light = GetComponent<Light>(); | |
m_Camera = Camera.main; | |
if (!m_ShadowMaskModulateMaterial) | |
{ | |
m_ShadowMaskModulateMaterial = new Material(m_ShadowMaskModulateShader); | |
m_ShadowMaskModulateMaterial.hideFlags = HideFlags.HideAndDontSave; | |
} | |
if (!m_OcclusionMaterial) | |
{ | |
m_OcclusionMaterial = new Material(m_OcclusionShader); | |
m_OcclusionMaterial.hideFlags = HideFlags.HideAndDontSave; | |
} | |
if (m_OcclusionBuffer == null) | |
{ | |
// compute occlusion after camera's depth texture is done | |
m_OcclusionBuffer = new CommandBuffer(); | |
m_OcclusionBuffer.name = "Compute ambient occlusion"; | |
int texID = Shader.PropertyToID("_GlobalOcclusionTexture"); | |
m_OcclusionBuffer.GetTemporaryRT (texID, -1, -1, 0, FilterMode.Bilinear); | |
m_OcclusionBuffer.Blit (BuiltinRenderTextureType.CurrentActive, texID, m_OcclusionMaterial); | |
m_Camera.AddCommandBuffer (CameraEvent.AfterDepthTexture, m_OcclusionBuffer); | |
} | |
if (m_Buffer == null) | |
{ | |
// after light's screenspace shadow mask is computed, modulate it by occlusion | |
// texture | |
m_Buffer = new CommandBuffer(); | |
m_Buffer.name = "Modify screenspace mask"; | |
m_Buffer.DrawMesh(m_Quad, Matrix4x4.identity, m_ShadowMaskModulateMaterial); | |
int screenCopyID = Shader.PropertyToID("_ShadowMapCopy"); | |
m_Buffer.GetTemporaryRT (screenCopyID, -1, -1, 0, FilterMode.Bilinear); | |
m_Buffer.Blit (BuiltinRenderTextureType.CurrentActive, screenCopyID); | |
m_Light.AddCommandBuffer (LightEvent.AfterScreenspaceMask, m_Buffer); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Shader "Hidden/MultiplyShadowMaskWithOcclusion" | |
{ | |
SubShader | |
{ | |
Pass | |
{ | |
Cull Off ZWrite Off ZTest Always | |
Blend DstColor Zero | |
CGPROGRAM | |
#pragma vertex vert | |
#pragma fragment frag | |
struct appdata_t { | |
float4 vertex : POSITION; | |
float2 uv : TEXCOORD0; | |
}; | |
struct v2f { | |
float4 vertex : SV_POSITION; | |
float2 uv : TEXCOORD0; | |
}; | |
v2f vert (appdata_t v) | |
{ | |
v2f o; | |
v.vertex.xy += 0.5; | |
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); | |
o.uv = v.uv; | |
return o; | |
} | |
sampler2D _GlobalOcclusionTexture; | |
fixed4 frag (v2f i) : SV_Target | |
{ | |
fixed4 col = tex2D(_GlobalOcclusionTexture, i.uv); | |
return col; | |
} | |
ENDCG | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment