Umbra with stage

This commit is contained in:
Williams
2026-08-07 15:24:54 +02:00
parent 8a5523ff54
commit 1d0ad8f26a
82 changed files with 36368 additions and 0 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3cd48523710754e7fb63556087fafce7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7997da25fef5647d2a56b20fa2942ae9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cd9666e1302f84659a44ae61cdc184c7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,124 @@
#pragma once
TEXTURE2D_X(_MainTex);
float4 _MainTex_ST;
float4 _MainTex_TexelSize;
float4 _ShadowData;
#define SHADOW_SAMPLES _ShadowData.x
#define POSTERIZATION _ShadowData.y
#define DEPTH_REJECTION _ShadowData.z
#define SHADOW_MAX_BLUR_DEPTH _ShadowData.w
float4 _ShadowData2;
#define CONTACT_STRENGTH _ShadowData2.x
#define MAX_SHADOW_SPREAD _ShadowData2.y
#define SHADOW_MAX_DEPTH _ShadowData2.z
#define LIGHT_SIZE _ShadowData2.w
float4 _ShadowData3;
#define BLUR_DEPTH_ATTEN_START _ShadowData3.x
#define BLUR_DEPTH_ATTEN_LENGTH _ShadowData3.y
#define BLUR_GRAZING_ATTEN_STRENGTH _ShadowData3.z
#define BLUR_EDGE_SHARPNESS _ShadowData3.w
float _BlurSpread;
#define BLUR_SPREAD _BlurSpread
float4 _ShadowData4;
#define OCCLUDERS_COUNT _ShadowData4.x
#define OCCLUDERS_SEARCH_RADIUS _ShadowData4.y
#define CONTACT_STRENGTH_KNEE _ShadowData4.z
#define MASK_SCALE _ShadowData4.w
float _BlurScale;
float4 _BlendCascadeData;
#define BLEND_CASCADE_DATA _BlendCascadeData
float2 _SourceSize;
float _ReceiverPlaneAltitude;
int _EarlyOutSamples;
#define dot2(x) dot(x,x)
struct AttributesSimple {
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct VaryingsSimple {
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_OUTPUT_STEREO
};
VaryingsSimple VertSimple(AttributesSimple v) {
VaryingsSimple o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.positionCS = v.positionOS;
o.positionCS.y *= _ProjectionParams.x;
o.uv = v.uv;
return o;
}
float GetLinearDepth(float2 uv) {
float rawDepth = SampleSceneDepth(uv);
float depthPersp = Linear01Depth(rawDepth, _ZBufferParams);
float depthOrtho = rawDepth;
#if UNITY_REVERSED_Z
depthOrtho = 1.0 - depthOrtho;
#endif
float depth = lerp(depthPersp, depthOrtho, unity_OrthoParams.w);
return depth;
}
float3 GetWorldPosition(float2 uv, float rawDepth) {
#if UNITY_REVERSED_Z
float depth = rawDepth;
#else
float depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, rawDepth);
#endif
float3 worldPos = ComputeWorldSpacePosition(uv, depth, UNITY_MATRIX_I_VP);
return worldPos;
}
float3 GetNormalFromWPOS(float3 wpos) {
float3 dx = ddx(wpos);
float3 dy = ddy(wpos);
float3 cr = cross(dy, dx);
float len = length(cr);
if (len == 0) {
return -UNITY_MATRIX_IT_MV[2].xyz;
}
return cr / len;
}
float3 GetNormalFromUV(float2 uv, float depth) {
float3 wpos = GetWorldPosition(uv, depth);
return GetNormalFromWPOS(wpos);
}
half InvLerp(half b, half t) {
half oneMinusT = 1 - t;
return oneMinusT + b * t;
}
bool IsSkyBox(float rawDepth) {
#if UNITY_REVERSED_Z
return rawDepth <= 0;
#else
return rawDepth >= 1;
#endif
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b4011d16d47104fac8fb0ab72211d911
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,221 @@
int _ContactShadowsSampleCount;
#define SAMPLE_COUNT _ContactShadowsSampleCount
float4 _ContactShadowsData1;
#define STEPPING _ContactShadowsData1.x
#define INTENSITY_MULTIPLIER _ContactShadowsData1.y
#define JITTER _ContactShadowsData1.z
#define DISTANCE_FADE _ContactShadowsData1.w
float4 _ContactShadowsData2;
#define CONTACT_SHADOWS_MIN_DISTANCE _ContactShadowsData2.x
#define CONTACT_SHADOWS_MIN_DISTANCE_FADE _ContactShadowsData2.y
#define CONTACT_SHADOWS_MAX_DISTANCE _ContactShadowsData2.z
#define CONTACT_SHADOWS_NORMAL_BIAS _ContactShadowsData2.w
float4 _ContactShadowsData3;
#define THICKNESS_NEAR _ContactShadowsData3.x
#define THICKNESS_DEPTH_MULTIPLIER _ContactShadowsData3.y
#define VIGNETTE_SIZE _ContactShadowsData3.z
#define BIAS _ContactShadowsData3.w
float4 _ContactShadowsData4;
#define BIAS_FAR _ContactShadowsData4.x
#define EDGE_SOFTNESS _ContactShadowsData4.y
#define SHADOWS_3D _ContactShadowsData4.z
float4 _PointLightPosition;
#if _LOOP_STEP_X3
#define LOOP_STEP 3
#elif _LOOP_STEP_X2
#define LOOP_STEP 2
#else
#define LOOP_STEP 1
#endif
#define SHADER_API_WEBGL ((SHADER_API_GLES || SHADER_API_GLES3) && SHADER_API_DESKTOP)
#if SHADER_API_MOBILE || SHADER_API_WEBGL
#define LOOP(index, count) UNITY_UNROLL for(int index=0;index<64;index+=LOOP_STEP) if (index < count) {
#else
#define LOOP(index, count) for(int index=0;index<count;index+=LOOP_STEP) {
#endif
#define END_LOOP }
inline float GetLinearDepth01(float2 uv) {
float rawDepth = SAMPLE_TEXTURE2D_X_LOD(_CameraDepthTexture, sampler_PointClamp, uv, 0).r;
float depthPersp = Linear01Depth(rawDepth, _ZBufferParams);
float depthOrtho = rawDepth;
#if UNITY_REVERSED_Z
depthOrtho = 1.0 - depthOrtho;
#endif
float depth01 = lerp(depthPersp, depthOrtho, unity_OrthoParams.w);
return depth01;
}
inline float3 GetSSCoords(float3 wpos) {
float4 pos = TransformWorldToHClip(wpos);
pos.xyz /= pos.w;
pos.y *= _ProjectionParams.x;
float3 coords = pos.xyz;
coords.xy = coords.xy * 0.5 + 0.5;
float depthPersp = Linear01Depth(coords.z, _ZBufferParams);
float depthOrtho = coords.z;
#if UNITY_REVERSED_Z
depthOrtho = 1.0 - depthOrtho;
#endif
coords.z = lerp(depthPersp, depthOrtho, unity_OrthoParams.w);
return coords;
}
half4 FragContactShadows(Varyings input) : SV_Target {
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = input.texcoord.xy;
float rawDepth = SampleSceneDepth(uv);
#if !_RECEIVER_PLANE
if (IsSkyBox(rawDepth)) return half4(0, 0, 0, 0);
#endif
float depthPersp = Linear01Depth(rawDepth, _ZBufferParams);
float depthOrtho = rawDepth;
#if UNITY_REVERSED_Z
depthOrtho = 1.0 - depthOrtho;
#endif
float depth01 = lerp(depthPersp, depthOrtho, unity_OrthoParams.w);
#if defined(CONTACT_SHADOWS_AFTER_OPAQUE)
if (depth01 >= CONTACT_SHADOWS_MAX_DISTANCE || depth01 < CONTACT_SHADOWS_MIN_DISTANCE)
return half4(0, 0, 0, 0);
#else
if (depth01 >= SHADOW_MAX_DEPTH || depth01 < CONTACT_SHADOWS_MIN_DISTANCE)
return half4(1, 0, 0, 1);
#endif
float3 wpos0 = GetWorldPosition(uv, rawDepth);
#if _NORMALS_TEXTURE
float3 norm = SampleSceneNormals(uv);
#else
float3 norm = GetNormalFromWPOS(wpos0);
#endif
wpos0 += norm * CONTACT_SHADOWS_NORMAL_BIAS;
#if _RECEIVER_PLANE
if (wpos0.y < _ReceiverPlaneAltitude) {
float3 cameraToWpos = wpos0 - _WorldSpaceCameraPos;
float t = (_ReceiverPlaneAltitude - _WorldSpaceCameraPos.y) / cameraToWpos.y;
wpos0 = _WorldSpaceCameraPos + t * cameraToWpos;
#if _NORMALS_TEXTURE
norm = float3(0, 1, 0);
#endif
}
#endif
float3 lightDirection;
#if _USE_POINT_LIGHT
_PointLightPosition.y = lerp(wpos0.y - 0.05f, _PointLightPosition.y, SHADOWS_3D);
lightDirection = normalize(_PointLightPosition.xyz - wpos0);
#else
lightDirection = _MainLightPosition.xyz;
#endif
float3 step = lightDirection * STEPPING;
half randomVal = InterleavedGradientNoise(uv * _SourceSize.xy, 0);
wpos0 += step * (randomVal * JITTER);
float bias = depth01 * lerp(BIAS, BIAS_FAR, depth01);
float thickness = THICKNESS_NEAR + depth01 * THICKNESS_DEPTH_MULTIPLIER;
float maxDist = STEPPING * SAMPLE_COUNT;
half shadow = 1.0;
half dist = 0;
#if _SOFT_EDGES
// Complex loop with edge softness
float softestShadow = 1.0;
LOOP(k, SAMPLE_COUNT)
float3 wpos = wpos0 + step * k;
float3 coords = GetSSCoords(wpos);
if (any(floor(coords.xy)!=0)) break;
float depth = GetLinearDepth01(coords.xy);
float depthDiff = coords.z - depth;
if (depthDiff > bias && depthDiff < thickness) {
// Soft edge calculation based on how close we are to the bias threshold
float edgeFade = saturate((depthDiff - bias) / (thickness * EDGE_SOFTNESS));
dist = STEPPING * k;
float distanceFade = lerp(0, DISTANCE_FADE, (float)k / SAMPLE_COUNT);
// Additional softening based on distance
float distanceSoftness = saturate(dist / (STEPPING * SAMPLE_COUNT * 0.5));
distanceFade = lerp(distanceFade, 1.0, distanceSoftness * 0.3);
float currentShadow = lerp(1.0, distanceFade, edgeFade);
softestShadow = min(softestShadow, currentShadow);
// Continue sampling for softer edges
if (edgeFade > 0.98 && k > SAMPLE_COUNT * 0.5) break;
}
END_LOOP
shadow = softestShadow;
#else
// Simple loop that exits immediately on hit
LOOP(k, SAMPLE_COUNT)
float3 wpos = wpos0 + step * k;
float3 coords = GetSSCoords(wpos);
if (any(floor(coords.xy)!=0)) break;
float depth = GetLinearDepth01(coords.xy);
float depthDiff = coords.z - depth;
if (depthDiff > bias && depthDiff < thickness) {
dist = STEPPING * k;
shadow = lerp(0, DISTANCE_FADE, (float)k / SAMPLE_COUNT);
break;
}
END_LOOP
#endif
shadow = saturate( shadow + 1.0 - saturate((depth01 - CONTACT_SHADOWS_MIN_DISTANCE) / CONTACT_SHADOWS_MIN_DISTANCE_FADE) );
// apply shadow intensity
half4 shadowParams = GetMainLightShadowParams();
if (all(shadowParams.xy == 0)) shadowParams.x = 1; // if shadows are disabled, shadowParams is not set
half shadowIntensity = shadowParams.x * INTENSITY_MULTIPLIER;
if (VIGNETTE_SIZE > 0) {
float2 screenCoord = uv * _SourceSize;
float2 distanceToEdges = min(screenCoord, _SourceSize - screenCoord);
float edgeDistance = min(distanceToEdges.x, distanceToEdges.y);
half vignette = edgeDistance / (VIGNETTE_SIZE * min(_SourceSize.x, _SourceSize.y));
vignette = saturate(vignette);
shadow = lerp(1, shadow, vignette);
}
shadow = InvLerp(shadow, shadowIntensity);
#if defined(CONTACT_SHADOWS_AFTER_OPAQUE)
return half4(0, 0, 0, 1.0 - shadow);
#else
return half4(shadow, dist, 0, 0);
#endif
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8c459ab4b3eba4c6f910b2049df58ddf
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,287 @@
TEXTURE2D_X_FLOAT(_DownsampledDepth);
float4 _DownsampledDepth_TexelSize;
half4 _OverlayShadowColor;
struct VaryingsCross {
float4 positionCS : SV_POSITION;
float2 uv: TEXCOORD0;
float2 dir : TEXCOORD1;
UNITY_VERTEX_OUTPUT_STEREO
};
VaryingsCross VertBlur(AttributesSimple v) {
VaryingsCross o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.positionCS = v.positionOS;
o.positionCS.y *= _ProjectionParams.x;
o.uv = v.uv;
#if defined(BLUR_VERT)
o.dir = float2(0, _MainTex_TexelSize.y * _BlurScale);
#else
o.dir = float2(_MainTex_TexelSize.x * _BlurScale, 0);
#endif
return o;
}
#if _BLUR_HQ
static const float weights[] = { 0.14446445, 0.13543542, 0.11153505, 0.08055309, 0.05087564, 0.02798160, 0.01332457, 0.00545096 };
#define SAMPLE_COUNT 7
#else
static const float weights[] = { 0.2270270270, 0.3162162162, 0.0702702703 };
#define SAMPLE_COUNT 2
#endif
half2 BlurShadowGaussian(VaryingsCross i, float depth) {
float2 uv = UnityStereoTransformScreenSpaceTex(i.uv);
half2 shadow = SAMPLE_TEXTURE2D_X_LOD(_MainTex, sampler_LinearClamp, uv, 0).xy;
if (depth > SHADOW_MAX_BLUR_DEPTH) return shadow;
float referenceDepth = 10.0 / _ProjectionParams.z;
float spread = BLUR_SPREAD * clamp(referenceDepth / depth, 1.0, 10.0);
#if _CONTACT_HARDENING
spread *= lerp(1, shadow.y, CONTACT_STRENGTH);
#endif
spread = clamp(spread, 0.5, 10);
half2 shadowBlur = 0;
half sum = 0.0000001;
UNITY_UNROLL
for (int index = -SAMPLE_COUNT; index <= SAMPLE_COUNT; index++) {
float2 uv = i.uv + i.dir * (index * spread);
float2 shadowN = SAMPLE_TEXTURE2D_X_LOD(_MainTex, sampler_LinearClamp, UnityStereoTransformScreenSpaceTex(uv), 0).xy;
float depthN = GetLinearDepth(uv);
float depthDiff = abs(depthN - depth);
float r2 = depthDiff * DEPTH_REJECTION;
float g = exp(-r2 * r2);
float w = g * weights[abs(index)];
shadowBlur += w * shadowN;
sum += w;
}
shadowBlur /= sum;
return shadowBlur;
}
half2 BlurShadowBox(VaryingsSimple i, float depth) {
float2 uv = UnityStereoTransformScreenSpaceTex(i.uv);
half2 shadow = SAMPLE_TEXTURE2D_X_LOD(_MainTex, sampler_LinearClamp, uv, 0).xy;
if (depth > SHADOW_MAX_BLUR_DEPTH) return shadow;
float referenceDepth = 10.0 / _ProjectionParams.z;
float spread = BLUR_SPREAD * clamp(referenceDepth / depth, 1.0, 10.0);
#if _CONTACT_HARDENING
spread *= lerp(1, shadow.y, CONTACT_STRENGTH);
#endif
spread = clamp(spread, 1, 10);
half2 shadowBlur = 0;
half sum = 0.0000001;
float2 blurSize = _MainTex_TexelSize.xy * spread;
UNITY_UNROLL
for(int y=-1;y<=1;y++) {
UNITY_UNROLL
for (int x = -1; x <= 1; x++) {
float2 uv = i.uv + float2(x,y) * blurSize;
float2 shadowN = SAMPLE_TEXTURE2D_X_LOD(_MainTex, sampler_LinearClamp, UnityStereoTransformScreenSpaceTex(uv), 0).xy;
float depthN = GetLinearDepth(uv);
float depthDiff = abs(depthN - depth);
float r2 = depthDiff * DEPTH_REJECTION;
float g = exp(-r2 * r2);
float w = g;
shadowBlur += w * shadowN;
sum += w;
}
}
shadowBlur /= sum;
return shadowBlur;
}
half4 FragBlurGaussian (VaryingsCross i): SV_Target {
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
float depth = GetLinearDepth(i.uv);
if (depth >= SHADOW_MAX_DEPTH) return 1;
half2 shadow = BlurShadowGaussian(i, depth);
return half4(shadow, 0, 0);
}
half4 FragBlurBox (VaryingsSimple i): SV_Target {
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
float depth = GetLinearDepth(i.uv);
if (depth >= SHADOW_MAX_DEPTH) return 1;
half2 shadow = BlurShadowBox(i, depth);
return half4(shadow, 0, 0);
}
half4 FragCompose (VaryingsSimple i): SV_Target {
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
float rawDepth = SampleSceneDepth(i.uv);
float depthPersp = Linear01Depth(rawDepth, _ZBufferParams);
float depthOrtho = rawDepth;
#if UNITY_REVERSED_Z
depthOrtho = 1.0 - depthOrtho;
#endif
float depth = lerp(depthPersp, depthOrtho, unity_OrthoParams.w);
if (depth >= SHADOW_MAX_DEPTH) return 1;
float2 uv = UnityStereoTransformScreenSpaceTex(i.uv);
#if _PRESERVE_EDGES
const float threshold = 0.00005;
const float t = 0.5;
float2 uv00 = UnityStereoTransformScreenSpaceTex(i.uv + _DownsampledDepth_TexelSize.xy * float2(-t, -t));
float2 uv10 = UnityStereoTransformScreenSpaceTex(i.uv + _DownsampledDepth_TexelSize.xy * float2(t, -t));
float2 uv01 = UnityStereoTransformScreenSpaceTex(i.uv + _DownsampledDepth_TexelSize.xy * float2(-t, t));
float2 uv11 = UnityStereoTransformScreenSpaceTex(i.uv + _DownsampledDepth_TexelSize.xy * float2(t, t));
float4 depths;
depths.x = SAMPLE_TEXTURE2D_X(_DownsampledDepth, sampler_PointClamp, uv00).r;
depths.y = SAMPLE_TEXTURE2D_X(_DownsampledDepth, sampler_PointClamp, uv10).r;
depths.z = SAMPLE_TEXTURE2D_X(_DownsampledDepth, sampler_PointClamp, uv01).r;
depths.w = SAMPLE_TEXTURE2D_X(_DownsampledDepth, sampler_PointClamp, uv11).r;
float4 diffs = abs(depth.xxxx - depths);
float2 minUV = UnityStereoTransformScreenSpaceTex(uv);
if (any(diffs > threshold)) {
// Check 10 vs 00
float minDiff = lerp(diffs.x, diffs.y, diffs.y < diffs.x);
minUV = lerp(uv00, uv10, diffs.y < diffs.x);
// Check against 01
minUV = lerp(minUV, uv01, diffs.z < minDiff);
minDiff = lerp(minDiff, diffs.z, diffs.z < minDiff);
// Check against 11
minUV = lerp(minUV, uv11, diffs.w < minDiff);
}
half2 shadow = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, minUV).xy;
#else
half2 shadow = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, uv).xy;
#endif
// improve shadow edge
#if _CONTACT_HARDENING
half penumbra = lerp(1.0 - BLUR_EDGE_SHARPNESS, 1.0, shadow.y);
#else
half penumbra = 1.0 - BLUR_EDGE_SHARPNESS;
#endif
half u0 = 0.5 - penumbra * 0.5;
half u1 = 0.5 + penumbra * 0.5;
// lerp between fine and smooth edge based on distance to occluder
half edged = smoothstep(u0, u1, shadow.x);
shadow.x = lerp(shadow.x, edged, BLUR_EDGE_SHARPNESS);
shadow = round(shadow * POSTERIZATION) / POSTERIZATION;
half blendingFactor = 1.0;
#if defined(COMPOSE_WITH_BLENDING)
// reduce blur with distance
blendingFactor -= saturate((depth - BLUR_DEPTH_ATTEN_START) / BLUR_DEPTH_ATTEN_LENGTH);
// under skewed view, reduce blur
if (BLUR_GRAZING_ATTEN_STRENGTH > 0) {
float3 wpos = GetWorldPosition(uv, rawDepth);
float3 viewDir = normalize(wpos - GetCameraPositionWS());
#if _NORMALS_TEXTURE
float3 norm = SampleSceneNormals(uv);
#else
float3 norm = GetNormalFromWPOS(wpos);
#endif
blendingFactor *= lerp(1, abs(dot(norm, viewDir)), BLUR_GRAZING_ATTEN_STRENGTH);
}
#endif
return half4(shadow.x, 0, 0, blendingFactor);
}
float4 FragDownsampleDepth (VaryingsSimple i): SV_Target {
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
float depth = GetLinearDepth(i.uv);
if (depth >= SHADOW_MAX_DEPTH) return 1;
return depth;
}
half4 FragComposeUnity (VaryingsSimple i): SV_Target {
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
float rawDepth = SampleSceneDepth(i.uv);
#if !_RECEIVER_PLANE
if (IsSkyBox(rawDepth)) return 1;
#endif
float2 uv = UnityStereoTransformScreenSpaceTex(i.uv);
#if _PRESERVE_EDGES
float depth = Linear01Depth(rawDepth, _ZBufferParams);
const float threshold = 0.00005;
const float t = 0.5;
float2 uv00 = UnityStereoTransformScreenSpaceTex(i.uv + _DownsampledDepth_TexelSize.xy * float2(-t, -t));
float2 uv10 = UnityStereoTransformScreenSpaceTex(i.uv + _DownsampledDepth_TexelSize.xy * float2(t, -t));
float2 uv01 = UnityStereoTransformScreenSpaceTex(i.uv + _DownsampledDepth_TexelSize.xy * float2(-t, t));
float2 uv11 = UnityStereoTransformScreenSpaceTex(i.uv + _DownsampledDepth_TexelSize.xy * float2(t, t));
float4 depths;
depths.x = SAMPLE_TEXTURE2D_X(_DownsampledDepth, sampler_PointClamp, uv00).r;
depths.y = SAMPLE_TEXTURE2D_X(_DownsampledDepth, sampler_PointClamp, uv10).r;
depths.z = SAMPLE_TEXTURE2D_X(_DownsampledDepth, sampler_PointClamp, uv01).r;
depths.w = SAMPLE_TEXTURE2D_X(_DownsampledDepth, sampler_PointClamp, uv11).r;
float4 diffs = abs(depth.xxxx - depths);
float2 minUV = UnityStereoTransformScreenSpaceTex(uv);
if (any(diffs > threshold)) {
// Check 10 vs 00
float minDiff = lerp(diffs.x, diffs.y, diffs.y < diffs.x);
minUV = lerp(uv00, uv10, diffs.y < diffs.x);
// Check against 01
minUV = lerp(minUV, uv01, diffs.z < minDiff);
minDiff = lerp(minDiff, diffs.z, diffs.z < minDiff);
// Check against 11
minUV = lerp(minUV, uv11, diffs.w < minDiff);
}
half shadow = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, minUV).x;
#else
half shadow = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, uv).x;
#endif
return half4(shadow, 0, 0, 0);
}
half4 FragDebugShadows(Varyings input) : SV_Target {
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = UnityStereoTransformScreenSpaceTex(input.texcoord.xy);
half shadow = SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_LinearClamp, uv).x;
return shadow.xxxx;
}
half4 FragOverlayShadows(Varyings input) : SV_Target {
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = UnityStereoTransformScreenSpaceTex(input.texcoord.xy);
half shadow = SAMPLE_TEXTURE2D_X(_ScreenSpaceShadowmapTexture, sampler_LinearClamp, uv).x;
return half4(1, 1, 1, 1 - shadow) * _OverlayShadowColor;
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: e319766b9a5a64e008d361eaac8a7079
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,341 @@
TEXTURE2D(_NoiseTex);
float4 _NoiseTex_TexelSize;
float4 _UmbraCascadeRects[4];
float _UmbraCascadeScales[4];
static const float2 randomOffsets[64] = {
float2(0.000000, 0.000000),
float2(-0.737277, 0.675590),
float2(0.123257, -1.408832),
float2(1.054406, 1.374128),
float2(-1.969616, -0.347296),
float2(1.885881, -1.201438),
float2(-0.633975, 2.366025),
float2(-1.221672, -2.346810),
float2(2.657852, 0.967379),
float2(-2.771639, 1.148050),
float2(1.336436, -2.865997),
float2(0.997328, 3.163121),
float2(-3.000000, -1.732051),
float2(3.520085, -0.780384),
float2(-2.146127, 3.064986),
float2(-0.505526, -3.839849),
float2(3.064178, 2.571150),
float2(-4.119181, 0.179847),
float2(3.000000, -3.000000),
float2(-0.190133, 4.354750),
float2(-2.874634, -3.425855),
float2(4.543371, 0.598146),
float2(-3.842164, 2.690312),
float2(1.038008, -4.682151),
float2(2.449490, 4.242641),
float2(-4.768585, -1.503529),
float2(4.621281, -2.154939),
float2(-1.988481, 4.800619),
float2(-1.809800, -4.972386),
float2(4.776700, 2.486592),
float2(-5.290594, 1.417610),
float2(2.991558, -4.695805),
float2(0.982302, 5.570914),
float2(-4.557468, -3.497068),
float2(5.808763, -0.508201),
float2(-3.996846, 4.361792),
float2(-0.000000, -6.000000),
float2(4.109455, 4.484683),
float2(-6.140957, -0.537264),
float2(4.954490, -3.801714),
float2(-1.098248, 6.228471),
float2(-3.440396, -5.400340),
float2(6.259915, 1.677339),
float2(-5.816519, 3.027888),
float2(2.268705, -6.233216),
float2(2.567119, 6.197572),
float2(-6.146878, -2.866337),
float2(6.538354, -2.061535),
float2(-3.464102, 6.000000),
float2(-1.515077, -6.834072),
float2(5.792280, 4.055798),
float2(-7.080333, 0.932143),
float2(4.635207, -5.524025),
float2(0.317554, 7.273181),
float2(-5.196152, -5.196152),
float2(7.409140, 0.323490),
float2(-5.732552, 4.810182),
float2(0.985451, -7.485245),
float2(4.368228, 6.238476),
float2(-7.499072, -1.662504),
float2(6.708204, -3.872983),
float2(-2.348587, 7.448768),
float2(-3.327700, -7.136275),
float2(7.333066, 3.037456)
};
#if _LOOP_STEP_X3
#define LOOP_STEP 3
#elif _LOOP_STEP_X2
#define LOOP_STEP 2
#else
#define LOOP_STEP 1
#endif
#define SHADER_API_WEBGL ((SHADER_API_GLES || SHADER_API_GLES3) && SHADER_API_DESKTOP)
#if SHADER_API_MOBILE || SHADER_API_WEBGL
#define LOOP(index, count) UNITY_UNROLL for(int index=0;index<64;index+=LOOP_STEP) if (index < count) {
#else
#define LOOP(index, count) for(int index=0;index<count;index+=LOOP_STEP) {
#endif
#define END_LOOP }
half ComputeCascadeIndexWithBlending(float3 positionWS, out half blendFactor) {
float3 fromCenter0 = positionWS - _CascadeShadowSplitSpheres0.xyz;
float3 fromCenter1 = positionWS - _CascadeShadowSplitSpheres1.xyz;
float3 fromCenter2 = positionWS - _CascadeShadowSplitSpheres2.xyz;
float3 fromCenter3 = positionWS - _CascadeShadowSplitSpheres3.xyz;
float4 distances2 = float4(dot(fromCenter0, fromCenter0), dot(fromCenter1, fromCenter1), dot(fromCenter2, fromCenter2), dot(fromCenter3, fromCenter3));
// Determine the closest cascade
half4 weights = half4(distances2 < _CascadeShadowSplitSphereRadii);
weights.yzw = saturate(weights.yzw - weights.xyz);
half cascadeIndex = 4 - dot(weights, half4(4, 3, 2, 1));
// Compute blend factor between cascades
half4 distancesToBorders = abs(distances2 - _CascadeShadowSplitSphereRadii);
half4 blendFactors = 1.0 - saturate(distancesToBorders / BLEND_CASCADE_DATA);
blendFactors *= blendFactors;
blendFactors *= 0.5;
if (blendFactors.x > blendFactors.y) {
blendFactor = blendFactors.x;
return saturate(1 - cascadeIndex);
}
if (blendFactors.y > blendFactors.z) {
blendFactor = blendFactors.y;
return clamp(3 - cascadeIndex, 1, 2);
}
blendFactor = blendFactors.z;
return clamp(5 - cascadeIndex, 2, 3);
}
float4 CustomTransformWorldToShadowCoord(float3 positionWS, out half cascadeIndex, out half blendFactor)
{
#ifdef _MAIN_LIGHT_SHADOWS_CASCADE
cascadeIndex = ComputeCascadeIndexWithBlending(positionWS, blendFactor);
#else
cascadeIndex = 0;
blendFactor = 0;
#endif
float4 shadowCoord = mul(_MainLightWorldToShadow[cascadeIndex], float4(positionWS, 1.0));
return float4(shadowCoord.xyz, 0);
}
float4 CustomTransformWorldToShadowCoord(float3 positionWS, out half cascadeIndex)
{
#ifdef _MAIN_LIGHT_SHADOWS_CASCADE
cascadeIndex = ComputeCascadeIndex(positionWS);
#else
cascadeIndex = 0;
#endif
float4 shadowCoord = mul(_MainLightWorldToShadow[cascadeIndex], float4(positionWS, 1.0));
return float4(shadowCoord.xyz, 0);
}
inline float3 InterpolateShadowmapCoord(float3 coords, float3 dx, float3 dy, float2 offset) {
return coords + dx * offset.x + dy * offset.y;
}
#if _MASK_TEXTURE
TEXTURE2D(_MaskTex);
half ComputeMaskWorldSpace(float3 wpos, float3 normalWS) {
float3 maskUV = wpos * MASK_SCALE;
half n1 = SAMPLE_TEXTURE2D(_MaskTex, sampler_LinearRepeat, maskUV.zy).r;
half n2 = SAMPLE_TEXTURE2D(_MaskTex, sampler_LinearRepeat, maskUV.xz).r;
half n3 = SAMPLE_TEXTURE2D(_MaskTex, sampler_LinearRepeat, maskUV.xy).r;
float3 triW = abs(normalWS);
float3 weights = triW / (triW.x + triW.y + triW.z);
half mask = dot(half3(n1, n2, n3), weights);
return mask;
}
#endif
half4 FragCast(Varyings input) : SV_Target {
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = input.texcoord.xy;
float rawDepth = SampleSceneDepth(uv);
#if !_RECEIVER_PLANE
if (IsSkyBox(rawDepth)) return half4(1, 0, 0, 0);
#endif
half cascadeIndex;
// normal provided by normals texture
#if _NORMALS_TEXTURE
float3 norm = SampleSceneNormals(uv);
#endif
float3 wpos = GetWorldPosition(uv, rawDepth);
#if _RECEIVER_PLANE
if (wpos.y < _ReceiverPlaneAltitude) {
float3 cameraToWpos = wpos - _WorldSpaceCameraPos;
float t = (_ReceiverPlaneAltitude - _WorldSpaceCameraPos.y) / cameraToWpos.y;
wpos = _WorldSpaceCameraPos + t * cameraToWpos;
#if _NORMALS_TEXTURE
norm = float3(0, 1, 0);
#endif
}
#endif
// compute normal at world position
#if !_NORMALS_TEXTURE
float3 norm = GetNormalFromWPOS(wpos);
#endif
// get cascade and shadowmap coordinate
#if defined(_BLEND_CASCADE)
half blendFactor;
float4 coords = CustomTransformWorldToShadowCoord(wpos, cascadeIndex, blendFactor);
if (blendFactor <= 0 || blendFactor >= 0.5) discard;
#else
float4 coords = CustomTransformWorldToShadowCoord(wpos, cascadeIndex);
#endif
if (BEYOND_SHADOW_FAR(coords)) return half4(1, 0, 0, 0);
// prepare noise
float2 pos = uv * _SourceSize;
float2 noise = normalize(SAMPLE_TEXTURE2D_LOD(_NoiseTex, sampler_PointRepeat, pos * _NoiseTex_TexelSize.xy, 0).xy - 0.5);
// pick tangent & binormal that are orthogonal to light direction
float3 v = _MainLightPosition.xyz;
v.y = abs(norm.y) < 0.9;
v = normalize(v);
float3 tangent = normalize(cross(norm, v));
float3 binormal = cross(norm, tangent);
// compute shadowmap axis coordinates for later interpolation
float3 cr0 = mul(_MainLightWorldToShadow[cascadeIndex], float4(wpos + tangent, 1.0)).xyz;
float3 cr1 = mul(_MainLightWorldToShadow[cascadeIndex], float4(wpos + binormal, 1.0)).xyz;
float3 dx = cr0 - coords.xyz;
float3 dy = cr1 - coords.xyz;
// clamp to cascade boundary
#if _MAIN_LIGHT_SHADOWS_CASCADE
float4 cascadeRect = _UmbraCascadeRects[cascadeIndex];
#endif
#if _CONTACT_HARDENING
// contact hardening
float depthAvg = 0;
float occluders = 0;
float3 dxSearch = dx * OCCLUDERS_SEARCH_RADIUS;
float3 dySearch = dy * OCCLUDERS_SEARCH_RADIUS;
#if SHADER_API_MOBILE
//UNITY_UNROLLX(32)
#endif
LOOP(i, OCCLUDERS_COUNT)
float2 offset = reflect(randomOffsets[i], noise);
float3 cr2 = InterpolateShadowmapCoord(coords.xyz, dxSearch, dySearch, offset);
#if _MAIN_LIGHT_SHADOWS_CASCADE
cr2.xy = clamp(cr2.xy, cascadeRect.xy, cascadeRect.zw);
#endif
float d = SAMPLE_TEXTURE2D_LOD(_MainLightShadowmapTexture, sampler_LinearClamp, cr2.xy, 0).x;
if (d > cr2.z) {
depthAvg += d;
occluders++;
}
END_LOOP
if (occluders < 1) return half4(1, 0, 0, 0);
depthAvg = depthAvg / occluders + 0.00001;
float distAvg = depthAvg - coords.z;
#if _MAIN_LIGHT_SHADOWS_CASCADE
distAvg *= _UmbraCascadeScales[cascadeIndex];
#endif
float smoothness = distAvg / depthAvg;
float distanceFactor = lerp(CONTACT_STRENGTH, MAX_SHADOW_SPREAD, saturate(distAvg / CONTACT_STRENGTH_KNEE) * smoothness) * LIGHT_SIZE;
#else
float distanceFactor = LIGHT_SIZE;
#endif
// compute shadow term
dx *= distanceFactor;
dy *= distanceFactor;
half shadow = 0;
half samples = 0;
#if SHADER_API_MOBILE
//SHADOW_SAMPLES = min(SHADOW_SAMPLES, 32);
//UNITY_UNROLLX(32)
#endif
LOOP(j, SHADOW_SAMPLES)
float2 offset = reflect(randomOffsets[j], noise);
float3 cr2 = InterpolateShadowmapCoord(coords.xyz, dx, dy, offset);
#if _MAIN_LIGHT_SHADOWS_CASCADE
cr2.xy = clamp(cr2.xy, cascadeRect.xy, cascadeRect.zw);
#endif
shadow += SAMPLE_TEXTURE2D_SHADOW(_MainLightShadowmapTexture, sampler_MainLightShadowmapTexture, cr2);
samples++;
if (samples > _EarlyOutSamples && (shadow <= 0 || shadow >= samples)) break;
END_LOOP
shadow /= samples;
#if _MASK_TEXTURE
half mask = ComputeMaskWorldSpace(wpos, norm);
shadow = saturate(shadow + mask);
#endif
// apply shadow intensity
half4 shadowParams = GetMainLightShadowParams();
half shadowIntensity = shadowParams.x;
shadow = InvLerp(shadow, shadowIntensity);
// output with alpha if cascade blending is used
#if defined(_BLEND_CASCADE)
return half4(shadow, distanceFactor, 0, blendFactor);
#else
return half4(shadow, distanceFactor, 0, 1);
#endif
}
half4 FragUnityShadows(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
#if UNITY_REVERSED_Z
float deviceDepth = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_PointClamp, input.texcoord.xy).r;
#else
float deviceDepth = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_PointClamp, input.texcoord.xy).r;
deviceDepth = deviceDepth * 2.0 - 1.0;
#endif
//Fetch shadow coordinates for cascade.
float3 wpos = ComputeWorldSpacePosition(input.texcoord.xy, deviceDepth, unity_MatrixInvVP);
float4 coords = TransformWorldToShadowCoord(wpos);
// Screenspace shadowmap is only used for directional lights which use orthogonal projection.
half realtimeShadow = MainLightRealtimeShadow(coords);
return realtimeShadow;
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: ec87f1a05845843d3bb05b576314b62a
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6c3132133fcd34506aa421c69014901d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,15 @@
#ifndef UMBRA_SHADOW_FUNCTIONS_INCLUDED
#define UMBRA_SHADOW_FUNCTIONS_INCLUDED
#if defined(SHADERGRAPH_PREVIEW) || !defined(_MAIN_LIGHT_SHADOWS_SCREEN)
void GetMainShadow_float(float3 worldPos, out half shadowAtten){
shadowAtten = 1;
}
#else
void GetMainShadow_float(float3 worldPos, out half shadowAtten){
float4 shadowCoord = ComputeScreenPos(TransformWorldToHClip(worldPos));
shadowAtten = SampleScreenSpaceShadowmap(shadowCoord);
}
#endif
#endif // UMBRA_SHADOW_FUNCTIONS_INCLUDED
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 97b280ff217a64e4fbf524cc3adf374a
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,804 @@
{
"m_SGVersion": 3,
"m_Type": "UnityEditor.ShaderGraph.GraphData",
"m_ObjectId": "313d9d1fe28a4561bfcd174269782ca6",
"m_Properties": [
{
"m_Id": "5f2fa682a67d4b9bb3ce0c032b99524c"
}
],
"m_Keywords": [],
"m_Dropdowns": [],
"m_CategoryData": [
{
"m_Id": "fbc63f3198b944c0ae62acc54dfb7583"
}
],
"m_Nodes": [
{
"m_Id": "9a45fa2786da4e9a8880b2416e884c1f"
},
{
"m_Id": "792ce8177b4b40f2b49db74b402ef06f"
},
{
"m_Id": "745ea9abdb724f25952d4740bf30c020"
},
{
"m_Id": "533b2f26ee9a43fdaa385258dc054356"
},
{
"m_Id": "15e6e2478d6b4b82aff4190884ad03de"
},
{
"m_Id": "0d8b270b1d8f40d8ac19121eb472db47"
},
{
"m_Id": "0e1e3ddeb5424df7a0afa5fe3064b5fb"
},
{
"m_Id": "046e55d7fa1f4aca841e660634642385"
},
{
"m_Id": "dc71a03354764aa4b2793dcec9e02920"
}
],
"m_GroupDatas": [],
"m_StickyNoteDatas": [],
"m_Edges": [
{
"m_OutputSlot": {
"m_Node": {
"m_Id": "046e55d7fa1f4aca841e660634642385"
},
"m_SlotId": 0
},
"m_InputSlot": {
"m_Node": {
"m_Id": "533b2f26ee9a43fdaa385258dc054356"
},
"m_SlotId": 0
}
},
{
"m_OutputSlot": {
"m_Node": {
"m_Id": "0d8b270b1d8f40d8ac19121eb472db47"
},
"m_SlotId": 0
},
"m_InputSlot": {
"m_Node": {
"m_Id": "15e6e2478d6b4b82aff4190884ad03de"
},
"m_SlotId": 0
}
},
{
"m_OutputSlot": {
"m_Node": {
"m_Id": "15e6e2478d6b4b82aff4190884ad03de"
},
"m_SlotId": 1
},
"m_InputSlot": {
"m_Node": {
"m_Id": "dc71a03354764aa4b2793dcec9e02920"
},
"m_SlotId": 0
}
},
{
"m_OutputSlot": {
"m_Node": {
"m_Id": "dc71a03354764aa4b2793dcec9e02920"
},
"m_SlotId": 1
},
"m_InputSlot": {
"m_Node": {
"m_Id": "0e1e3ddeb5424df7a0afa5fe3064b5fb"
},
"m_SlotId": 0
}
}
],
"m_VertexContext": {
"m_Position": {
"x": 165.0,
"y": 184.0
},
"m_Blocks": [
{
"m_Id": "9a45fa2786da4e9a8880b2416e884c1f"
},
{
"m_Id": "792ce8177b4b40f2b49db74b402ef06f"
},
{
"m_Id": "745ea9abdb724f25952d4740bf30c020"
}
]
},
"m_FragmentContext": {
"m_Position": {
"x": 165.0,
"y": 401.0
},
"m_Blocks": [
{
"m_Id": "533b2f26ee9a43fdaa385258dc054356"
},
{
"m_Id": "0e1e3ddeb5424df7a0afa5fe3064b5fb"
}
]
},
"m_PreviewData": {
"serializedMesh": {
"m_SerializedMesh": "{\"mesh\":{\"instanceID\":0}}",
"m_Guid": ""
},
"preventRotation": false
},
"m_Path": "Shader Graphs",
"m_GraphPrecision": 1,
"m_PreviewMode": 2,
"m_OutputNode": {
"m_Id": ""
},
"m_SubDatas": [],
"m_ActiveTargets": [
{
"m_Id": "e36cc0dd20a44f22923e392b9bfccc84"
}
]
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.PropertyNode",
"m_ObjectId": "046e55d7fa1f4aca841e660634642385",
"m_Group": {
"m_Id": ""
},
"m_Name": "Property",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": -239.0000457763672,
"y": 183.99993896484376,
"width": 147.0,
"height": 34.00004577636719
}
},
"m_Slots": [
{
"m_Id": "7459cf9619dd4269918e7e62a14828e4"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_Property": {
"m_Id": "5f2fa682a67d4b9bb3ce0c032b99524c"
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
"m_ObjectId": "073a43107aba4af6b619005c8ec766ea",
"m_Id": 0,
"m_DisplayName": "Alpha",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Alpha",
"m_StageCapability": 2,
"m_Value": 1.0,
"m_DefaultValue": 1.0,
"m_Labels": []
}
{
"m_SGVersion": 1,
"m_Type": "UnityEditor.ShaderGraph.PositionNode",
"m_ObjectId": "0d8b270b1d8f40d8ac19121eb472db47",
"m_Group": {
"m_Id": ""
},
"m_Name": "Position",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": -1064.0,
"y": 257.9999694824219,
"width": 208.0,
"height": 314.4999694824219
}
},
"m_Slots": [
{
"m_Id": "fe302a6ca1e9493d92edbeb37dd9d398"
}
],
"synonyms": [
"location"
],
"m_Precision": 1,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 2,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_Space": 2,
"m_PositionSource": 0
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
"m_ObjectId": "0e1e3ddeb5424df7a0afa5fe3064b5fb",
"m_Group": {
"m_Id": ""
},
"m_Name": "SurfaceDescription.Alpha",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": 0.0,
"y": 0.0,
"width": 0.0,
"height": 0.0
}
},
"m_Slots": [
{
"m_Id": "073a43107aba4af6b619005c8ec766ea"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_SerializedDescriptor": "SurfaceDescription.Alpha"
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot",
"m_ObjectId": "13ee747054f84538ba3da482273283c7",
"m_Id": 0,
"m_DisplayName": "Base Color",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "BaseColor",
"m_StageCapability": 2,
"m_Value": {
"x": 0.5,
"y": 0.5,
"z": 0.5
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": [],
"m_ColorMode": 0,
"m_DefaultColor": {
"r": 0.5,
"g": 0.5,
"b": 0.5,
"a": 1.0
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
"m_ObjectId": "14b5565b46d3477daee496d9ab92b620",
"m_Id": 1,
"m_DisplayName": "attenuation",
"m_SlotType": 1,
"m_Hidden": false,
"m_ShaderOutputName": "attenuation",
"m_StageCapability": 3,
"m_Value": 0.0,
"m_DefaultValue": 0.0,
"m_Labels": []
}
{
"m_SGVersion": 1,
"m_Type": "UnityEditor.ShaderGraph.CustomFunctionNode",
"m_ObjectId": "15e6e2478d6b4b82aff4190884ad03de",
"m_Group": {
"m_Id": ""
},
"m_Name": "GetMainShadow (Custom Function)",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": -802.5,
"y": 262.0000305175781,
"width": 262.5,
"height": 277.9999694824219
}
},
"m_Slots": [
{
"m_Id": "a8408df2e5c84a1380869614a19939c2"
},
{
"m_Id": "14b5565b46d3477daee496d9ab92b620"
}
],
"synonyms": [
"code",
"HLSL"
],
"m_Precision": 1,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_SourceType": 0,
"m_FunctionName": "GetMainShadow",
"m_FunctionSource": "97b280ff217a64e4fbf524cc3adf374a",
"m_FunctionBody": "Enter function body here..."
}
{
"m_SGVersion": 2,
"m_Type": "UnityEditor.Rendering.Universal.ShaderGraph.UniversalUnlitSubTarget",
"m_ObjectId": "16533883a7c0489eaecf612ab54498ff"
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.DynamicVectorMaterialSlot",
"m_ObjectId": "26741a9638224fc6bcd1bfa42507da22",
"m_Id": 0,
"m_DisplayName": "In",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "In",
"m_StageCapability": 3,
"m_Value": {
"x": 1.0,
"y": 1.0,
"z": 1.0,
"w": 1.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0,
"w": 0.0
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
"m_ObjectId": "533b2f26ee9a43fdaa385258dc054356",
"m_Group": {
"m_Id": ""
},
"m_Name": "SurfaceDescription.BaseColor",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": 0.0,
"y": 0.0,
"width": 0.0,
"height": 0.0
}
},
"m_Slots": [
{
"m_Id": "13ee747054f84538ba3da482273283c7"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_SerializedDescriptor": "SurfaceDescription.BaseColor"
}
{
"m_SGVersion": 3,
"m_Type": "UnityEditor.ShaderGraph.Internal.ColorShaderProperty",
"m_ObjectId": "5f2fa682a67d4b9bb3ce0c032b99524c",
"m_Guid": {
"m_GuidSerialized": "e3787be8-4877-4493-8455-7d929ee3a994"
},
"m_Name": "ShadowColor",
"m_DefaultRefNameVersion": 1,
"m_RefNameGeneratedByDisplayName": "ShadowColor",
"m_DefaultReferenceName": "_ShadowColor",
"m_OverrideReferenceName": "",
"m_GeneratePropertyBlock": true,
"m_UseCustomSlotLabel": false,
"m_CustomSlotLabel": "",
"m_DismissedVersion": 0,
"m_Precision": 0,
"overrideHLSLDeclaration": false,
"hlslDeclarationOverride": 0,
"m_Hidden": false,
"m_Value": {
"r": 0.0,
"g": 0.0,
"b": 0.0,
"a": 0.0
},
"isMainColor": false,
"m_ColorMode": 0
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot",
"m_ObjectId": "7459cf9619dd4269918e7e62a14828e4",
"m_Id": 0,
"m_DisplayName": "ShadowColor",
"m_SlotType": 1,
"m_Hidden": false,
"m_ShaderOutputName": "Out",
"m_StageCapability": 3,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0,
"w": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0,
"w": 0.0
},
"m_Labels": []
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
"m_ObjectId": "745ea9abdb724f25952d4740bf30c020",
"m_Group": {
"m_Id": ""
},
"m_Name": "VertexDescription.Tangent",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": 0.0,
"y": 0.0,
"width": 0.0,
"height": 0.0
}
},
"m_Slots": [
{
"m_Id": "8be0770c35914fe2951ec373bae178ed"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_SerializedDescriptor": "VertexDescription.Tangent"
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
"m_ObjectId": "792ce8177b4b40f2b49db74b402ef06f",
"m_Group": {
"m_Id": ""
},
"m_Name": "VertexDescription.Normal",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": 0.0,
"y": 0.0,
"width": 0.0,
"height": 0.0
}
},
"m_Slots": [
{
"m_Id": "c900a2e48237468ba5e76c3677280076"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_SerializedDescriptor": "VertexDescription.Normal"
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.TangentMaterialSlot",
"m_ObjectId": "8be0770c35914fe2951ec373bae178ed",
"m_Id": 0,
"m_DisplayName": "Tangent",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Tangent",
"m_StageCapability": 1,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": [],
"m_Space": 0
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
"m_ObjectId": "9a45fa2786da4e9a8880b2416e884c1f",
"m_Group": {
"m_Id": ""
},
"m_Name": "VertexDescription.Position",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": 0.0,
"y": 0.0,
"width": 0.0,
"height": 0.0
}
},
"m_Slots": [
{
"m_Id": "df25a6de5fd648879475811c09b1810a"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_SerializedDescriptor": "VertexDescription.Position"
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot",
"m_ObjectId": "a8408df2e5c84a1380869614a19939c2",
"m_Id": 0,
"m_DisplayName": "worldPos",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "worldPos",
"m_StageCapability": 3,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": []
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot",
"m_ObjectId": "c900a2e48237468ba5e76c3677280076",
"m_Id": 0,
"m_DisplayName": "Normal",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Normal",
"m_StageCapability": 1,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": [],
"m_Space": 0
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.DynamicVectorMaterialSlot",
"m_ObjectId": "d364eb86aab34fd08179bcb500ede32c",
"m_Id": 1,
"m_DisplayName": "Out",
"m_SlotType": 1,
"m_Hidden": false,
"m_ShaderOutputName": "Out",
"m_StageCapability": 3,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0,
"w": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0,
"w": 0.0
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.OneMinusNode",
"m_ObjectId": "dc71a03354764aa4b2793dcec9e02920",
"m_Group": {
"m_Id": ""
},
"m_Name": "One Minus",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": -487.0000305175781,
"y": 262.0000305175781,
"width": 208.0,
"height": 277.9999694824219
}
},
"m_Slots": [
{
"m_Id": "26741a9638224fc6bcd1bfa42507da22"
},
{
"m_Id": "d364eb86aab34fd08179bcb500ede32c"
}
],
"synonyms": [
"complement",
"invert",
"opposite"
],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.PositionMaterialSlot",
"m_ObjectId": "df25a6de5fd648879475811c09b1810a",
"m_Id": 0,
"m_DisplayName": "Position",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Position",
"m_StageCapability": 1,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": [],
"m_Space": 0
}
{
"m_SGVersion": 1,
"m_Type": "UnityEditor.Rendering.Universal.ShaderGraph.UniversalTarget",
"m_ObjectId": "e36cc0dd20a44f22923e392b9bfccc84",
"m_Datas": [],
"m_ActiveSubTarget": {
"m_Id": "16533883a7c0489eaecf612ab54498ff"
},
"m_AllowMaterialOverride": false,
"m_SurfaceType": 1,
"m_ZTestMode": 4,
"m_ZWriteControl": 0,
"m_AlphaMode": 0,
"m_RenderFace": 0,
"m_AlphaClip": false,
"m_CastShadows": false,
"m_ReceiveShadows": false,
"m_SupportsLODCrossFade": false,
"m_CustomEditorGUI": "",
"m_SupportVFX": false
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.CategoryData",
"m_ObjectId": "fbc63f3198b944c0ae62acc54dfb7583",
"m_Name": "",
"m_ChildObjectList": [
{
"m_Id": "5f2fa682a67d4b9bb3ce0c032b99524c"
}
]
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector3MaterialSlot",
"m_ObjectId": "fe302a6ca1e9493d92edbeb37dd9d398",
"m_Id": 0,
"m_DisplayName": "Out",
"m_SlotType": 1,
"m_Hidden": false,
"m_ShaderOutputName": "Out",
"m_StageCapability": 3,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": []
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 2653b59b7388e4f53806f4ab964d71c8
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3}
@@ -0,0 +1,135 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Transparent Floor
m_Shader: {fileID: -6465566751694194690, guid: 2653b59b7388e4f53806f4ab964d71c8,
type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: 3000
stringTagMap: {}
disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 10
- _DstBlendAlpha: 10
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueControl: 0
- _QueueOffset: 0
- _ReceiveShadows: 0
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 1
- _WorkflowMode: 1
- _ZWrite: 0
m_Colors:
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _ShadowColor: {r: 0.028301895, g: 0.028301895, b: 0.028301895, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
--- !u!114 &4464394433452166678
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier:
version: 7
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a2dfb70d5172b43e29db28656b0948e5
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,219 @@
Shader "Hidden/Kronnect/UmbraScreenSpaceShadows"
{
Properties {
// _MainTex ("Main Tex", 2D) = "white" {}
// _Color ("Color", Color) = (1, 1, 1, 1)
[NoScaleoffset] _NoiseTex("Noise Tex", 2D) = "white" {}
_ContactShadowsBlend ("Contact Shadows Blend", Int) = 10 // OneMinusSrcAlpha
}
SubShader
{
Tags{ "RenderPipeline" = "UniversalPipeline" "IgnoreProjector" = "True"}
ZTest Always ZWrite Off Cull Off
HLSLINCLUDE
#pragma target 3.0
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ImageBasedLighting.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareNormalsTexture.hlsl"
#include "Common.hlsl"
ENDHLSL
Pass
{
Name "Umbra Shadows"
HLSLPROGRAM
#pragma multi_compile _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile_fragment _ _GBUFFER_NORMALS_OCT
#pragma multi_compile_local_fragment _ _NORMALS_TEXTURE
#pragma multi_compile_local_fragment _ _CONTACT_HARDENING
#pragma multi_compile_local_fragment _ _LOOP_STEP_X2 _LOOP_STEP_X3
#pragma multi_compile_local_fragment _ _MASK_TEXTURE
#pragma multi_compile_local_fragment _ _RECEIVER_PLANE
#pragma vertex Vert
#pragma fragment FragCast
#include "ShadowCast.hlsl"
ENDHLSL
}
Pass
{
Name "Blur Horiz"
HLSLPROGRAM
#pragma multi_compile_local_fragment _ _BLUR_HQ
#pragma multi_compile_local_fragment _ _CONTACT_HARDENING
#pragma vertex VertBlur
#pragma fragment FragBlurGaussian
#include "ShadowBlur.hlsl"
ENDHLSL
}
Pass
{
Name "Blur Vert"
HLSLPROGRAM
#pragma multi_compile_local_fragment _ _BLUR_HQ
#pragma multi_compile_local_fragment _ _CONTACT_HARDENING
#pragma vertex VertBlur
#pragma fragment FragBlurGaussian
#define BLUR_VERT
#include "ShadowBlur.hlsl"
ENDHLSL
}
Pass
{
Name "Box Blur"
HLSLPROGRAM
#pragma multi_compile_local_fragment _ _CONTACT_HARDENING
#pragma vertex VertSimple
#pragma fragment FragBlurBox
#define BOX_BLUR
#include "ShadowBlur.hlsl"
ENDHLSL
}
Pass
{
Name "Compose with Blending"
Blend SrcAlpha OneMinusSrcAlpha
HLSLPROGRAM
#pragma multi_compile_local_fragment _ _PRESERVE_EDGES
#pragma multi_compile_local_fragment _ _NORMALS_TEXTURE
#pragma multi_compile_fragment _ _GBUFFER_NORMALS_OCT
#pragma vertex VertSimple
#pragma fragment FragCompose
#define COMPOSE_WITH_BLENDING
#include "ShadowBlur.hlsl"
ENDHLSL
}
Pass
{
Name "Downsample Depth"
HLSLPROGRAM
#pragma vertex VertSimple
#pragma fragment FragDownsampleDepth
#include "ShadowBlur.hlsl"
ENDHLSL
}
Pass
{
Name "Umbra Cascade Blending"
Blend SrcAlpha OneMinusSrcAlpha
HLSLPROGRAM
#pragma multi_compile _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile_fragment _ _GBUFFER_NORMALS_OCT
#pragma multi_compile_local_fragment _ _NORMALS_TEXTURE
#pragma multi_compile_local_fragment _ _CONTACT_HARDENING
#pragma multi_compile_local_fragment _ _LOOP_STEP_X2 _LOOP_STEP_X3
#pragma multi_compile_local_fragment _ _MASK_TEXTURE
#define _BLEND_CASCADE
#pragma vertex Vert
#pragma fragment FragCast
#include "ShadowCast.hlsl"
ENDHLSL
}
Pass
{
Name "ScreenSpaceShadows"
HLSLPROGRAM
#pragma multi_compile _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile_fragment _ _SHADOWS_SOFT _SHADOWS_SOFT_LOW _SHADOWS_SOFT_MEDIUM _SHADOWS_SOFT_HIGH
#pragma vertex Vert
#pragma fragment FragUnityShadows
#include "ShadowCast.hlsl"
ENDHLSL
}
Pass
{
Name "Compose Unity Shadows"
HLSLPROGRAM
#pragma multi_compile_local_fragment _ _PRESERVE_EDGES
#pragma vertex VertSimple
#pragma fragment FragComposeUnity
#include "ShadowBlur.hlsl"
ENDHLSL
}
Pass
{
Name "Contact Shadows"
Blend One One
BlendOp Min
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment FragContactShadows
#pragma multi_compile_local_fragment _ _LOOP_STEP_X2 _LOOP_STEP_X3
#pragma multi_compile_local_fragment _ _NORMALS_TEXTURE
#pragma multi_compile_local_fragment _ _RECEIVER_PLANE
#pragma multi_compile_local_fragment _ _USE_POINT_LIGHT
#pragma multi_compile_local_fragment _ _SOFT_EDGES
#include "ContactShadows.hlsl"
ENDHLSL
}
Pass
{
Name "Compose"
HLSLPROGRAM
#pragma multi_compile_local_fragment _ _PRESERVE_EDGES
#pragma vertex VertSimple
#pragma fragment FragCompose
#include "ShadowBlur.hlsl"
ENDHLSL
}
Pass
{
Name "Debug Shadows"
HLSLPROGRAM
#pragma multi_compile_local_fragment _ _PRESERVE_EDGES
#pragma vertex Vert
#pragma fragment FragDebugShadows
#include "ShadowBlur.hlsl"
ENDHLSL
}
Pass
{
Name "Contact Shadows After Opaque"
Blend SrcAlpha [_ContactShadowsBlend]
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment FragContactShadows
#pragma multi_compile_local_fragment _ _LOOP_STEP_X2 _LOOP_STEP_X3
#pragma multi_compile_local_fragment _ _NORMALS_TEXTURE
#pragma multi_compile_local_fragment _ _RECEIVER_PLANE
#pragma multi_compile_local_fragment _ _USE_POINT_LIGHT
#pragma multi_compile_local_fragment _ _SOFT_EDGES
#define CONTACT_SHADOWS_AFTER_OPAQUE
#include "ContactShadows.hlsl"
ENDHLSL
}
Pass
{
Name "Overlay Shadows"
Blend SrcAlpha OneMinusSrcAlpha
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment FragOverlayShadows
#include "ShadowBlur.hlsl"
ENDHLSL
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: d461f5567983941438cff09455e8b8f4
ShaderImporter:
externalObjects: {}
defaultTextures:
- _BlueNoise: {fileID: 2800000, guid: e48811f1a66574b199fbc047d7139f79, type: 3}
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2b377dac2021c4e30923e01c90299f79
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,140 @@
fileFormatVersion: 2
guid: 32293bd0d9827458cb949a5cc32b3027
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 0
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 0
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 1
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 1
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 728e006b190ca466b95d89b38279a52f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,75 @@
using System.Collections.Generic;
using UnityEngine;
namespace Umbra {
[RequireComponent(typeof(Light))]
[ExecuteAlways]
[HelpURL("https://kronnect.com/docs/umbra/")]
public class UmbraPointLightContactShadows : MonoBehaviour {
public BoxCollider boxCollider;
public float fadeDistance = 1f;
public static readonly Dictionary<Light, UmbraPointLightContactShadows> umbraPointLights = new Dictionary<Light, UmbraPointLightContactShadows>();
Light attachedLight;
void OValidate () {
fadeDistance = Mathf.Max(fadeDistance, 0f);
}
private void OnEnable() {
attachedLight = GetComponent<Light>();
if (attachedLight == null) {
Debug.LogError("UmbraPointLightContactShadows requires a Light component on the same GameObject.");
return;
}
if (attachedLight.type != LightType.Point) {
Debug.LogWarning("UmbraPointLightContactShadows is designed for Point lights but found " + attachedLight.type + " light.");
return;
}
// Initialize or get the BoxCollider
boxCollider = GetComponent<BoxCollider>();
if (boxCollider == null) {
boxCollider = gameObject.AddComponent<BoxCollider>();
boxCollider.isTrigger = true;
boxCollider.size = Vector3.one * 20f;
}
umbraPointLights[attachedLight] = this;
}
private void OnDisable() {
if (attachedLight != null) {
umbraPointLights.Remove(attachedLight);
}
}
/// <summary>
/// Check if a world position is inside this point light's volume
/// </summary>
/// <param name="worldPosition">World space position to check</param>
/// <returns>True if the position is inside the volume</returns>
public float ComputeVolumeFade(Vector3 worldPosition) {
if (boxCollider == null) return 0;
Bounds bounds = boxCollider.bounds;
Vector3 diff = bounds.center - worldPosition;
diff.x = diff.x < 0 ? -diff.x : diff.x;
diff.y = diff.y < 0 ? -diff.y : diff.y;
diff.z = diff.z < 0 ? -diff.z : diff.z;
Vector3 gap = diff - bounds.extents;
float maxDiff = gap.x > gap.y ? gap.x : gap.y;
maxDiff = maxDiff > gap.z ? maxDiff : gap.z;
return 1f - Mathf.Clamp01(maxDiff / (fadeDistance + 0.0001f));
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,351 @@
using UnityEngine;
namespace Umbra {
public enum ShadowSource {
UnityShadows,
UmbraShadows,
OnlyContactShadows
}
public enum ContactShadowsInjectionPoint {
ShadowTexture,
AfterOpaque
}
public enum UmbraPreset {
[InspectorName("")]
None = 0,
Hard = 10,
Soft = 20,
Smooth = 30,
ExtraSmooth = 40,
Blurred = 50,
Fast = 60
}
public enum BlurType {
[InspectorName("Gaussian (15 taps, 2 passes)")]
Gaussian15 = 10,
[InspectorName("Gaussian (5 taps, 2 passes)")]
Gaussian5 = 20,
[InspectorName("Box Blur (9 taps, 1 pass)")]
Box = 30
}
public enum NormalSource {
ReconstructFromDepth,
NormalsPass,
[InspectorName("GBuffer Normals")]
GBufferNormals
}
public enum LoopStep {
Default,
x2,
x3
}
public enum Style {
Default,
Textured
}
[CreateAssetMenu(fileName = "UmbraProfile", menuName = "Umbra Profile", order = 251)]
[HelpURL("https://kronnect.com/docs/umbra/")]
public class UmbraProfile : ScriptableObject {
[Tooltip("Which shadow generation system should be used")]
public ShadowSource shadowSource = ShadowSource.UmbraShadows;
[Tooltip("Translates to the number of shadow map samples used to resolve shadows")]
[Range(1, 64)]
public int sampleCount = 16;
[Tooltip("Number of samples to early out if shadow is already fully resolved")]
[Range(1, 64)]
public int earlyOutSamples = 32;
[Tooltip("Size of the directional light which influences the penumbra size")]
[Range(0f, 32)]
public float lightSize = 6;
[Tooltip("Makes shadows sharper nearer to the occluder")]
public bool enableContactHardening = true;
[Tooltip("Makes shadows sharper and stronger near the occluder")]
[Range(0, 1)]
public float contactStrength = 0.5f;
[Tooltip("Usual value is 5. Modify to alter the shadow edge appearance.")]
public float contactStrengthKnee = 0.0001f;
[Tooltip("Makes shadows smoother when far from occluder")]
[Range(1, 16)]
public float distantSpread = 1f;
[Tooltip("Number of shadow map samples to find occluders which improve the penumbra radius calculation")]
[Range(1, 64)]
public int occludersCount = 8;
[Tooltip("Multiplier to the occluder search radius in texture space. A higher value creates more diffused penumbra.")]
public float occludersSearchRadius = 8f;
[Tooltip("Number of blur passes. Each blur pass increases shadow softness but reduces performance.")]
[Range(0, 3)]
public int blurIterations;
[Tooltip("Specifies the blur method. Gaussian blur uses two passes per iteration and produces smoother results.")]
public BlurType blurType = BlurType.Gaussian15;
[Tooltip("Blur kerner radius multiplier. Improves softness but can introduce artifacts")]
[Range(0.5f, 5)]
public float blurSpread = 1f;
[Tooltip("Increases the contrast on the shadow border to create sharper shadows when blur is used")]
[Range(0, 1)]
public float blurEdgeSharpness;
[Tooltip("Strength of the edge weight when blurring")]
public float blurEdgeTolerance = 5f;
[Tooltip("Reduces blur on distance from camera")]
public float blurDepthAttenStart = 50;
[Tooltip("Blur reduction intensity")]
public float blurDepthAttenLength = 50;
[Tooltip("Blur reduction when viewing shadow from a grazing angle")]
[Range(0, 1)]
public float blurGrazingAttenuation;
public bool blendCascades;
[Range(1, 10)]
public int posterization = 1;
public float cascade1BlendingStrength = 0.1f;
public float cascade2BlendingStrength = 0.1f;
public float cascade3BlendingStrength = 0.1f;
[Tooltip("Manual adjustment of shadow smoothness multiplier for this cascade")]
public float cascade1Scale = 1f;
[Tooltip("Manual adjustment of shadow smoothness multiplier for this cascade")]
public float cascade2Scale = 1f;
[Tooltip("Manual adjustment of shadow smoothness multiplier for this cascade")]
public float cascade3Scale = 1f;
[Tooltip("Manual adjustment of shadow smoothness multiplier for this cascade")]
public float cascade4Scale = 1f;
[Tooltip("Method used to obtain surface normals. Reconstruct from depth is fastest, normals pass is more accurate, and GBuffer normals (deferred only) uses existing GBuffer data.")]
public NormalSource normalsSource = NormalSource.ReconstructFromDepth;
/// <summary>
/// Gets the effective normals source, falling back to ReconstructFromDepth when GBufferNormals is selected but not in deferred mode
/// </summary>
public NormalSource effectiveNormalsSource =>
normalsSource == NormalSource.GBufferNormals && !UmbraSoftShadows.isDeferred
? NormalSource.ReconstructFromDepth
: normalsSource;
[Tooltip("Reduces the number of samples while keeping the shadow size")]
public LoopStep loopStepOptimization = LoopStep.Default;
[Tooltip("Resolves shadowmap every two frames, reusing the result from previous frame")]
public bool frameSkipOptimization;
[Tooltip("Distance threshold - if camera has moved this distance from previous frame, ignore cached shadowmap")]
public float skipFrameMaxCameraDisplacement = 0.1f;
[Tooltip("Rotation threshold - if camera has rotated this angle from previous frame, ignore cached shadowmap")]
public float skipFrameMaxCameraRotation = 5f;
[Tooltip("Resolves screen space shadows in a reduced buffer of half of screen size")]
public bool downsample;
[Tooltip("Forces a depth prepass so depth and normals are available even for forward-only materials (useful in Deferred when using forward only materials).")]
public bool forceDepthPrepass;
[Tooltip("Prevents shadow blurring on geometry edges")]
public bool preserveEdges = true;
[Tooltip("Stylized look for shadows")]
public Style style = Style.Default;
[Tooltip("Optional mask texture to create stylized shadows")]
public Texture2D maskTexture;
public float maskScale = 1f;
public bool contactShadows;
[Range(0, 1)]
public float contactShadowsIntensityMultiplier = 0.85f;
public ContactShadowsInjectionPoint contactShadowsInjectionPoint = ContactShadowsInjectionPoint.ShadowTexture;
public ContactShadowsInjectionPoint actualContactShadowsInjectionPoint => shadowSource == ShadowSource.OnlyContactShadows || contactShadowsInjectionPoint == ContactShadowsInjectionPoint.AfterOpaque ? ContactShadowsInjectionPoint.AfterOpaque : contactShadowsInjectionPoint;
[Range(1, 64)]
public int contactShadowsSampleCount = 16;
public float contactShadowsStepping = 0.01f;
public float contactShadowsThicknessNear = 0.5f;
public float contactShadowsThicknessDistanceMultiplier;
public float contactShadowsJitter = 0.3f;
[Range(0, 1)]
[Tooltip("Attenuates shadow intensity with distance to occluder")]
public float contactShadowsDistanceFade = 0.75f;
public float contactShadowsStartDistance;
public float contactShadowsStartDistanceFade = 0.01f;
[Tooltip("Adds an offset to the pixel position to avoid self-occlusion")]
[Range(0.0001f, 0.25f)]
public float contactShadowsNormalBias = 0.1f;
[Tooltip("Attenuates contact shadows on the edges of screen")]
[Range(0, 0.5f)]
public float contactShadowsVignetteSize = 0.15f;
[Tooltip("Adds an offset to the pixel position to avoid self-occlusion")]
[Range(0f, 1f)]
public float contactShadowsBias = 0.001f;
[Tooltip("Bias applied at far distances. Use only if self-shadowing occurs on certain surfaces.")]
[Range(0, 1)]
public float contactShadowsBiasFar = 0.4f;
[Tooltip("Softens the edges of contact shadows. Higher values create softer edges.")]
[Range(0.01f, 0.5f)]
public float contactShadowsEdgeSoftness = 0.1f;
[Tooltip("Enables soft edges for contact shadows. When disabled, shadows have hard edges for better performance.")]
public bool contactShadowsSoftEdges;
[Tooltip("Makes contact shadows planar by ignoring the Y component of the light direction. Useful for ground shadows.")]
public bool contactShadowsPlanarShadows;
[Tooltip("Adds an extra pass after opaque with custom colored shadows")]
public bool overlayShadows;
public float overlayShadowsIntensity = 0.5f;
[ColorUsage(showAlpha: false, hdr: false)]
public Color overlayShadowsColor = Color.black;
[Tooltip("Enables a receiver plane to cast shadows from transparent objects. Check demo scene Transparent Receiver for an example.")]
public bool transparentReceiverPlane;
public float receiverPlaneAltitude;
void OnValidate() {
blurDepthAttenLength = Mathf.Max(0.001f, blurDepthAttenLength);
blurEdgeTolerance = Mathf.Max(0, blurEdgeTolerance);
blurDepthAttenStart = Mathf.Max(0, blurDepthAttenStart);
blurDepthAttenLength = Mathf.Max(0, blurDepthAttenLength);
blurGrazingAttenuation = Mathf.Max(0, blurGrazingAttenuation);
occludersSearchRadius = Mathf.Max(0.01f, occludersSearchRadius);
contactStrengthKnee = Mathf.Max(0.0001f, contactStrengthKnee);
cascade1BlendingStrength = Mathf.Max(0.01f, cascade1BlendingStrength);
cascade2BlendingStrength = Mathf.Max(0.01f, cascade2BlendingStrength);
cascade3BlendingStrength = Mathf.Max(0.01f, cascade3BlendingStrength);
cascade1Scale = Mathf.Max(0, cascade1Scale);
cascade2Scale = Mathf.Max(0, cascade2Scale);
cascade3Scale = Mathf.Max(0, cascade3Scale);
cascade4Scale = Mathf.Max(0, cascade4Scale);
maskScale = Mathf.Max(maskScale, 0);
skipFrameMaxCameraRotation = Mathf.Max(skipFrameMaxCameraRotation, 0);
skipFrameMaxCameraDisplacement = Mathf.Max(skipFrameMaxCameraDisplacement, 0);
contactShadowsStepping = Mathf.Max(0.0001f, contactShadowsStepping);
contactShadowsThicknessNear = Mathf.Max(0.0f, contactShadowsThicknessNear);
contactShadowsThicknessDistanceMultiplier = Mathf.Max(0.0f, contactShadowsThicknessDistanceMultiplier);
contactShadowsJitter = Mathf.Max(0f, contactShadowsJitter);
contactShadowsStartDistance = Mathf.Max(0, contactShadowsStartDistance);
contactShadowsStartDistanceFade = Mathf.Max(0.00001f, contactShadowsStartDistanceFade);
overlayShadowsIntensity = Mathf.Max(0, overlayShadowsIntensity);
}
public void ApplyPreset(UmbraPreset preset) {
shadowSource = ShadowSource.UmbraShadows;
switch (preset) {
case UmbraPreset.Fast:
sampleCount = 12;
lightSize = 12;
occludersCount = 6;
occludersSearchRadius = 5f;
enableContactHardening = true;
contactStrength = 0.5f;
contactStrengthKnee = 0.0001f;
blurIterations = 0;
distantSpread = 1f;
break;
case UmbraPreset.Hard:
sampleCount = 1;
lightSize = 0.5f;
enableContactHardening = false;
blurIterations = 1;
blurType = BlurType.Box;
blurSpread = 1f;
blurEdgeTolerance = 5f;
blurEdgeSharpness = 1f;
blurDepthAttenStart = 75;
blurDepthAttenLength = 50;
blurGrazingAttenuation = 0;
break;
case UmbraPreset.Soft:
sampleCount = 16;
lightSize = 8;
enableContactHardening = true;
occludersCount = 8;
occludersSearchRadius = 8f;
contactStrength = 0.5f;
contactStrengthKnee = 0.0001f;
distantSpread = 1f;
blurIterations = 0;
break;
case UmbraPreset.Smooth:
sampleCount = 16;
lightSize = 13;
enableContactHardening = true;
occludersCount = 9;
occludersSearchRadius = 8f;
contactStrength = 0.5f;
contactStrengthKnee = 0.0001f;
distantSpread = 1.2f;
blurIterations = 0;
break;
case UmbraPreset.ExtraSmooth:
sampleCount = 20;
lightSize = 16;
enableContactHardening = true;
occludersCount = 16;
occludersSearchRadius = 10;
contactStrength = 0.8f;
contactStrengthKnee = 0.0001f;
distantSpread = 1.4f;
blurIterations = 0;
break;
case UmbraPreset.Blurred:
sampleCount = 32;
lightSize = 16;
enableContactHardening = true;
occludersCount = 24;
occludersSearchRadius = 16;
contactStrength = 0.4f;
contactStrengthKnee = 0.0001f;
blurIterations = 0;
distantSpread = 2f;
break;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6751c6668ce8047e5bcc50f8586c1fe7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,483 @@
#if UNITY_2023_3_OR_NEWER
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Rendering.RenderGraphModule;
using System.Collections.Generic;
namespace Umbra {
internal partial class UmbraRenderFeature : ScreenSpaceShadows {
private partial class UmbraScreenSpaceShadowsPass : ScriptableRenderPass {
class PassData {
public UmbraScreenSpaceShadowsPass pass;
public UniversalShadowData shadowData;
public UniversalLightData lightData;
public UniversalCameraData cameraData;
public UniversalRenderingData renderingData;
public TextureHandle rtCameraDepthTexture;
public TextureHandle rtCameraNormalsTexture;
}
public override void RecordRenderGraph (RenderGraph renderGraph, ContextContainer frameData) {
if (mat == null) {
Debug.LogError("Umbra material not initialized");
return;
}
using (var builder = renderGraph.AddUnsafePass<PassData>("Umbra Soft Shadows", out var passData, m_ProfilingSampler)) {
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
desc = cameraData.cameraTargetDescriptor;
desc.depthBufferBits = 0;
desc.msaaSamples = 1;
desc.graphicsFormat = screenShadowTextureFormat;
UmbraProfile profile = settings.profile;
if (profile.downsample && !profile.preserveEdges) {
desc.width /= 2;
desc.height /= 2;
}
Camera cam = cameraData.camera;
#if UNITY_EDITOR
if (profile.frameSkipOptimization && Application.isPlaying) {
#else
if (profile.frameSkipOptimization) {
#endif
newShadowmap = !shadowTextures.TryGetValue(cam, out m_RenderTarget);
}
if (RenderingUtils.ReAllocateHandleIfNeeded(ref m_RenderTarget, desc, FilterMode.Point, TextureWrapMode.Clamp, name: "_ScreenSpaceShadowmapTexture")) {
newShadowmap = true;
}
if (newShadowmap) {
shadowTextures[cam] = m_RenderTarget;
}
builder.AllowGlobalStateModification(true);
#if UNITY_6000_0_OR_NEWER
TextureHandle shadowmap = renderGraph.ImportTexture(m_RenderTarget, new RenderTargetInfo {
width = desc.width,
height = desc.height,
volumeDepth = 1,
msaaSamples = 1,
format = desc.graphicsFormat
});
#else
TextureHandle shadowmap = renderGraph.ImportTexture(m_RenderTarget);
#endif
builder.UseTexture(shadowmap, AccessFlags.ReadWrite);
if (UmbraSoftShadows.isDeferred && resourceData.gBuffer[2].IsValid()) {
passData.rtCameraNormalsTexture = resourceData.gBuffer[2];
builder.UseTexture(passData.rtCameraNormalsTexture, AccessFlags.Read);
}
passData.rtCameraDepthTexture = resourceData.cameraDepthTexture;
builder.UseTexture(resourceData.cameraDepthTexture, AccessFlags.Read);
if ((input & ScriptableRenderPassInput.Normal) != 0) {
builder.UseTexture(resourceData.cameraNormalsTexture, AccessFlags.Read);
}
passData.pass = this;
passData.cameraData = cameraData;
passData.lightData = frameData.Get<UniversalLightData>();
passData.shadowData = frameData.Get<UniversalShadowData>();
passData.renderingData = frameData.Get<UniversalRenderingData>();
builder.SetRenderFunc(static (PassData data, UnsafeGraphContext rgContext) => {
if (data.rtCameraDepthTexture.IsValid()) {
mat.SetTexture(ShaderParams.CameraDepthTexture, data.rtCameraDepthTexture);
}
if (data.rtCameraNormalsTexture.IsValid()) {
mat.SetTexture(ShaderParams.CameraNormalsTexture, data.rtCameraNormalsTexture);
}
CommandBuffer cmd = CommandBufferHelpers.GetNativeCommandBuffer(rgContext.cmd);
cmd.SetGlobalTexture(m_RenderTarget.name, m_RenderTarget.nameID);
ExecutePass(cmd, data);
});
}
}
static void ExecutePass (CommandBuffer cmd, PassData passData) {
UmbraProfile profile = settings.profile;
int frameCount = Time.frameCount;
#if UNITY_EDITOR
bool useFrame = !Application.isPlaying || !profile.frameSkipOptimization || newShadowmap || !usesCachedShadowmap;
#else
bool useFrame = !profile.frameSkipOptimization || newShadowmap || !usesCachedShadowmap;
#endif
if (useFrame) {
cachedShadowmapTimestap = frameCount;
newShadowmap = false;
RTHandle shadowsHandle;
if (profile.downsample && profile.preserveEdges) {
desc.width /= 2;
desc.height /= 2;
#if UNITY_6000_0_OR_NEWER
RenderingUtils.ReAllocateHandleIfNeeded(ref m_DownscaledRenderTarget, desc, FilterMode.Point, TextureWrapMode.Clamp);
#else
RenderingUtils.ReAllocateIfNeeded(ref m_DownscaledRenderTarget, desc, FilterMode.Point, TextureWrapMode.Clamp);
#endif
shadowsHandle = m_DownscaledRenderTarget;
}
else {
shadowsHandle = m_RenderTarget;
}
float farClipPlane = passData.cameraData.camera.farClipPlane;
int cascadeCount = passData.shadowData.mainLightShadowCascadesCount;
UniversalRenderPipelineAsset urpAsset = GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset;
float shadowMaxDistance = urpAsset.shadowDistance;
Pass castShadowsPass;
if (profile.shadowSource == ShadowSource.UnityShadows) {
castShadowsPass = Pass.UnityShadows;
}
else {
castShadowsPass = Pass.UmbraCastShadows;
if (profile.transparentReceiverPlane) {
mat.EnableKeyword(ShaderParams.SKW_RECEIVER_PLANE);
cmd.SetGlobalFloat(ShaderParams.ReceiverPlaneAltitude, profile.receiverPlaneAltitude);
}
else {
mat.DisableKeyword(ShaderParams.SKW_RECEIVER_PLANE);
}
cmd.SetGlobalVector(ShaderParams.ShadowData, new Vector4(profile.sampleCount, 1024 / Mathf.Pow(2, profile.posterization), profile.blurEdgeTolerance * 1000f, (profile.blurDepthAttenStart + profile.blurDepthAttenLength) / farClipPlane));
float shadowMaxDepth = profile.transparentReceiverPlane ? 2 : shadowMaxDistance / farClipPlane;
cmd.SetGlobalVector(ShaderParams.ShadowData2, new Vector4(1f - profile.contactStrength, profile.distantSpread, shadowMaxDepth, profile.lightSize * 0.02f));
cmd.SetGlobalVector(ShaderParams.ShadowData3, new Vector4(profile.blurDepthAttenStart / farClipPlane, profile.blurDepthAttenLength / farClipPlane, profile.blurGrazingAttenuation, profile.blurEdgeSharpness));
cmd.SetGlobalVector(ShaderParams.ShadowData4, new Vector4(profile.occludersCount, profile.occludersSearchRadius * 0.02f, profile.contactStrength > 0 ? profile.contactStrengthKnee * 0.1f : 0.00001f, profile.maskScale));
cmd.SetGlobalVector(ShaderParams.SourceSize, new Vector4(desc.width, desc.height, 0, 0));
cmd.SetGlobalInt(ShaderParams.EarlyOutSamples, profile.earlyOutSamples);
if (cascadeCount > 1) {
VisibleLight shadowLight = passData.lightData.visibleLights[shadowLightIndex];
float shadowNearPlane = shadowLight.light.shadowNearPlane;
for (int k = 0; k < cascadeCount; k++) {
passData.renderingData.cullResults.ComputeDirectionalShadowMatricesAndCullingPrimitives(shadowLightIndex,
k, cascadeCount, passData.shadowData.mainLightShadowCascadesSplit, urpAsset.mainLightShadowmapResolution, shadowNearPlane, out _, out Matrix4x4 proj,
out _);
Matrix4x4 invProj = proj.inverse;
autoCascadeScales[k] = Mathf.Abs(invProj.MultiplyPoint(ShaderParams.Vector3Back).z - invProj.MultiplyPoint(ShaderParams.Vector3Forward).z) / 100f;
}
Vector4[] cascadeRectsTemp = cascadeRectsWithPadding[cascadeCount - 1];
float texel = 1f / urpAsset.mainLightShadowmapResolution;
float padding = texel;
for (int c = 0; c < 4; c++) {
Vector4 defaultRect = cascadeRects[cascadeCount - 1][c];
Vector4 rect = cascadeRectsTemp[c];
rect.x = defaultRect.x + padding;
rect.y = defaultRect.y + padding;
rect.z = defaultRect.z - padding;
rect.w = defaultRect.w - padding;
cascadeRectsTemp[c] = rect;
}
cmd.SetGlobalVectorArray(ShaderParams.UmbraCascadeRects, cascadeRectsTemp);
cascadeScales[0] = profile.cascade1Scale * autoCascadeScales[0];
cascadeScales[1] = profile.cascade2Scale * autoCascadeScales[1];
cascadeScales[2] = profile.cascade3Scale * autoCascadeScales[2];
cascadeScales[3] = profile.cascade4Scale * autoCascadeScales[3];
cmd.SetGlobalFloatArray(ShaderParams.UmbraCascadeScales, cascadeScales);
}
if ((UmbraSoftShadows.isDeferred && profile.normalsSource == NormalSource.GBufferNormals) || profile.effectiveNormalsSource == NormalSource.NormalsPass || profile.downsample) {
mat.EnableKeyword(ShaderParams.SKW_NORMALS_TEXTURE);
}
else {
mat.DisableKeyword(ShaderParams.SKW_NORMALS_TEXTURE);
}
#if !UNITY_WEBGL
if (profile.enableContactHardening) {
mat.EnableKeyword(ShaderParams.SKW_CONTACT_HARDENING);
}
else
#endif
{
mat.DisableKeyword(ShaderParams.SKW_CONTACT_HARDENING);
}
mat.DisableKeyword(ShaderParams.SKW_LOOP_STEP_X3);
mat.DisableKeyword(ShaderParams.SKW_LOOP_STEP_X2);
if (profile.loopStepOptimization == LoopStep.x3) {
mat.EnableKeyword(ShaderParams.SKW_LOOP_STEP_X3);
}
else if (profile.loopStepOptimization == LoopStep.x2) {
mat.EnableKeyword(ShaderParams.SKW_LOOP_STEP_X2);
}
if (profile.style == Style.Textured && profile.maskTexture != null) {
mat.EnableKeyword(ShaderParams.SKW_MASK_TEXTURE);
mat.SetTexture(ShaderParams.MaskTexture, profile.maskTexture);
}
else {
mat.DisableKeyword(ShaderParams.SKW_MASK_TEXTURE);
}
}
// Resolve screen space shadows
Blitter.BlitCameraTexture(cmd, m_RenderTarget, shadowsHandle, mat, (int)castShadowsPass);
// Blend cascades 0 & 1
if (profile.shadowSource == ShadowSource.UmbraShadows) {
if (profile.blendCascades && cascadeCount > 1) {
cmd.SetGlobalVector(ShaderParams.BlendCascadeData, new Vector4(profile.cascade1BlendingStrength * 100f, profile.cascade2BlendingStrength * 100f, profile.cascade3BlendingStrength * 100f, 1f));
Blitter.BlitCameraTexture(cmd, shadowsHandle, shadowsHandle, mat, (int)Pass.CascadeBlending);
}
}
// Add contact shadows
if (profile.contactShadows && SetupContactShadowsMaterial(passData.cameraData.camera, profile, mat)) {
if (!settings.debugShadows && profile.actualContactShadowsInjectionPoint == ContactShadowsInjectionPoint.ShadowTexture) {
Blitter.BlitCameraTexture(cmd, shadowsHandle, shadowsHandle, mat, (int)Pass.ContactShadows);
}
}
// Downscale depth for upscaler
if (profile.downsample && profile.preserveEdges) {
RenderTextureDescriptor downscampledDepthDesc = desc;
downscampledDepthDesc.colorFormat = RenderTextureFormat.RFloat;
cmd.GetTemporaryRT(ShaderParams.DownsampledDepth, downscampledDepthDesc);
FullScreenBlit(cmd, ShaderParams.DownsampledDepth, mat, (int)Pass.DownsampledDepth);
mat.EnableKeyword(ShaderParams.SKW_PRESERVE_EDGES);
}
else {
mat.DisableKeyword(ShaderParams.SKW_PRESERVE_EDGES);
}
if (profile.shadowSource == ShadowSource.UnityShadows) {
if (profile.downsample && profile.preserveEdges) {
// upscale
FullScreenBlit(cmd, m_DownscaledRenderTarget, m_RenderTarget, mat, (int)Pass.ComposeUnity);
}
}
else {
if (profile.style == Style.Default && profile.blurIterations > 0) {
cmd.SetGlobalFloat(ShaderParams.BlurSpread, profile.blurSpread);
// perform blur
cmd.GetTemporaryRT(ShaderParams.BlurTemp, desc);
cmd.GetTemporaryRT(ShaderParams.BlurTemp2, desc);
cmd.SetGlobalFloat(ShaderParams.BlurScale, 1f);
RenderTargetIdentifier shadowsRT = shadowsHandle;
RenderTargetIdentifier blurredRT = ShaderParams.BlurTemp2;
if (profile.blurType == BlurType.Box) {
for (int k = 0; k < profile.blurIterations; k++) {
blurredRT = (k % 2) == 0 ? ShaderParams.BlurTemp2 : ShaderParams.BlurTemp;
FullScreenBlit(cmd, shadowsRT, blurredRT, mat, (int)Pass.BoxBlur);
shadowsRT = blurredRT;
cmd.SetGlobalFloat(ShaderParams.BlurScale, k + 1f);
}
}
else {
if (profile.blurType == BlurType.Gaussian15) {
mat.EnableKeyword(ShaderParams.SKW_BLUR_HQ);
}
else {
mat.DisableKeyword(ShaderParams.SKW_BLUR_HQ);
}
FullScreenBlit(cmd, shadowsRT, ShaderParams.BlurTemp, mat, (int)Pass.BlurHoriz);
cmd.SetGlobalFloat(ShaderParams.BlurScale, 1f);
for (int k = 0; k < profile.blurIterations - 1; k++) {
FullScreenBlit(cmd, ShaderParams.BlurTemp, ShaderParams.BlurTemp2, mat, (int)Pass.BlurVert);
cmd.SetGlobalFloat(ShaderParams.BlurScale, k + 2f);
FullScreenBlit(cmd, ShaderParams.BlurTemp2, ShaderParams.BlurTemp, mat, (int)Pass.BlurHoriz);
}
FullScreenBlit(cmd, ShaderParams.BlurTemp, ShaderParams.BlurTemp2, mat, (int)Pass.BlurVert);
}
// blit blurred shadows
FullScreenBlit(cmd, blurredRT, m_RenderTarget, mat, (int)Pass.ComposeWithBlending);
}
else if (profile.downsample && profile.preserveEdges) {
// upscale
FullScreenBlit(cmd, m_DownscaledRenderTarget, m_RenderTarget, mat, (int)Pass.Compose);
}
}
}
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadows, false);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadowCascades, false);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadowScreen, true);
}
}
private partial class UmbraScreenSpaceShadowsPostPass : ScriptableRenderPass {
internal class PassData {
internal UniversalShadowData shadowData;
}
private static void ExecutePass (RasterCommandBuffer cmd, UniversalShadowData shadowData) {
int cascadesCount = shadowData.mainLightShadowCascadesCount;
bool mainLightShadows = shadowData.supportsMainLightShadows;
bool receiveShadowsNoCascade = mainLightShadows && cascadesCount == 1;
bool receiveShadowsCascades = mainLightShadows && cascadesCount > 1;
// Before transparent object pass, force to disable screen space shadow of main light
cmd.SetKeyword(ShaderGlobalKeywords.MainLightShadowScreen, false);
// then enable main light shadows with or without cascades
cmd.SetKeyword(ShaderGlobalKeywords.MainLightShadows, receiveShadowsNoCascade);
cmd.SetKeyword(ShaderGlobalKeywords.MainLightShadowCascades, receiveShadowsCascades);
}
public override void RecordRenderGraph (RenderGraph renderGraph, ContextContainer frameData) {
using (var builder = renderGraph.AddRasterRenderPass<PassData>("Umbra Screen Space Shadow Post Pass", out var passData, m_ProfilingSampler)) {
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
TextureHandle color = resourceData.activeColorTexture;
builder.SetRenderAttachment(color, 0, AccessFlags.Write);
passData.shadowData = frameData.Get<UniversalShadowData>();
builder.AllowGlobalStateModification(true);
builder.SetRenderFunc(static (PassData data, RasterGraphContext rgContext) => {
ExecutePass(rgContext.cmd, data.shadowData);
});
}
}
}
private partial class UmbraDebugPass : ScriptableRenderPass {
internal class PassData {
internal Camera cam;
}
private static void ExecutePass (RasterCommandBuffer cmd, Camera cam) {
Material mat = UmbraScreenSpaceShadowsPass.mat;
if (mat == null) return;
RTHandle shadows = null;
Dictionary<Camera, RTHandle> shadowTextures = shadowPass.shadowTextures;
if (shadowTextures != null) {
shadows = shadowTextures[cam];
}
if (shadows == null) return;
using (new ProfilingScope(cmd, m_ProfilingSampler)) {
Blitter.BlitTexture(cmd, shadows, new Vector4(1, 1, 0, 0), mat, (int)Pass.DebugShadows);
if (settings.debugShadows && settings.profile != null && settings.profile.contactShadows) {
Blitter.BlitTexture(cmd, shadows, new Vector4(1, 1, 0, 0), mat, (int)Pass.ContactShadowsAfterOpaque);
}
}
}
public override void RecordRenderGraph (RenderGraph renderGraph, ContextContainer frameData) {
using (var builder = renderGraph.AddRasterRenderPass<PassData>("Umbra Debug Pass", out var passData, m_ProfilingSampler)) {
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
TextureHandle color = resourceData.activeColorTexture;
builder.SetRenderAttachment(color, 0, AccessFlags.Write);
passData.cam = frameData.Get<UniversalCameraData>().camera;
builder.SetRenderFunc((PassData data, RasterGraphContext rgContext) => {
ExecutePass(rgContext.cmd, data.cam);
});
}
}
}
private partial class UmbraContactShadowsAfterOpaquePass : ScriptableRenderPass {
internal class PassData {
internal Vector4 sourceSize;
internal TextureHandle depthTexture;
}
private static void ExecutePass (RasterCommandBuffer cmd, Vector4 sourceSize, RTHandle depth) {
Material mat = UmbraScreenSpaceShadowsPass.mat;
if (mat == null) return;
using (new ProfilingScope(cmd, m_ProfilingSampler)) {
mat.SetTexture(ShaderParams.CameraDepthTexture, depth);
UmbraProfile profile = settings.profile;
if (profile.transparentReceiverPlane) {
cmd.SetGlobalFloat(ShaderParams.ReceiverPlaneAltitude, profile.receiverPlaneAltitude);
}
cmd.SetGlobalVector(ShaderParams.SourceSize, sourceSize);
Blitter.BlitTexture(cmd, new Vector4(1, 1, 0, 0), mat, (int)Pass.ContactShadowsAfterOpaque);
}
}
public override void RecordRenderGraph (RenderGraph renderGraph, ContextContainer frameData) {
using (var builder = renderGraph.AddRasterRenderPass<PassData>("Umbra Contact Shadows After Opaque Pass", out var passData, m_ProfilingSampler)) {
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
TextureHandle color = resourceData.activeColorTexture;
if (UmbraSoftShadows.isDeferred && resourceData.gBuffer[4].IsValid()) {
passData.depthTexture = resourceData.gBuffer[4];
builder.UseTexture(passData.depthTexture, AccessFlags.Read);
}
else {
passData.depthTexture = resourceData.cameraDepthTexture;
builder.UseTexture(resourceData.cameraDepthTexture, AccessFlags.Read);
}
builder.AllowGlobalStateModification(true);
builder.SetRenderAttachment(color, 0, AccessFlags.Write);
RenderTargetInfo colorInfo = renderGraph.GetRenderTargetInfo(color);
passData.sourceSize = new Vector4(colorInfo.width, colorInfo.height, 0, 0);
builder.SetRenderFunc((PassData data, RasterGraphContext rgContext) => {
ExecutePass(rgContext.cmd, data.sourceSize, data.depthTexture);
});
}
}
}
private partial class UmbraOverlayShadows : ScriptableRenderPass {
internal class PassData {
}
private static void ExecutePass (RasterCommandBuffer cmd) {
Material mat = UmbraScreenSpaceShadowsPass.mat;
if (mat == null) return;
using (new ProfilingScope(cmd, m_ProfilingSampler)) {
Color shadowColor = settings.profile.overlayShadowsColor;
shadowColor.a = settings.profile.overlayShadowsIntensity;
mat.SetColor(ShaderParams.OverlayShadowColor, shadowColor);
Blitter.BlitTexture(cmd, new Vector4(1, 1, 0, 0), mat, (int)Pass.OverlayShadows);
}
}
public override void RecordRenderGraph (RenderGraph renderGraph, ContextContainer frameData) {
using (var builder = renderGraph.AddRasterRenderPass<PassData>("Umbra Overlay Shadows", out var passData, m_ProfilingSampler)) {
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
TextureHandle color = resourceData.activeColorTexture;
builder.SetRenderAttachment(color, 0, AccessFlags.Write);
builder.SetRenderFunc((PassData data, RasterGraphContext rgContext) => {
ExecutePass(rgContext.cmd);
});
}
}
}
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cb0594141e67f4a1aadba1722240bb79
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,918 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Umbra {
[DisallowMultipleRendererFeature("Umbra Render Feature")]
[Tooltip("Umbra Render Feature")]
internal partial class UmbraRenderFeature : ScreenSpaceShadows {
#if UNITY_EDITOR
[UnityEditor.ShaderKeywordFilter.SelectIf(true, keywordNames: ShaderKeywordStrings.MainLightShadowScreen)]
private const bool k_RequiresScreenSpaceShadowsKeyword = true;
#endif
static class ShaderParams {
readonly public static int MainTex = Shader.PropertyToID("_MainTex");
readonly public static int ShadowData = Shader.PropertyToID("_ShadowData");
readonly public static int ShadowData2 = Shader.PropertyToID("_ShadowData2");
readonly public static int ShadowData3 = Shader.PropertyToID("_ShadowData3");
readonly public static int ShadowData4 = Shader.PropertyToID("_ShadowData4");
readonly public static int BlurTemp = Shader.PropertyToID("_BlurTemp");
readonly public static int BlurTemp2 = Shader.PropertyToID("_BlurTemp2");
readonly public static int BlurScale = Shader.PropertyToID("_BlurScale");
readonly public static int BlurSpread = Shader.PropertyToID("_BlurSpread");
readonly public static int UmbraCascadeRects = Shader.PropertyToID("_UmbraCascadeRects");
readonly public static int UmbraCascadeScales = Shader.PropertyToID("_UmbraCascadeScales");
readonly public static int DownsampledDepth = Shader.PropertyToID("_DownsampledDepth");
readonly public static int NoiseTex = Shader.PropertyToID("_NoiseTex");
readonly public static int SourceSize = Shader.PropertyToID("_SourceSize");
readonly public static int BlendCascadeData = Shader.PropertyToID("_BlendCascadeData");
readonly public static int MaskTexture = Shader.PropertyToID("_MaskTex");
readonly public static int CameraDepthTexture = Shader.PropertyToID("_CameraDepthTexture");
readonly public static int CameraNormalsTexture = Shader.PropertyToID("_CameraNormalsTexture");
readonly public static int ContactShadowsSampleCount = Shader.PropertyToID("_ContactShadowsSampleCount");
readonly public static int ContactShadowsData1 = Shader.PropertyToID("_ContactShadowsData1");
readonly public static int ContactShadowsData2 = Shader.PropertyToID("_ContactShadowsData2");
readonly public static int ContactShadowsData3 = Shader.PropertyToID("_ContactShadowsData3");
readonly public static int ContactShadowsData4 = Shader.PropertyToID("_ContactShadowsData4");
readonly public static int ContactShadowsBlendMode = Shader.PropertyToID("_ContactShadowsBlend");
readonly public static int ReceiverPlaneAltitude = Shader.PropertyToID("_ReceiverPlaneAltitude");
readonly public static int OverlayShadowColor = Shader.PropertyToID("_OverlayShadowColor");
readonly public static int EarlyOutSamples = Shader.PropertyToID("_EarlyOutSamples");
readonly public static int PointLightPosition = Shader.PropertyToID("_PointLightPosition");
public static Vector3 Vector3Back = Vector3.back;
public static Vector3 Vector3Forward = Vector3.forward;
public const string SKW_LOOP_STEP_X3 = "_LOOP_STEP_X3";
public const string SKW_LOOP_STEP_X2 = "_LOOP_STEP_X2";
public const string SKW_PRESERVE_EDGES = "_PRESERVE_EDGES";
public const string SKW_BLUR_HQ = "_BLUR_HQ";
public const string SKW_NORMALS_TEXTURE = "_NORMALS_TEXTURE";
public const string SKW_CONTACT_HARDENING = "_CONTACT_HARDENING";
public const string SKW_MASK_TEXTURE = "_MASK_TEXTURE";
public const string SKW_RECEIVER_PLANE = "_RECEIVER_PLANE";
public const string SKW_USE_POINT_LIGHT = "_USE_POINT_LIGHT";
public const string SKW_CONTACT_SHADOWS_SOFT_EDGES = "_SOFT_EDGES";
}
enum Pass {
UmbraCastShadows,
BlurHoriz,
BlurVert,
BoxBlur,
ComposeWithBlending,
DownsampledDepth,
CascadeBlending,
UnityShadows,
ComposeUnity,
ContactShadows,
Compose,
DebugShadows,
ContactShadowsAfterOpaque,
OverlayShadows
}
struct CameraLocation {
public Vector3 position;
public Vector3 forward;
}
const string k_ShaderName = "Hidden/Kronnect/UmbraScreenSpaceShadows";
[Tooltip("Specify which cameras can render Umbra Soft Shadows")]
public LayerMask camerasLayerMask = -1;
public static UmbraSoftShadows settings;
public static int shadowLightIndex;
static int cachedShadowmapTimestap;
static bool usesCachedShadowmap;
readonly Dictionary<Camera, CameraLocation> cameraPrevLocation = new Dictionary<Camera, CameraLocation>();
static readonly Dictionary<Light, UmbraSoftShadows> umbraSettings = new Dictionary<Light, UmbraSoftShadows>();
Material mat;
UmbraScreenSpaceShadowsPass m_SSShadowsPass;
UmbraScreenSpaceShadowsPostPass m_SSShadowsPostPass;
UmbraDebugPass m_SSSShadowsDebugPass;
UmbraContactShadowsAfterOpaquePass m_ContactShadowsAfterOpaquePass;
UmbraOverlayShadows m_OverlayShadowsPass;
public static void RegisterUmbraLight (UmbraSoftShadows settings) {
Light light = settings.GetComponent<Light>();
if (light != null) {
if (light.type == LightType.Directional) {
umbraSettings[light] = settings;
}
else {
Debug.LogError("Umbra Soft Shadows only work on directiona light.");
}
}
}
public static void UnregisterUmbraLight (UmbraSoftShadows settings) {
Light light = settings.GetComponent<Light>();
if (light != null && umbraSettings.ContainsKey(light)) {
umbraSettings.Remove(light);
}
}
public override void Create () {
if (m_SSShadowsPass == null) {
m_SSShadowsPass = new UmbraScreenSpaceShadowsPass();
}
if (m_SSShadowsPostPass == null) {
m_SSShadowsPostPass = new UmbraScreenSpaceShadowsPostPass();
}
if (m_ContactShadowsAfterOpaquePass == null) {
m_ContactShadowsAfterOpaquePass = new UmbraContactShadowsAfterOpaquePass();
}
if (m_SSSShadowsDebugPass == null) {
m_SSSShadowsDebugPass = new UmbraDebugPass();
}
if (m_OverlayShadowsPass == null) {
m_OverlayShadowsPass = new UmbraOverlayShadows();
}
cachedShadowmapTimestap = -100;
LoadMaterial();
m_SSShadowsPass.renderPassEvent = RenderPassEvent.AfterRenderingGbuffer;
m_SSShadowsPostPass.renderPassEvent = RenderPassEvent.BeforeRenderingTransparents;
m_OverlayShadowsPass.renderPassEvent = RenderPassEvent.AfterRenderingOpaques + 1;
m_ContactShadowsAfterOpaquePass.renderPassEvent = RenderPassEvent.AfterRenderingOpaques + 1;
m_SSSShadowsDebugPass.renderPassEvent = RenderPassEvent.AfterRenderingTransparents;
}
void OnDisable () {
UmbraSoftShadows.installed = false;
}
protected override void Dispose (bool disposing) {
m_SSShadowsPass?.Dispose();
m_SSShadowsPass = null;
CoreUtils.Destroy(mat);
}
static bool SetupContactShadowsMaterial (Camera cam, UmbraProfile profile, Material mat) {
float intensityMultiplier = profile.contactShadowsIntensityMultiplier;
// Check if we should use point lights for contact shadows
mat.DisableKeyword(ShaderParams.SKW_USE_POINT_LIGHT);
if (settings.contactShadowsSource == ContactShadowsSource.PointLights) {
if (settings.pointLightsTrigger == null && Camera.main != null) {
settings.pointLightsTrigger = Camera.main.transform;
}
float fade = 0;
if (settings.pointLightsTrigger != null) {
Vector3 triggerPosition = settings.pointLightsTrigger.position;
// Find the point light that contains the trigger position
foreach (var kvp in UmbraPointLightContactShadows.umbraPointLights) {
UmbraPointLightContactShadows pointLightComponent = kvp.Value;
if (pointLightComponent == null) continue;
fade = pointLightComponent.ComputeVolumeFade(triggerPosition);
if (fade > 0) {
// Set point light data for the shader
Vector3 pointLightPosition = pointLightComponent.transform.position;
mat.SetVector(ShaderParams.PointLightPosition, new Vector4(pointLightPosition.x, pointLightPosition.y, pointLightPosition.z, 1.0f));
mat.EnableKeyword(ShaderParams.SKW_USE_POINT_LIGHT);
break; // Use the first point light found
}
}
}
if (fade <= 0) return false;
intensityMultiplier *= fade;
}
float farClipPlane = cam.farClipPlane;
UniversalRenderPipelineAsset urpAsset = GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset;
float shadowMaxDistance = urpAsset.shadowDistance;
mat.SetInt(ShaderParams.ContactShadowsSampleCount, profile.contactShadowsSampleCount);
float contactShadowsMaxDistance;
if (settings.profile.shadowSource == ShadowSource.UnityShadows || settings.profile.actualContactShadowsInjectionPoint == ContactShadowsInjectionPoint.AfterOpaque) {
contactShadowsMaxDistance = 1;
}
else {
contactShadowsMaxDistance = shadowMaxDistance / farClipPlane;
}
mat.SetVector(ShaderParams.ContactShadowsData1, new Vector4(profile.contactShadowsStepping, intensityMultiplier, profile.contactShadowsJitter, profile.contactShadowsDistanceFade));
mat.SetVector(ShaderParams.ContactShadowsData2, new Vector4(profile.contactShadowsStartDistance / farClipPlane, profile.contactShadowsStartDistanceFade / farClipPlane, contactShadowsMaxDistance, profile.contactShadowsNormalBias));
mat.SetVector(ShaderParams.ContactShadowsData3, new Vector4(profile.contactShadowsThicknessNear / farClipPlane, profile.contactShadowsThicknessDistanceMultiplier * 0.1f, profile.contactShadowsVignetteSize, profile.contactShadowsBias));
mat.SetVector(ShaderParams.ContactShadowsData4, new Vector4(profile.contactShadowsBiasFar + 0.0025f, profile.contactShadowsEdgeSoftness, profile.contactShadowsPlanarShadows ? 0f : 1f, 0));
mat.SetInt(ShaderParams.ContactShadowsBlendMode, settings.debugShadows ? (int)BlendMode.SrcAlpha : (int)BlendMode.OneMinusSrcAlpha);
// Enable/disable soft edges keyword
if (profile.contactShadowsSoftEdges) {
mat.EnableKeyword(ShaderParams.SKW_CONTACT_SHADOWS_SOFT_EDGES);
}
else {
mat.DisableKeyword(ShaderParams.SKW_CONTACT_SHADOWS_SOFT_EDGES);
}
return true;
}
static void SetupContactShadowsAfterOpaqueOnlyMaterial (UmbraProfile profile, Material mat) {
if ((UmbraSoftShadows.isDeferred && profile.normalsSource == NormalSource.GBufferNormals) || profile.effectiveNormalsSource == NormalSource.NormalsPass) {
mat.EnableKeyword(ShaderParams.SKW_NORMALS_TEXTURE);
}
else {
mat.DisableKeyword(ShaderParams.SKW_NORMALS_TEXTURE);
}
mat.DisableKeyword(ShaderParams.SKW_LOOP_STEP_X3);
mat.DisableKeyword(ShaderParams.SKW_LOOP_STEP_X2);
if (profile.loopStepOptimization == LoopStep.x3) {
mat.EnableKeyword(ShaderParams.SKW_LOOP_STEP_X3);
}
else if (profile.loopStepOptimization == LoopStep.x2) {
mat.EnableKeyword(ShaderParams.SKW_LOOP_STEP_X2);
}
if (profile.transparentReceiverPlane) {
mat.EnableKeyword(ShaderParams.SKW_RECEIVER_PLANE);
}
else {
mat.DisableKeyword(ShaderParams.SKW_RECEIVER_PLANE);
}
}
static bool IsOffscreenDepthTexture (ref CameraData cameraData) => cameraData.targetTexture != null && cameraData.targetTexture.format == RenderTextureFormat.Depth;
public override void AddRenderPasses (ScriptableRenderer renderer, ref RenderingData renderingData) {
UmbraSoftShadows.installed = true;
if (IsOffscreenDepthTexture(ref renderingData.cameraData))
return;
if (!LoadMaterial()) {
Debug.LogError("Umbra: can't load material");
return;
}
// Fetch settings from current main directional light
Light light = null;
shadowLightIndex = renderingData.lightData.mainLightIndex;
if (shadowLightIndex < 0) {
// fallback to static instance search in case that "Only Contact Shadows" option is used
if (UmbraSoftShadows.instance != null) {
light = UmbraSoftShadows.instance.GetComponent<Light>();
}
}
else {
light = renderingData.lightData.visibleLights[shadowLightIndex].light;
}
if (light == null) return;
if (!umbraSettings.TryGetValue(light, out settings)) return;
if (settings == null) return;
Camera cam = renderingData.cameraData.camera;
usesCachedShadowmap = cachedShadowmapTimestap == Time.frameCount - 1 && settings != null && settings.profile != null && settings.profile.frameSkipOptimization && Application.isPlaying;
if (usesCachedShadowmap) {
// test camera rotation/movement
Transform t = cam.transform;
Vector3 pos = t.position;
Vector3 fwd = t.forward;
bool camMoved = true;
if (cameraPrevLocation.TryGetValue(cam, out CameraLocation prevLocation)) {
float dx = pos.x - prevLocation.position.x;
float dy = pos.y - prevLocation.position.y;
float dz = pos.z - prevLocation.position.z;
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
if (dz < 0) dz = -dz;
float thresholdPosition = settings.profile.skipFrameMaxCameraDisplacement;
if (dx <= thresholdPosition && dy <= thresholdPosition && dz <= thresholdPosition) {
if (Vector3.Angle(prevLocation.forward, fwd) <= settings.profile.skipFrameMaxCameraRotation) {
camMoved = false;
}
}
}
if (camMoved) {
prevLocation.position = pos;
prevLocation.forward = fwd;
cameraPrevLocation[cam] = prevLocation;
usesCachedShadowmap = false;
}
}
UmbraSoftShadows.isDeferred = renderer is UniversalRenderer ur && (
ur.renderingModeRequested == RenderingMode.Deferred
|| (int)ur.renderingModeRequested == 3 // RenderingMode.DeferredPlus
);
bool shouldEnqueue = ((camerasLayerMask & (1 << cam.gameObject.layer)) != 0) && m_SSShadowsPass.Setup(mat);
if (shouldEnqueue) {
bool allowMainLightShadows = renderingData.shadowData.supportsMainLightShadows && renderingData.lightData.mainLightIndex != -1 && renderingData.lightData.visibleLights[renderingData.lightData.mainLightIndex].light.shadowStrength > 0;
bool allowScreenSpaceShadows = allowMainLightShadows && (settings.profile == null || settings.profile.shadowSource != ShadowSource.OnlyContactShadows);
if (allowScreenSpaceShadows) {
m_SSShadowsPass.renderPassEvent = UmbraSoftShadows.isDeferred
? RenderPassEvent.AfterRenderingGbuffer
: RenderPassEvent.AfterRenderingPrePasses + 1; // We add 1 to ensure this happens after depth priming depth copy pass that might be scheduled
renderer.EnqueuePass(m_SSShadowsPass);
renderer.EnqueuePass(m_SSShadowsPostPass);
}
if (settings.profile != null) {
if (!settings.debugShadows && allowScreenSpaceShadows && settings.profile.overlayShadows && settings.profile.overlayShadowsIntensity > 0) {
renderer.EnqueuePass(m_OverlayShadowsPass);
}
if (settings.profile.contactShadows || settings.profile.shadowSource == ShadowSource.OnlyContactShadows) {
if (SetupContactShadowsMaterial(cam, settings.profile, mat)) {
if (settings.profile.shadowSource != ShadowSource.UmbraShadows || settings.profile.actualContactShadowsInjectionPoint == ContactShadowsInjectionPoint.AfterOpaque) {
SetupContactShadowsAfterOpaqueOnlyMaterial(settings.profile, mat);
m_ContactShadowsAfterOpaquePass.Setup();
renderer.EnqueuePass(m_ContactShadowsAfterOpaquePass);
}
}
}
}
if (allowScreenSpaceShadows && settings.debugShadows) {
m_SSSShadowsDebugPass.Setup(m_SSShadowsPass);
renderer.EnqueuePass(m_SSSShadowsDebugPass);
}
}
}
private bool LoadMaterial () {
if (mat != null) {
return true;
}
Shader shader = Shader.Find(k_ShaderName);
if (shader == null) {
return false;
}
mat = CoreUtils.CreateEngineMaterial(shader);
Texture2D noiseTex = Resources.Load<Texture2D>("Umbra/Textures/NoiseTex");
mat.SetTexture(ShaderParams.NoiseTex, noiseTex);
return mat != null;
}
private partial class UmbraScreenSpaceShadowsPass : ScriptableRenderPass {
static string m_ProfilerTag = "UmbraSoftShadows";
static ProfilingSampler m_ProfilingSampler = new ProfilingSampler(m_ProfilerTag);
public static Material mat;
static RTHandle m_RenderTarget, m_DownscaledRenderTarget;
static readonly Vector4[][] cascadeRects = {
new Vector4[] { new Vector4(0, 0, 1, 1), new Vector4(0, 0, 1, 1), new Vector4(0, 0, 1, 1), new Vector4(0, 0, 1, 1) },
new Vector4[] { new Vector4(0, 0, 0.5f, 1f), new Vector4(0.5f, 0, 1, 1f), new Vector4(0, 0, 1, 1), new Vector4(0, 0, 1, 1) },
new Vector4[] { new Vector4(0, 0, 0.5f, 0.5f), new Vector4(0.5f, 0, 1, 0.5f), new Vector4(0, 0.5f, 0.5f, 1), new Vector4(0.5f, 0.5f, 1, 1) },
new Vector4[] { new Vector4(0, 0, 0.5f, 0.5f), new Vector4(0.5f, 0, 1, 0.5f), new Vector4(0, 0.5f, 0.5f, 1), new Vector4(0.5f, 0.5f, 1, 1) }
};
static readonly Vector4[][] cascadeRectsWithPadding = {
new Vector4[] { new Vector4(0, 0, 1, 1), new Vector4(0, 0, 1, 1), new Vector4(0, 0, 1, 1), new Vector4(0, 0, 1, 1) },
new Vector4[] { new Vector4(0, 0, 0.5f, 1f), new Vector4(0.5f, 0, 1, 1f), new Vector4(0, 0, 1, 1), new Vector4(0, 0, 1, 1) },
new Vector4[] { new Vector4(0, 0, 0.5f, 0.5f), new Vector4(0.5f, 0, 1, 0.5f), new Vector4(0, 0.5f, 0.5f, 1), new Vector4(0.5f, 0.5f, 1, 1) },
new Vector4[] { new Vector4(0, 0, 0.5f, 0.5f), new Vector4(0.5f, 0, 1, 0.5f), new Vector4(0, 0.5f, 0.5f, 1), new Vector4(0.5f, 0.5f, 1, 1) }
};
static readonly float[] cascadeScales = { 1, 1, 1, 1 };
static RenderTextureDescriptor desc;
GraphicsFormat screenShadowTextureFormat;
public readonly Dictionary<Camera, RTHandle> shadowTextures = new Dictionary<Camera, RTHandle>();
static bool newShadowmap = true;
static readonly float[] autoCascadeScales = new float[4];
public void Dispose () {
foreach (var rt in shadowTextures.Values) {
rt?.Release();
}
shadowTextures.Clear();
m_RenderTarget?.Release();
m_DownscaledRenderTarget?.Release();
}
internal bool Setup (Material material) {
if (settings == null || !settings.enabled || settings.profile == null) return false;
mat = material;
UmbraProfile profile = settings.profile;
GraphicsFormat desiredFormat = profile.shadowSource == ShadowSource.UmbraShadows && profile.blurIterations > 0 && profile.enableContactHardening ? GraphicsFormat.R8G8_UNorm : GraphicsFormat.R8_UNorm;
#if UNITY_2023_1_OR_NEWER
screenShadowTextureFormat = SystemInfo.IsFormatSupported(desiredFormat, GraphicsFormatUsage.Linear | GraphicsFormatUsage.Render)
#else
screenShadowTextureFormat = RenderingUtils.SupportsGraphicsFormat(desiredFormat, FormatUsage.Linear | FormatUsage.Render)
#endif
? desiredFormat
: GraphicsFormat.B8G8R8A8_UNorm;
if (usesCachedShadowmap) {
ConfigureInput(ScriptableRenderPassInput.None);
}
else {
if (profile.shadowSource == ShadowSource.UmbraShadows && (profile.effectiveNormalsSource == NormalSource.NormalsPass || profile.downsample || profile.forceDepthPrepass)) {
ConfigureInput(ScriptableRenderPassInput.Depth | ScriptableRenderPassInput.Normal);
}
else {
ConfigureInput(ScriptableRenderPassInput.Depth);
}
}
return mat != null;
}
#if !UNITY_6000_3_OR_NEWER
#if UNITY_2023_3_OR_NEWER
[Obsolete]
#endif
public override void OnCameraSetup (CommandBuffer cmd, ref RenderingData renderingData) {
desc = renderingData.cameraData.cameraTargetDescriptor;
desc.depthBufferBits = 0;
desc.msaaSamples = 1;
desc.graphicsFormat = screenShadowTextureFormat;
if (settings == null || settings.profile == null) return;
UmbraProfile profile = settings.profile;
if (profile.downsample && !profile.preserveEdges) {
desc.width /= 2;
desc.height /= 2;
}
Camera cam = renderingData.cameraData.camera;
#if UNITY_EDITOR
if (profile.frameSkipOptimization && Application.isPlaying) {
#else
if (profile.frameSkipOptimization) {
#endif
newShadowmap = !shadowTextures.TryGetValue(cam, out m_RenderTarget);
}
#if UNITY_6000_0_OR_NEWER
if (RenderingUtils.ReAllocateHandleIfNeeded(ref m_RenderTarget, desc, FilterMode.Point, TextureWrapMode.Clamp, name: "_ScreenSpaceShadowmapTexture")) {
#else
if (RenderingUtils.ReAllocateIfNeeded(ref m_RenderTarget, desc, FilterMode.Point, TextureWrapMode.Clamp, name: "_ScreenSpaceShadowmapTexture")) {
#endif
newShadowmap = true;
}
if (newShadowmap) {
shadowTextures[cam] = m_RenderTarget;
}
cmd.SetGlobalTexture(m_RenderTarget.name, m_RenderTarget.nameID);
ConfigureTarget(m_RenderTarget);
ConfigureClear(ClearFlag.None, Color.white);
}
#endif
#if !UNITY_6000_3_OR_NEWER
#if UNITY_2023_3_OR_NEWER
[Obsolete]
#endif
public override void Execute (ScriptableRenderContext context, ref RenderingData renderingData) {
if (mat == null) {
Debug.LogError("Umbra material not initialized");
return;
}
UmbraProfile profile = settings.profile;
var cmd = renderingData.commandBuffer;
using (new ProfilingScope(cmd, m_ProfilingSampler)) {
int frameCount = Time.frameCount;
#if UNITY_EDITOR
bool useFrame = !Application.isPlaying || !profile.frameSkipOptimization || newShadowmap || !usesCachedShadowmap;
#else
bool useFrame = !profile.frameSkipOptimization || newShadowmap || !usesCachedShadowmap;
#endif
if (useFrame) {
cachedShadowmapTimestap = frameCount;
newShadowmap = false;
RTHandle shadowsHandle;
if (profile.downsample && profile.preserveEdges) {
desc.width /= 2;
desc.height /= 2;
#if UNITY_6000_0_OR_NEWER
RenderingUtils.ReAllocateHandleIfNeeded(ref m_DownscaledRenderTarget, desc, FilterMode.Point, TextureWrapMode.Clamp);
#else
RenderingUtils.ReAllocateIfNeeded(ref m_DownscaledRenderTarget, desc, FilterMode.Point, TextureWrapMode.Clamp);
#endif
shadowsHandle = m_DownscaledRenderTarget;
}
else {
shadowsHandle = m_RenderTarget;
}
int cascadeCount = renderingData.shadowData.mainLightShadowCascadesCount;
float farClipPlane = renderingData.cameraData.camera.farClipPlane;
UniversalRenderPipelineAsset urpAsset = GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset;
float shadowMaxDistance = urpAsset.shadowDistance;
Pass castShadowsPass;
if (profile.shadowSource == ShadowSource.UnityShadows) {
castShadowsPass = Pass.UnityShadows;
}
else {
castShadowsPass = Pass.UmbraCastShadows;
if (profile.transparentReceiverPlane) {
mat.EnableKeyword(ShaderParams.SKW_RECEIVER_PLANE);
cmd.SetGlobalFloat(ShaderParams.ReceiverPlaneAltitude, profile.receiverPlaneAltitude);
cmd.SetGlobalVector(ShaderParams.ShadowData3, new Vector4(10f, 0.001f, 0, profile.blurEdgeSharpness));
}
else {
mat.DisableKeyword(ShaderParams.SKW_RECEIVER_PLANE);
cmd.SetGlobalVector(ShaderParams.ShadowData3, new Vector4(profile.blurDepthAttenStart / farClipPlane, profile.blurDepthAttenLength / farClipPlane, profile.blurGrazingAttenuation, profile.blurEdgeSharpness));
}
cmd.SetGlobalVector(ShaderParams.ShadowData, new Vector4(profile.sampleCount, 1024 / Mathf.Pow(2, profile.posterization), profile.blurEdgeTolerance * 1000f, (profile.blurDepthAttenStart + profile.blurDepthAttenLength) / farClipPlane));
float shadowMaxDepth = profile.transparentReceiverPlane ? 2 : shadowMaxDistance / farClipPlane;
cmd.SetGlobalVector(ShaderParams.ShadowData2, new Vector4(1f - profile.contactStrength, profile.distantSpread, shadowMaxDepth, profile.lightSize * 0.02f));
cmd.SetGlobalVector(ShaderParams.ShadowData4, new Vector4(profile.occludersCount, profile.occludersSearchRadius * 0.02f, profile.contactStrength > 0 ? profile.contactStrengthKnee * 0.1f : 0.00001f, profile.maskScale));
cmd.SetGlobalVector(ShaderParams.SourceSize, new Vector4(desc.width, desc.height, 0, 0));
cmd.SetGlobalInt(ShaderParams.EarlyOutSamples, profile.earlyOutSamples);
if (cascadeCount > 1) {
VisibleLight shadowLight = renderingData.lightData.visibleLights[shadowLightIndex];
float shadowNearPlane = shadowLight.light.shadowNearPlane;
for (int k = 0; k < cascadeCount; k++) {
renderingData.cullResults.ComputeDirectionalShadowMatricesAndCullingPrimitives(shadowLightIndex,
k, cascadeCount, renderingData.shadowData.mainLightShadowCascadesSplit, urpAsset.mainLightShadowmapResolution, shadowNearPlane, out _, out Matrix4x4 proj,
out _);
Matrix4x4 invProj = proj.inverse;
autoCascadeScales[k] = Mathf.Abs(invProj.MultiplyPoint(ShaderParams.Vector3Back).z - invProj.MultiplyPoint(ShaderParams.Vector3Forward).z) / 100f;
}
Vector4[] cascadeRectsTemp = cascadeRectsWithPadding[cascadeCount - 1];
float texel = 1f / urpAsset.mainLightShadowmapResolution;
float padding = texel;
for (int c = 0; c < 4; c++) {
Vector4 defaultRect = cascadeRects[cascadeCount - 1][c];
Vector4 rect = cascadeRectsTemp[c];
rect.x = defaultRect.x + padding;
rect.y = defaultRect.y + padding;
rect.z = defaultRect.z - padding;
rect.w = defaultRect.w - padding;
cascadeRectsTemp[c] = rect;
}
cmd.SetGlobalVectorArray(ShaderParams.UmbraCascadeRects, cascadeRectsTemp);
cascadeScales[0] = profile.cascade1Scale * autoCascadeScales[0];
cascadeScales[1] = profile.cascade2Scale * autoCascadeScales[1];
cascadeScales[2] = profile.cascade3Scale * autoCascadeScales[2];
cascadeScales[3] = profile.cascade4Scale * autoCascadeScales[3];
cmd.SetGlobalFloatArray(ShaderParams.UmbraCascadeScales, cascadeScales);
}
if ((UmbraSoftShadows.isDeferred && profile.normalsSource == NormalSource.GBufferNormals) || profile.effectiveNormalsSource == NormalSource.NormalsPass || profile.downsample) {
mat.EnableKeyword(ShaderParams.SKW_NORMALS_TEXTURE);
}
else {
mat.DisableKeyword(ShaderParams.SKW_NORMALS_TEXTURE);
}
#if !UNITY_WEBGL
if (profile.enableContactHardening) {
mat.EnableKeyword(ShaderParams.SKW_CONTACT_HARDENING);
}
else
#endif
{
mat.DisableKeyword(ShaderParams.SKW_CONTACT_HARDENING);
}
mat.DisableKeyword(ShaderParams.SKW_LOOP_STEP_X3);
mat.DisableKeyword(ShaderParams.SKW_LOOP_STEP_X2);
if (profile.loopStepOptimization == LoopStep.x3) {
mat.EnableKeyword(ShaderParams.SKW_LOOP_STEP_X3);
}
else if (profile.loopStepOptimization == LoopStep.x2) {
mat.EnableKeyword(ShaderParams.SKW_LOOP_STEP_X2);
}
if (profile.style == Style.Textured && profile.maskTexture != null) {
mat.EnableKeyword(ShaderParams.SKW_MASK_TEXTURE);
mat.SetTexture(ShaderParams.MaskTexture, profile.maskTexture);
}
else {
mat.DisableKeyword(ShaderParams.SKW_MASK_TEXTURE);
}
}
// Resolve screen space shadows
Blitter.BlitCameraTexture(cmd, m_RenderTarget, shadowsHandle, mat, (int)castShadowsPass);
// Blend cascades 0 & 1
if (profile.shadowSource == ShadowSource.UmbraShadows) {
if (profile.blendCascades && cascadeCount > 1) {
cmd.SetGlobalVector(ShaderParams.BlendCascadeData, new Vector4(profile.cascade1BlendingStrength * 100f, profile.cascade2BlendingStrength * 100f, profile.cascade3BlendingStrength * 100f, 1f));
Blitter.BlitCameraTexture(cmd, shadowsHandle, shadowsHandle, mat, (int)Pass.CascadeBlending);
}
}
// Add contact shadows
if (profile.contactShadows) {
if (!settings.debugShadows && profile.actualContactShadowsInjectionPoint == ContactShadowsInjectionPoint.ShadowTexture) {
Blitter.BlitCameraTexture(cmd, shadowsHandle, shadowsHandle, mat, (int)Pass.ContactShadows);
}
}
// Downscale depth for upscaler
if (profile.downsample && profile.preserveEdges) {
RenderTextureDescriptor downscampledDepthDesc = desc;
downscampledDepthDesc.colorFormat = RenderTextureFormat.RFloat;
cmd.GetTemporaryRT(ShaderParams.DownsampledDepth, downscampledDepthDesc);
FullScreenBlit(cmd, ShaderParams.DownsampledDepth, mat, (int)Pass.DownsampledDepth);
mat.EnableKeyword(ShaderParams.SKW_PRESERVE_EDGES);
}
else {
mat.DisableKeyword(ShaderParams.SKW_PRESERVE_EDGES);
}
if (profile.shadowSource == ShadowSource.UnityShadows) {
if (profile.downsample && profile.preserveEdges) {
// upscale
FullScreenBlit(cmd, m_DownscaledRenderTarget, m_RenderTarget, mat, (int)Pass.ComposeUnity);
}
}
else {
if (profile.style == Style.Default && profile.blurIterations > 0) {
cmd.SetGlobalFloat(ShaderParams.BlurSpread, profile.blurSpread);
// perform blur
cmd.GetTemporaryRT(ShaderParams.BlurTemp, desc);
cmd.GetTemporaryRT(ShaderParams.BlurTemp2, desc);
cmd.SetGlobalFloat(ShaderParams.BlurScale, 1f);
RenderTargetIdentifier shadowsRT = shadowsHandle;
RenderTargetIdentifier blurredRT = ShaderParams.BlurTemp2;
if (profile.blurType == BlurType.Box) {
for (int k = 0; k < profile.blurIterations; k++) {
blurredRT = (k % 2) == 0 ? ShaderParams.BlurTemp2 : ShaderParams.BlurTemp;
FullScreenBlit(cmd, shadowsRT, blurredRT, mat, (int)Pass.BoxBlur);
shadowsRT = blurredRT;
cmd.SetGlobalFloat(ShaderParams.BlurScale, k + 1f);
}
}
else {
if (profile.blurType == BlurType.Gaussian15) {
mat.EnableKeyword(ShaderParams.SKW_BLUR_HQ);
}
else {
mat.DisableKeyword(ShaderParams.SKW_BLUR_HQ);
}
FullScreenBlit(cmd, shadowsRT, ShaderParams.BlurTemp, mat, (int)Pass.BlurHoriz);
cmd.SetGlobalFloat(ShaderParams.BlurScale, 1f);
for (int k = 0; k < profile.blurIterations - 1; k++) {
FullScreenBlit(cmd, ShaderParams.BlurTemp, ShaderParams.BlurTemp2, mat, (int)Pass.BlurVert);
cmd.SetGlobalFloat(ShaderParams.BlurScale, k + 2f);
FullScreenBlit(cmd, ShaderParams.BlurTemp2, ShaderParams.BlurTemp, mat, (int)Pass.BlurHoriz);
}
FullScreenBlit(cmd, ShaderParams.BlurTemp, ShaderParams.BlurTemp2, mat, (int)Pass.BlurVert);
}
// blit blurred shadows
FullScreenBlit(cmd, blurredRT, m_RenderTarget, mat, (int)Pass.ComposeWithBlending);
}
else if (profile.downsample && profile.preserveEdges) {
// upscale
FullScreenBlit(cmd, m_DownscaledRenderTarget, m_RenderTarget, mat, (int)Pass.Compose);
}
}
}
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadows, false);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadowCascades, false);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadowScreen, true);
}
}
#endif
static Mesh _fullScreenMesh;
static Mesh fullscreenMesh {
get {
if (_fullScreenMesh != null) {
return _fullScreenMesh;
}
float num = 1f;
float num2 = 0f;
Mesh val = new Mesh();
_fullScreenMesh = val;
_fullScreenMesh.SetVertices(new List<Vector3> {
new Vector3 (-1f, -1f, 0f),
new Vector3 (-1f, 1f, 0f),
new Vector3 (1f, -1f, 0f),
new Vector3 (1f, 1f, 0f)
});
_fullScreenMesh.SetUVs(0, new List<Vector2> {
new Vector2 (0f, num2),
new Vector2 (0f, num),
new Vector2 (1f, num2),
new Vector2 (1f, num)
});
_fullScreenMesh.SetIndices(new int[6] { 0, 1, 2, 2, 1, 3 }, (MeshTopology)0, 0, false);
_fullScreenMesh.UploadMeshData(true);
return _fullScreenMesh;
}
}
static void FullScreenBlit (CommandBuffer cmd, RenderTargetIdentifier destination, Material material, int passIndex) {
destination = new RenderTargetIdentifier(destination, 0, CubemapFace.Unknown, -1);
cmd.SetRenderTarget(destination);
cmd.DrawMesh(fullscreenMesh, Matrix4x4.identity, material, 0, passIndex);
}
static void FullScreenBlit (CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, Material material, int passIndex) {
destination = new RenderTargetIdentifier(destination, 0, CubemapFace.Unknown, -1);
cmd.SetRenderTarget(destination);
cmd.SetGlobalTexture(ShaderParams.MainTex, source);
cmd.DrawMesh(fullscreenMesh, Matrix4x4.identity, material, 0, passIndex);
}
}
private partial class UmbraScreenSpaceShadowsPostPass : ScriptableRenderPass {
// Profiling tag
private static string m_ProfilerTag = "Umbra Screen Space Shadows Post Pass";
private static ProfilingSampler m_ProfilingSampler = new ProfilingSampler(m_ProfilerTag);
private static readonly RTHandle k_CurrentActive = RTHandles.Alloc(BuiltinRenderTextureType.CurrentActive);
#if !UNITY_6000_3_OR_NEWER
#if UNITY_2023_3_OR_NEWER
[Obsolete]
#endif
public override void Configure (CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor) {
ConfigureTarget(k_CurrentActive);
}
#endif
#if !UNITY_6000_3_OR_NEWER
#if UNITY_2023_3_OR_NEWER
[Obsolete]
#endif
public override void Execute (ScriptableRenderContext context, ref RenderingData renderingData) {
var cmd = renderingData.commandBuffer;
using (new ProfilingScope(cmd, m_ProfilingSampler)) {
ShadowData shadowData = renderingData.shadowData;
int cascadesCount = shadowData.mainLightShadowCascadesCount;
bool mainLightShadows = renderingData.shadowData.supportsMainLightShadows;
bool receiveShadowsNoCascade = mainLightShadows && cascadesCount == 1;
bool receiveShadowsCascades = mainLightShadows && cascadesCount > 1;
// Before transparent object pass, force to disable screen space shadow of main light
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadowScreen, false);
// then enable main light shadows with or without cascades
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadows, receiveShadowsNoCascade);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadowCascades, receiveShadowsCascades);
}
}
#endif
}
private partial class UmbraDebugPass : ScriptableRenderPass {
// Profiling tag
private static string m_ProfilerTag = "Umbra Debug Pass";
private static ProfilingSampler m_ProfilingSampler = new ProfilingSampler(m_ProfilerTag);
RTHandle source;
static UmbraScreenSpaceShadowsPass shadowPass;
public void Setup (UmbraScreenSpaceShadowsPass shadowPass) {
UmbraDebugPass.shadowPass = shadowPass;
if (settings.debugShadows) {
ConfigureInput(ScriptableRenderPassInput.Depth);
}
}
#if !UNITY_6000_3_OR_NEWER
#if UNITY_2023_3_OR_NEWER
[Obsolete]
#endif
public override void OnCameraSetup (CommandBuffer cmd, ref RenderingData renderingData) {
source = renderingData.cameraData.renderer.cameraColorTargetHandle;
}
#if UNITY_2023_3_OR_NEWER
[Obsolete]
#endif
public override void Execute (ScriptableRenderContext context, ref RenderingData renderingData) {
Material mat = UmbraScreenSpaceShadowsPass.mat;
if (mat == null) return;
RTHandle shadows = null;
Camera cam = renderingData.cameraData.camera;
Dictionary<Camera, RTHandle> shadowTextures = shadowPass.shadowTextures;
if (shadowTextures != null) {
shadows = shadowTextures[cam];
}
if (shadows == null) return;
var cmd = renderingData.commandBuffer;
using (new ProfilingScope(cmd, m_ProfilingSampler)) {
Blitter.BlitCameraTexture(cmd, shadows, source, mat, (int)Pass.DebugShadows);
if (settings.debugShadows && settings.profile != null && settings.profile.contactShadows) {
Blitter.BlitCameraTexture(cmd, source, source, mat, (int)Pass.ContactShadowsAfterOpaque);
}
}
}
#endif
}
private partial class UmbraContactShadowsAfterOpaquePass : ScriptableRenderPass {
// Profiling tag
private static string m_ProfilerTag = "Umbra Contact Shadows After Opaque Pass";
private static ProfilingSampler m_ProfilingSampler = new ProfilingSampler(m_ProfilerTag);
RTHandle source;
public void Setup () {
ConfigureInput(ScriptableRenderPassInput.Depth);
}
#if !UNITY_6000_3_OR_NEWER
#if UNITY_2023_3_OR_NEWER
[Obsolete]
#endif
public override void OnCameraSetup (CommandBuffer cmd, ref RenderingData renderingData) {
source = renderingData.cameraData.renderer.cameraColorTargetHandle;
ConfigureTarget(source);
}
#if UNITY_2023_3_OR_NEWER
[Obsolete]
#endif
public override void Execute (ScriptableRenderContext context, ref RenderingData renderingData) {
Material mat = UmbraScreenSpaceShadowsPass.mat;
if (mat == null || source.rt == null) return;
var cmd = renderingData.commandBuffer;
using (new ProfilingScope(cmd, m_ProfilingSampler)) {
UmbraProfile profile = settings.profile;
if (profile.transparentReceiverPlane) {
cmd.SetGlobalFloat(ShaderParams.ReceiverPlaneAltitude, profile.receiverPlaneAltitude);
}
cmd.SetGlobalVector(ShaderParams.SourceSize, new Vector4(source.rt.width, source.rt.height, 0, 0));
Blitter.BlitCameraTexture(cmd, source, source, mat, (int)Pass.ContactShadowsAfterOpaque);
}
}
#endif
}
private partial class UmbraOverlayShadows : ScriptableRenderPass {
// Profiling tag
private static string m_ProfilerTag = "Umbra Overlay Shadows";
private static ProfilingSampler m_ProfilingSampler = new ProfilingSampler(m_ProfilerTag);
RTHandle source;
#if !UNITY_6000_3_OR_NEWER
#if UNITY_2023_3_OR_NEWER
[Obsolete]
#endif
public override void OnCameraSetup (CommandBuffer cmd, ref RenderingData renderingData) {
source = renderingData.cameraData.renderer.cameraColorTargetHandle;
ConfigureTarget(source);
}
#if UNITY_2023_3_OR_NEWER
[Obsolete]
#endif
public override void Execute (ScriptableRenderContext context, ref RenderingData renderingData) {
Material mat = UmbraScreenSpaceShadowsPass.mat;
if (mat == null || source == null) return;
var cmd = renderingData.commandBuffer;
using (new ProfilingScope(cmd, m_ProfilingSampler)) {
Color shadowColor = settings.profile.overlayShadowsColor;
shadowColor.a = settings.profile.overlayShadowsIntensity;
mat.SetColor(ShaderParams.OverlayShadowColor, shadowColor);
Blitter.BlitCameraTexture(cmd, source, source, mat, (int)Pass.OverlayShadows);
}
}
#endif
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 163d34cee9b7a428d9899ab92abd7e0d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,61 @@
using UnityEngine;
namespace Umbra {
public enum ContactShadowsSource {
DirectionalLight,
PointLights
}
[ExecuteAlways]
[HelpURL("https://kronnect.com/docs/umbra/")]
public class UmbraSoftShadows : MonoBehaviour {
[Tooltip("Currently used umbra profile with settings")]
public UmbraProfile profile;
[Tooltip("Source of contact shadows")]
public ContactShadowsSource contactShadowsSource = ContactShadowsSource.DirectionalLight;
[Tooltip("Object whose position is used to determine if it's inside point light volumes")]
public Transform pointLightsTrigger;
public bool debugShadows;
public static bool installed;
public static bool isDeferred;
public static UmbraSoftShadows instance;
private void OnEnable () {
CheckProfile();
instance = this;
}
private void OnDisable () {
UmbraRenderFeature.UnregisterUmbraLight(this);
instance = null;
}
void OnValidate () {
CheckProfile();
}
private void Reset () {
CheckProfile();
}
void CheckProfile () {
if (profile == null) {
profile = ScriptableObject.CreateInstance<UmbraProfile>();
profile.name = "New Umbra Profile";
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(this);
#endif
}
UmbraRenderFeature.RegisterUmbraLight(this);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7e828e348ac39438eb8ae845fe499ae5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,3 @@
{
"reference": "GUID:15fc0a57446b3144c949da3e2b9737a9"
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7aeef6f5814744ae3a7b75542a11ec53
AssemblyDefinitionReferenceImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: