• RenderTextureFormat.Depth和RenderTextureFormat.Shadowmap两种格式的深度图


    shadow acne(阴影失真)和peter panning(阴影悬浮)

    代码:
    https://gitee.com/yichichunshui/mvpmatrix.git
    master分支
    节点:
    8d8cbb5cdf163a3f3b098ce5d292447d623c8bfc

    参考网址:https://blog.csdn.net/qq_37484084/article/details/116093693

    1、material的队列要选择shader中:
    在这里插入图片描述
    2、产生深度的shader

    Shader "LearningShadow/SMCaster"{
        SubShader{
            Fog{Mode Off}
            Lighting Off
            ColorMask 0
            Cull Front
    
            Pass{
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
    
                #include "UnityCG.cginc"
    
                struct v2f {
                    float4 pos : SV_POSITION;
                    float2 depth : TEXCOORD0;
                };
    
                v2f vert(appdata_base v) {
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    UNITY_TRANSFER_DEPTH(o.depth);
                    return o;
                }
    
                fixed4 frag(v2f i) : SV_Target{
                    UNITY_OUTPUT_DEPTH(i.depth);
                }
                ENDCG
            }
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    UNITY_TRANSFER_DEPTH和
    UNITY_OUTPUT_DEPTH
    在这里插入图片描述
    UNITY_TRANSFER_DEPTH居然是空实现;UNITY_OUTPUT_DEPTH返回的是0

    3、开深度图
    shadowTexture = new RenderTexture(shadowResolution, shadowResolution, 24, RenderTextureFormat.Depth);

    4、采样深度之后,要判断是否使用了UNITY_REVERSED_Z

    float2 uv = i.shadowPos.xy / i.shadowPos.w;
    				uv = uv * 0.5 + 0.5;
    				float depth = SAMPLE_DEPTH_TEXTURE(_gShadowTexture, uv);
    				#if defined(UNITY_REVERSED_Z)
    				depth = 1 - depth;
    				#endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    点转换到灯光空间计算深度:

    //计算灯光坐标系下的片元深度
    				float lightCoordDepth = i.shadowPos.z / i.shadowPos.w;
    			#if defined(SHADER_TARGET_GLSL)
    				lightCoordDepth = lightCoordDepth * 0.5 + 0.5;
    			#elif defined(UNITY_REVERSED_Z)
    				lightCoordDepth = 1 - lightCoordDepth;
    			#endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    然后比较:

    //偏移采样深度,避开shadow acne
    				float shadow = (depth < lightCoordDepth - bias) ? 0 : 1;
    
    • 1
    • 2

    当计算的深度lightCoordDepth ,减去bias之后,还大于采样的深度depth,则表明此点在阴影中。

    完整的shader

    Shader "LearningShadow/SMShadow"{
    	SubShader{
    		Tags { "RenderType" = "Opaque" }
    
    		Pass{
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    
    			#include "UnityCG.cginc"
    			#include "Lighting.cginc"
    
    			struct v2f {
    				float4 pos : SV_POSITION;
    				float4 shadowPos : TEXCOORD0;
    				float3 worldPos : TEXCOORD1;
    				float3 worldNormal : TEXCOORD2;
    			};
    
    			float4x4 _gWorldToLight;
    
    			v2f vert(appdata_base v) {
    				v2f o;
    				o.pos = UnityObjectToClipPos(v.vertex);
    				//计算顶点的世界坐标
    				float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
    				//计算顶点的灯光坐标系坐标
    				o.shadowPos = mul(_gWorldToLight, worldPos);
    
    				o.worldPos = worldPos;
    				o.worldNormal = UnityObjectToWorldNormal(v.normal);
    				return o;
    			}
    
    			sampler2D _gShadowTexture;
    			float _gShadowBias;
    
    			fixed4 frag(v2f i) : SV_Target{
    				//构建灯光坐标系下的NDC坐标,作为UV进行深度采样
    				float2 uv = i.shadowPos.xy / i.shadowPos.w;
    				uv = uv * 0.5 + 0.5;
    				float depth = SAMPLE_DEPTH_TEXTURE(_gShadowTexture, uv);
    				#if defined(UNITY_REVERSED_Z)
    				depth = 1 - depth;
    				#endif
    
    				//计算灯光坐标系下的片元深度
    				float lightCoordDepth = i.shadowPos.z / i.shadowPos.w;
    			#if defined(SHADER_TARGET_GLSL)
    				lightCoordDepth = lightCoordDepth * 0.5 + 0.5;
    			#elif defined(UNITY_REVERSED_Z)
    				lightCoordDepth = 1 - lightCoordDepth;
    			#endif
    				//指向灯光方向
    				float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
    				//bias = tan(cos(n·l)),其中n为法向,l指向灯光
    				//我们使用acos(n·l)来获取夹角,然后在求正交值
    				float bias = _gShadowBias * tan(acos(saturate(dot(worldLightDir, i.worldNormal))));
    				bias = clamp(bias, 0, 0.01);
    
    				//偏移采样深度,避开shadow acne
    				float shadow = (depth < lightCoordDepth - bias) ? 0 : 1;
    
    				float3 worldN = normalize(i.worldNormal);
    				float3 worldLight = normalize(UnityWorldSpaceLightDir(i.worldPos));
    				float lambert = saturate(dot(worldN, worldLight));
    
    				float3 col = UNITY_LIGHTMODEL_AMBIENT.xyz + shadow * lambert * _LightColor0.rgb;
    				return fixed4(col, 1);
    			}
    			ENDCG
    		}
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    5、bias的原因
    https://blog.csdn.net/lawest/article/details/106364935

    会出现阴影失真的根本原因是所生成的深度贴图的分辨率是有限的,就会造成在fragment位置处取深度图中的值发生采样就会出现问题,这里我引用知乎用户王十一的回答用的图(懒得自己画)。如图:以四个格子为四个fragment为例,由于深度图分辨率有限四个格子会采样同一个深度值(由于纹理参数设置的是临近GL_NEAREST,设置线性也会有这个问题)。
    ————————————————
    版权声明:本文为CSDN博主「lawest」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/lawest/article/details/106364935

    如图假设采样这个四方格的正中心,假设这个深度值为10
    在这里插入图片描述
    在这里插入图片描述

    这四个fragment分别取名a,b,c,d,由于光源的位置会导致求得的四个距离会不一样,先求a到光源的距离假设为9.8<10,b到光源的距离是11.6 >10,c到光源的距离12.1>10,d到光源的距离9.5<10,。就会导致a和d亮,b和c暗,他们本来应该都是亮的才对。然后整个光源视椎体下各个片段都会出现这个问题,就会出现上面的明暗交错的条纹。

    原文说的解决方法是将fragment到光源的距离适当的缩小bias,就会避免这个问题,但是这种解决方法会带来另外一个问题,那就是peter panning(阴影悬浮),bias越大悬浮的越厉害。
    ————————————————
    版权声明:本文为CSDN博主「lawest」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/lawest/article/details/106364935

    在这里插入图片描述
    6、如果使用RenderTextureFormat.Shadowmap
    则采样的使用,要使用如下的方法采样:
    shadowmap采样
    https://gameinstitute.qq.com/community/detail/124214

    Shader "LearningShadow/SMShadow"{
    	SubShader{
    		Tags { "RenderType" = "Opaque" }
    
    		Pass{
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    
    			#include "UnityCG.cginc"
    			#include "Lighting.cginc"
    
    			struct v2f {
    				float4 pos : SV_POSITION;
    				float4 shadowPos : TEXCOORD0;
    				float3 worldPos : TEXCOORD1;
    				float3 worldNormal : TEXCOORD2;
    			};
    
    			float4x4 _gWorldToLight;
    
    			v2f vert(appdata_base v) {
    				v2f o;
    				o.pos = UnityObjectToClipPos(v.vertex);
    				//计算顶点的世界坐标
    				float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
    				//计算顶点的灯光坐标系坐标
    				o.shadowPos = mul(_gWorldToLight, worldPos);
    
    				o.worldPos = worldPos;
    				o.worldNormal = UnityObjectToWorldNormal(v.normal);
    				return o;
    			}
    
    			//UNITY_DECLARE_SHADOWMAP(_gShadowTexture);
    			//sampler2D _gShadowTexture;
    			float _gShadowBias;
    			//Texture2D _gShadowTexture;
    			//SamplerComparisonState sampler_gShadowTexture;
    
    
    			uniform Texture2D _gShadowTexture;
    			uniform SamplerState sample_gShadowTexture;
    			Texture2D fakePoint;
    			SamplerState samplerfakePoint;
    
    			//使用这种方式采样shadowmap格式的rt,参考:https://gameinstitute.qq.com/community/detail/124214
    			float Sample(float2 uv)
    			{
    				float depth = fakePoint.Sample(samplerfakePoint,float2(0,0)).a; //建立采样器/  
    				for (int j = 0; j < 5; j++)
    				{
    					depth += _gShadowTexture.Sample(samplerfakePoint, uv).r;			//对该点进行反复采样/  
    				}
    				depth -= fakePoint.Sample(samplerfakePoint, float2(0, 0)).a;    //去除多余量/  
    				depth = depth / 5.f;                                            //对采样总和取平均值/  
    				return depth;
    			}
    
    
    			fixed4 frag(v2f i) : SV_Target{
    				//构建灯光坐标系下的NDC坐标,作为UV进行深度采样
    				float2 uv = i.shadowPos.xy / i.shadowPos.w;
    				uv = uv * 0.5 + 0.5;
    				//float depth = SAMPLE_DEPTH_TEXTURE(_gShadowTexture, uv);
    				float depth = Sample(uv);
    				#if defined(UNITY_REVERSED_Z)
    				depth = 1 - depth;
    				#endif
    
    				//计算灯光坐标系下的片元深度
    				float lightCoordDepth = i.shadowPos.z / i.shadowPos.w;
    			#if defined(SHADER_TARGET_GLSL)
    				lightCoordDepth = lightCoordDepth * 0.5 + 0.5;
    			#elif defined(UNITY_REVERSED_Z)
    				lightCoordDepth = 1 - lightCoordDepth;
    			#endif
    				//指向灯光方向
    				float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
    				//bias = tan(cos(n·l)),其中n为法向,l指向灯光
    				//我们使用acos(n·l)来获取夹角,然后在求正交值
    				float bias = _gShadowBias * tan(acos(saturate(dot(worldLightDir, i.worldNormal))));
    				bias = clamp(bias, 0, 0.01);
    
    				//偏移采样深度,避开shadow acne
    				//float shadow = UNITY_SAMPLE_SHADOW(_gShadowTexture, i.shadowPos.xyz);
    				float shadow = (depth < lightCoordDepth - bias) ? 0 : 1;
    				//float shadow = _gShadowTexture.SampleCmpLevelZero(sampler_gShadowTexture, uv, lightCoordDepth);
    				//return shadow;
    
    				float3 worldN = normalize(i.worldNormal);
    				float3 worldLight = normalize(UnityWorldSpaceLightDir(i.worldPos));
    				float lambert = saturate(dot(worldN, worldLight));
    
    				float3 col = UNITY_LIGHTMODEL_AMBIENT.xyz + shadow * lambert * _LightColor0.rgb;
    				return fixed4(col, 1);
    			}
    			ENDCG
    		}
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102

    代码:
    https://gitee.com/yichichunshui/mvpmatrix.git
    master分支
    节点:
    56756bd0386bbabee78f24f14e2910966557bf34

  • 相关阅读:
    Git如何上传代码至GitHub
    JVM调优
    利率里面的BP是什么意思,基准利率bp是什么意思
    Spring源码之九finishRefresh详解
    Python实现猎人猎物优化算法(HPO)优化LightGBM回归模型(LGBMRegressor算法)项目实战
    Centos 7.6 安装部署 openGauss 3.1.0 企业版一主两备集群
    Eureka服务注册中心
    C语言中的类型转换有哪些方式?
    数学建模部分常用模型总结
    微机-------8086/8088寻址方式
  • 原文地址:https://blog.csdn.net/wodownload2/article/details/125016510