Umbra with stage
This commit is contained in:
@@ -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:
|
||||
+15
@@ -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
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 97b280ff217a64e4fbf524cc3adf374a
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+804
@@ -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": []
|
||||
}
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2653b59b7388e4f53806f4ab964d71c8
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3}
|
||||
+135
@@ -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
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2dfb70d5172b43e29db28656b0948e5
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+219
@@ -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
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
+10
@@ -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:
|
||||
Binary file not shown.
@@ -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:
|
||||
Reference in New Issue
Block a user