试了一下unity自带的阴影,发现有接缝问题,
上网找了一些解决方案,都非常庞大,
基本是要自己处理级联阴影
看了urp的build-in之后,想了一个比较暗黑的方式,简单处理一下,运行对比图如下,
左边是unity自带的级联阴影效果,右边是平滑后的级联阴影
思路比较简单,从unity内部函数中抽几个出来改造
计算当前像素点(世界坐标)位于哪个裁切球,代码如下:
强制取某个裁切球的级联阴影映射,代码如下:
本案例只处理第一个裁切球与第二个裁切球过渡效果,
其它的裁切球离摄像机比较远,处不处理影响不大,如果要处理,方法也是相同的
混合两个解析度的阴影代码如下
其它urp管线需要用到的pass DepthOnly ShadowCaster就不说明了,照抄就可以了,以便物体本身也能生成阴影
以下贴出完整的urp shader代码
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
|
Shader "lsc/csm_shader" { Properties { _MainTex( "Texture" , 2D) = "white" {} } SubShader { LOD 100 Tags{ "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "UniversalMaterialType" = "Lit" "IgnoreProjector" = "True" "ShaderModel" = "2.0" } Pass { Name "ForwardLit" Tags{ "LightMode" = "UniversalForward" } HLSLPROGRAM #pragma vertex vert #pragma fragment frag #pragma exclude_renderers gles gles3 glcore #pragma target 4.5 #pragma multi_compile _ _MAIN_LIGHT_SHADOWS #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE #pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS #pragma multi_compile_fragment _ _SHADOWS_SOFT #pragma vertex LitPassVertex #pragma fragment LitPassFragment #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; float3 normal : NORMAL; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; float3 normal : TEXCOORD2; float3 world_pos : TEXCOORD3; }; sampler2D _MainTex; float4 _MainTex_ST; v2f vert(appdata v) { v2f o; VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz); o.vertex = vertexInput.positionCS;; o.uv = TRANSFORM_TEX(v.uv, _MainTex); o.normal = v.normal; o.world_pos = vertexInput.positionWS; return o; } //常规的计算csm纹理映射函数 //unity把所有的级联阴影刷在一个深度纹理 //通过切换shadow coord的方式取不同解析度的光源深度纹理 //每个解析度区间是用裁切球的方式 float4 anhei_TransformWorldToShadowCoord(float3 positionWS) { half cascadeIndex = ComputeCascadeIndex(positionWS); float4 shadowCoord = mul(_MainLightWorldToShadow[cascadeIndex], float4(positionWS, 1.0)); return float4(shadowCoord.xyz, cascadeIndex); } //自定义直接指定取某个区间段级联阴影 float4 anhei_TransformWorldToShadowCoord2( int idx, float3 positionWS) { half cascadeIndex = idx; float4 shadowCoord = mul(_MainLightWorldToShadow[cascadeIndex], float4(positionWS, 1.0)); return float4(shadowCoord.xyz, cascadeIndex); } //常规计算当前像素点(世界坐标)处于哪个裁切球 half anhei_ComputeCascadeIndex(float3 positionWS) { 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)); half4 weights = half4(distances2 < _CascadeShadowSplitSphereRadii); weights.yzw = saturate(weights.yzw - weights.xyz); return 4 - dot(weights, half4(4, 3, 2, 1)); } float4 frag(v2f i) : SV_Target { // sample the texture float4 col = tex2D(_MainTex, i.uv); float3 nml = normalize(i.normal.xyz); int cas_idx_1 = anhei_ComputeCascadeIndex(i.world_pos); Light light_1; Light light_0; half shadow_mix = 1.0f; float mix_fact = 0; if (cas_idx_1 == 0) //只处理第一个裁切球,其它裁切球的太远了,在画面上可能看不见 { float4 shadow_coord0 = anhei_TransformWorldToShadowCoord2(0, i.world_pos); light_0 = GetMainLight(shadow_coord0); float4 shadow_coord1 = anhei_TransformWorldToShadowCoord2(1, i.world_pos); light_1 = GetMainLight(shadow_coord1); shadow_mix = light_1.shadowAttenuation; //离第一个裁切球心距离 float3 fromCenter0 = i.world_pos - _CascadeShadowSplitSpheres0.xyz; float3 first_sphere_dis = length(fromCenter0); //第一个裁切球的半径 float first_sphere_rad = sqrt(_CascadeShadowSplitSphereRadii.x); //做一个简单的插值 mix_fact = clamp((first_sphere_dis) / (first_sphere_rad / 1.0f), 0.0f, 1.0f); shadow_mix = light_0.shadowAttenuation* (1 - mix_fact) + light_1.shadowAttenuation * mix_fact; } else { float4 shadow_coord1 = anhei_TransformWorldToShadowCoord2(1, i.world_pos); light_1 = GetMainLight(shadow_coord1); shadow_mix = light_1.shadowAttenuation; } col.rgb = shadow_mix * col.rgb; return col; } ENDHLSL } // ShadowCaster 将物体写入光源的深度纹理 // 使用自定义的shadow caster, urp会从光源处拍摄场影 pass { Tags{ "LightMode" = "ShadowCaster" } HLSLPROGRAM #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float3 _LightDirection; v2f vert(appdata v) { v2f o; float3 world_pos = TransformObjectToWorld(v.vertex); float3 world_nml = TransformObjectToWorldNormal(v.normal); o.pos = TransformWorldToHClip(ApplyShadowBias(world_pos, world_nml, _LightDirection)); return o; } float4 frag(v2f i) : SV_Target { float4 color; color.xyz = float3(0.0, 0.0, 0.0); return color; } ENDHLSL } // DepthOnly 直接使用内置hlsl代码 Pass { Name "DepthOnly" Tags{ "LightMode" = "DepthOnly" } ZWrite On ColorMask 0 Cull[_Cull] HLSLPROGRAM #pragma exclude_renderers gles gles3 glcore #pragma target 4.5 #pragma vertex DepthOnlyVertex #pragma fragment DepthOnlyFragment // ------------------------------------- // Material Keywords #pragma shader_feature_local_fragment _ALPHATEST_ON #pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A //-------------------------------------- // GPU Instancing #pragma multi_compile_instancing #pragma multi_compile _ DOTS_INSTANCING_ON #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl" #include "Packages/com.unity.render-pipelines.universal/Shaders/DepthOnlyPass.hlsl" ENDHLSL } } } |
以上就是解决Unity urp级联阴影接缝问题的详细内容,更多关于Unity级联阴影的资料请关注服务器之家其它相关文章!
原文链接:https://blog.csdn.net/lsccsl/article/details/118161524