In UnityShadowLibrary.cginc I see: #if defined( SHADOWS_SCREEN ) && defined( LIGHTMAP_ON ) #define HANDLE_SHADOWS_BLENDING_IN_GI 1 #endif But I didn't find explanation of SHADOWS_SCREEN macro.When would it be true?
By default, on the desktop and consoles, Unity uses screen space deferred cascaded shadows for the main directional light, for both forward and deferred rendering. This means that the main directional light's shadows are cast on the scene's depth texture and not calculated on the geometry itself. If you disable shadow cascades, or are on a platform that doesn't support using them (mobile) then it doesn't do this. TLDR: SHADOWS_SCREEN is defined when cascaded shadow maps are in use.
Do you mean SHADOWS_SCREEN = using cascaded shadow maps ?And mobile device does not support cascades,hence in mobile device there will never be "#define HANDLE_SHADOWS_BLENDING_IN_GI 1" defined?
Well, specifically SCREEN_SHADOWS means screen space shadows are being used, but cascaded shadow maps are only supported using screen space shadows so they're roughly equivalent. Technically you can disable cascades on desktop, but it'll still use screen space shadows unless you dig a lot deeper into the settings to really disable it (if it's possible at all, some versions of Unity it is not). However any platform that doesn't support cascaded shadow maps, like mobile, don't support them because they don't support screen space shadows. So yes, it will not be defined on mobile.
As I understand Unity realtime shadowing transfers shadow map to screen space coordinate and compare it with depth map to get the final shadowed pixel.Is this correct?If so,the Unity real-time shadows are certainly all "screen space shadows",is that correct?Because of this,I just feel the name of this macro a bit ambiguous.Please let me know if I get it wrong,Thank you bgolus.
Normally shadow maps work by transforming the mesh's vertex positions into light space and comparing the interpolated fragment shader light space position's depth against the shadow map's depth at the particular light space xy coordinate. It's "screen space" in that "light space" is equivalent the position that would be referred to as screen space if the main camera was rendering from the view of the light, but it's not really ever in screen space any more than anything else being rendered by a fragment shader. You'd never refer to something like per pixel Lambert shading as being "screen space", the calculations in the shader are all likely in world or view space. Screen space shadows are done by extrapolating a world position from the camera's depth buffer, (or some other screen space position texture encoding) then transforming that into light space to do the shadow map comparisons. Generally any screen space effect refers to only using data from the scene that's been previously encoded into a full screen texture. Technically any kind of deferred rendering technique is a screen space technique. But I don't really see any ambiguity here as no one ever refers to "light space" as "screen space". However one ambiguity might be mobile deferred rendering. I don't know if SHADOWS_SCREEN is set when rendering deferred shadows.
But I check out this post https://catlikecoding.com/unity/tutorials/rendering/part-7/,it says: "When the main directional light casts shadows, Unity will look for a shader variant that has the SHADOWS_SCREEN keyword enabled. " And in AutoLight.cginc,we can often find comments as below: // ---- Screen space direction light shadows helpers (any version) #if defined (SHADOWS_SCREEN)[/code] // ---- Screen space direction light shadows helpers (any version) #if defined (SHADOWS_SCREEN) ... It seems all these places suggest that the SHADOWS_SCREEN is very related to directional light shadows. And in the UnityComputeForwardShadows function,we can see that,if,as you say,SHADOWS_SCREEN means using cascaded shadows,which will not occur on mobile platforms,then the will be no shadow sampling process for mobile directional light shadows. So still not sure about that.
Yes. That's what I said in my first response. There's no additional in shader filtering done on the shadows, yes. Only direct shadow map sampling. On PC any shadowing real time directional light past the first brightest will be the same as mobile.
If there are only directional lights and "shadow cascades" in quality settings is 0,and it's mobile platform,what kind of shadows are in use? In this situation,does it mean cascaded shadows are not used and so SHADOWS_SCREEN macro is false? On mobile platform,If "shadow cascades = 0" in Quality Settings means "cascaded shadow maps are not in use" so SHADOWS_SCREEN is not defined ,and if there are only directional lights in the scene,I don't see where simple shadow map sampling is happening in this function: Code (CSharp): half UnityComputeForwardShadows(float2 lightmapUV, float3 worldPos, float4 screenPos) { //fade value float zDist = dot(_WorldSpaceCameraPos - worldPos, UNITY_MATRIX_V[2].xyz); float fadeDist = UnityComputeShadowFadeDistance(worldPos, zDist); half realtimeToBakedShadowFade = UnityComputeShadowFade(fadeDist); //baked occlusion if any half shadowMaskAttenuation = UnitySampleBakedOcclusion(lightmapUV, worldPos); half realtimeShadowAttenuation = 1.0f; //directional realtime shadow #if defined (SHADOWS_SCREEN) #if defined(UNITY_NO_SCREENSPACE_SHADOWS) realtimeShadowAttenuation = unitySampleShadow(mul(unity_WorldToShadow[0], unityShadowCoord4(worldPos, 1))); #else //Only reached when LIGHTMAP_ON is NOT defined (and thus we use interpolator for screenPos rather than lightmap UVs). See HANDLE_SHADOWS_BLENDING_IN_GI below. realtimeShadowAttenuation = unitySampleShadow(screenPos); #endif #endif #if defined(UNITY_FAST_COHERENT_DYNAMIC_BRANCHING) && defined(SHADOWS_SOFT) && !defined(LIGHTMAP_SHADOW_MIXING) //avoid expensive shadows fetches in the distance where coherency will be good UNITY_BRANCH if (realtimeToBakedShadowFade < (1.0f - 1e-2f)) { #endif //spot realtime shadow #if (defined (SHADOWS_DEPTH) && defined (SPOT)) unityShadowCoord4 spotShadowCoord = mul(unity_WorldToShadow[0], unityShadowCoord4(worldPos, 1)); realtimeShadowAttenuation = UnitySampleShadowmap(spotShadowCoord); #endif //point realtime shadow #if defined (SHADOWS_CUBE) realtimeShadowAttenuation = UnitySampleShadowmap(worldPos - _LightPositionRange.xyz); #endif #if defined(UNITY_FAST_COHERENT_DYNAMIC_BRANCHING) && defined(SHADOWS_SOFT) && !defined(LIGHTMAP_SHADOW_MIXING) } #endif return UnityMixRealtimeAndBakedShadows(realtimeShadowAttenuation, shadowMaskAttenuation, realtimeToBakedShadowFade); }
Uhhhg... It looks like SHADOWS_SCREEN is likely enabled for directional lights on mobile, but then additionally UNITY_NO_SCREENSPACE_SHADOWS is also enabled for platforms that don't support cascades.
Assume SHADOWS_SCREEN plus UNITY_NO_SCREENSPACE_SHADOWS equals using a single directional light shadows on mobile. then it seems it will directly do simple sampling of shadow map with "unitySampleShadow": Code (CSharp): // ---- Screen space direction light shadows helpers (any version) #if defined (SHADOWS_SCREEN) #if defined(UNITY_NO_SCREENSPACE_SHADOWS) UNITY_DECLARE_SHADOWMAP(_ShadowMapTexture); #define TRANSFER_SHADOW(a) a._ShadowCoord = mul( unity_WorldToShadow[0], mul( unity_ObjectToWorld, v.vertex ) ); inline fixed unitySampleShadow (unityShadowCoord4 shadowCoord) { #if defined(SHADOWS_NATIVE) fixed shadow = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, shadowCoord.xyz); shadow = _LightShadowData.r + shadow * (1-_LightShadowData.r); return shadow; #else ... #endif } #else ... #endif #define SHADOW_COORDS(idx1) unityShadowCoord4 _ShadowCoord : TEXCOORD##idx1; #define SHADOW_ATTENUATION(a) unitySampleShadow(a._ShadowCoord) #endif But in this situation I don't see where does the shadow fadeout is calculated,which is the directional shadow of a object disappears gradually as the camera gets further. In other circumstance,I think the below does this job: Code (CSharp): ///////////////////////////////////////////////////////////////////////// /////////// blend shadow with cam distance /// ///////////////////////////////////////////////////////////////////////// half bakedAtten = UnitySampleBakedOcclusion(giInput.lightmapUV.xy, giInput.worldPos); half zDist = dot(_WorldSpaceCameraPos - giInput.worldPos, UNITY_MATRIX_V[2].xyz); half fadeDist = UnityComputeShadowFadeDistance(giInput.worldPos, zDist); giInput.atten = UnityMixRealtimeAndBakedShadows(giInput.atten, bakedAtten, UnityComputeShadowFade(fadeDist)); But for unitySampleShadow,I don't see that.But the Unity default directional shadow on mobile DOES fade out with camera distance,right.How does it do it?
Code (CSharp): half UnityComputeForwardShadows(float2 lightmapUV, float3 worldPos, float4 screenPos) { ... return UnityMixRealtimeAndBakedShadows(realtimeShadowAttenuation, shadowMaskAttenuation, realtimeToBakedShadowFade); }
If it goes to UnityComputeFowardShadows,it makes sense. But my doubt is if using main directional light to cast shadow means "SHADOWS_SCREEN" (on mobile too) and if the current scene has lightmap baked so "LIGHTMAP_ON" is defined,so the "HANDLE_SHADOWS_BLENDING_IN_GI" will be defined,then there will be no chance for the codes to go to UnityComputeForwardShadows,instead it will goes to SHADOW_ATTENUATION(a) and wind up wtih unitySampleShadow only,and would not have fadeout: Code (CSharp): #if defined(HANDLE_SHADOWS_BLENDING_IN_GI) // handles shadows in the depths of the GI function for performance reasons # define UNITY_SHADOW_COORDS(idx1) SHADOW_COORDS(idx1) # define UNITY_TRANSFER_SHADOW(a, coord) TRANSFER_SHADOW(a) # define UNITY_SHADOW_ATTENUATION(a, worldPos) SHADOW_ATTENUATION(a) #elif defined(SHADOWS_SCREEN) && !defined(LIGHTMAP_ON) && !defined(UNITY_NO_SCREENSPACE_SHADOWS) // no lightmap uv thus store screenPos instead // can happen if we have two directional lights. main light gets handled in GI code, but 2nd dir light can have shadow screen and mask. // - Disabled on DX9 as we don't get valid .zw in vpos // - Disabled on ES2 because WebGL 1.0 seems to have junk in .w (even though it shouldn't) # if defined(SHADOWS_SHADOWMASK) && !defined(SHADER_API_D3D9) && !defined(SHADER_API_GLES) # define UNITY_SHADOW_COORDS(idx1) unityShadowCoord4 _ShadowCoord : TEXCOORD##idx1; # define UNITY_TRANSFER_SHADOW(a, coord) {a._ShadowCoord.xy = coord * unity_LightmapST.xy + unity_LightmapST.zw; a._ShadowCoord.zw = ComputeScreenPos(a.pos).xy;} # define UNITY_SHADOW_ATTENUATION(a, worldPos) UnityComputeForwardShadows(a._ShadowCoord.xy, worldPos, float4(a._ShadowCoord.zw, 0.0, UNITY_SHADOW_W(a.pos.w))); # else # define UNITY_SHADOW_COORDS(idx1) SHADOW_COORDS(idx1) # define UNITY_TRANSFER_SHADOW(a, coord) TRANSFER_SHADOW(a) # define UNITY_SHADOW_ATTENUATION(a, worldPos) UnityComputeForwardShadows(0, worldPos, a._ShadowCoord) # endif #else # if defined(SHADOWS_SHADOWMASK) # define UNITY_SHADOW_COORDS(idx1) unityShadowCoord2 _ShadowCoord : TEXCOORD##idx1; # define UNITY_TRANSFER_SHADOW(a, coord) a._ShadowCoord = coord * unity_LightmapST.xy + unity_LightmapST.zw; # if (defined(SHADOWS_DEPTH) || defined(SHADOWS_SCREEN) || defined(SHADOWS_CUBE) || UNITY_LIGHT_PROBE_PROXY_VOLUME) # define UNITY_SHADOW_ATTENUATION(a, worldPos) UnityComputeForwardShadows(a._ShadowCoord, worldPos, 0) # else # define UNITY_SHADOW_ATTENUATION(a, worldPos) UnityComputeForwardShadows(a._ShadowCoord, 0, 0) # endif # else # define UNITY_SHADOW_COORDS(idx1) SHADOW_COORDS(idx1) # define UNITY_TRANSFER_SHADOW(a, coord) # if (defined(SHADOWS_DEPTH) || defined(SHADOWS_SCREEN) || defined(SHADOWS_CUBE)) # define UNITY_SHADOW_ATTENUATION(a, worldPos) UnityComputeForwardShadows(0, worldPos, 0) # else #if UNITY_LIGHT_PROBE_PROXY_VOLUME # define UNITY_SHADOW_ATTENUATION(a, worldPos) UnityComputeForwardShadows(0, worldPos, 0) #else # define UNITY_SHADOW_ATTENUATION(a, worldPos) UnityComputeForwardShadows(0, 0, 0) #endif # endif # endif #endif
Not so sure what does "float zDist = dot(_WorldSpaceCameraPos - worldPos, UNITY_MATRIX_V[2].xyz);" do here: Code (CSharp): half UnityComputeForwardShadows(float2 lightmapUV, float3 worldPos, float4 screenPos) { //fade value float zDist = dot(_WorldSpaceCameraPos - worldPos, UNITY_MATRIX_V[2].xyz); float fadeDist = UnityComputeShadowFadeDistance(worldPos, zDist); half realtimeToBakedShadowFade = UnityComputeShadowFade(fadeDist); ... As Cg is using row matrix,UNITY_MATRIX_V[2].xyz means the world space's z basis vector in view space.What is the meaning of its dot product with world space view vector("_WorldSpaceCameraPos - worldPos")? If we need only the z value of the transformed vecor,shouldn't we use below instead? Code (CSharp): dot(_WorldSpaceCameraPos - worldPos, float3(UNITY_MATRIX_V[0].z,UNITY_MATRIX_V[1].z,UNITY_MATRIX_V[2].z));
is there a way to force unity to use world space shadow calculation instead of screen space for specific shaders? Turning off shadow cascades is no option. I'm trying to achieve a fake volumetric light effect in Universal RP by having a couple of additive shadow-recieving planes. Maybe sample the shadow-texture and do shadow calculation by myself?
nevermind https://forum.unity.com/threads/wat...adows-universal-render-pipeline-order.748142/ appears to handle the same task
UNITY_MATRIX_V is column major, while UNITY_MATRIX_V[2] means the corresponding row vector. Here, "dot(_WorldSpaceCameraPos - worldPos, UNITY_MATRIX_V[2].xyz);" is equal to "mul(UNITY_MATRIX_V, _WorldSpaceCameraPos - worldPos).z". But matrix multiplication is not necessary here, so Unity use "dot(_WorldSpaceCameraPos - worldPos, UNITY_MATRIX_V[2].xyz);" . About this "dot" code snippet, you can also see this article. Also, Matrix4x4 is also column major, while Matrix4x4[0] is the corresponding row vector.