解決Unity urp級聯(lián)陰影接縫問題
試了一下unity自帶的陰影,發(fā)現(xiàn)有接縫問題,
上網(wǎng)找了一些解決方案,都非常龐大,
基本是要自己處理級聯(lián)陰影
看了urp的build-in之后,想了一個比較暗黑的方式,簡單處理一下,運(yùn)行對比圖如下,
左邊是unity自帶的級聯(lián)陰影效果,右邊是平滑后的級聯(lián)陰影
思路比較簡單,從unity內(nèi)部函數(shù)中抽幾個出來改造
計算當(dāng)前像素點(diǎn)(世界坐標(biāo))位于哪個裁切球,代碼如下:
強(qiáng)制取某個裁切球的級聯(lián)陰影映射,代碼如下:
本案例只處理第一個裁切球與第二個裁切球過渡效果,
其它的裁切球離攝像機(jī)比較遠(yuǎn),處不處理影響不大,如果要處理,方法也是相同的
混合兩個解析度的陰影代碼如下
其它urp管線需要用到的pass DepthOnly ShadowCaster就不說明了,照抄就可以了,以便物體本身也能生成陰影
以下貼出完整的urp shader代碼
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; } //常規(guī)的計算csm紋理映射函數(shù) //unity把所有的級聯(lián)陰影刷在一個深度紋理 //通過切換shadow coord的方式取不同解析度的光源深度紋理 //每個解析度區(qū)間是用裁切球的方式 float4 anhei_TransformWorldToShadowCoord(float3 positionWS) { half cascadeIndex = ComputeCascadeIndex(positionWS); float4 shadowCoord = mul(_MainLightWorldToShadow[cascadeIndex], float4(positionWS, 1.0)); return float4(shadowCoord.xyz, cascadeIndex); } //自定義直接指定取某個區(qū)間段級聯(lián)陰影 float4 anhei_TransformWorldToShadowCoord2(int idx, float3 positionWS) { half cascadeIndex = idx; float4 shadowCoord = mul(_MainLightWorldToShadow[cascadeIndex], float4(positionWS, 1.0)); return float4(shadowCoord.xyz, cascadeIndex); } //常規(guī)計算當(dāng)前像素點(diǎn)(世界坐標(biāo))處于哪個裁切球 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)//只處理第一個裁切球,其它裁切球的太遠(yuǎn)了,在畫面上可能看不見 { 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 直接使用內(nèi)置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級聯(lián)陰影接縫問題的詳細(xì)內(nèi)容,更多關(guān)于Unity級聯(lián)陰影的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于C#實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲 C#抓取網(wǎng)頁Html源碼
這篇文章主要為大家詳細(xì)介紹了基于C#實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲的相關(guān)資料,即C#抓取網(wǎng)頁Html源碼,感興趣的小伙伴們可以參考一下2016-03-03winform模擬鼠標(biāo)按鍵的具體實(shí)現(xiàn)
這篇文章介紹了winform模擬鼠標(biāo)按鍵的具體實(shí)現(xiàn),有需要的朋友可以參考一下2013-10-10C# 實(shí)現(xiàn)TXT文檔轉(zhuǎn)Table的示例代碼
這篇文章主要介紹了C# 實(shí)現(xiàn)TXT文檔轉(zhuǎn)Table的示例代碼,幫助大家更好的理解和學(xué)習(xí)c#,感興趣的朋友可以了解下2020-12-12在C#中g(shù)lobal關(guān)鍵字的作用及其用法
global 是 C# 2.0 中新增的關(guān)鍵字,理論上說,如果代碼寫得好的話,根本不需要用到它,但是不排除一些特別的情況,比如修改別人的代碼,本文僅舉例說明。2016-03-03WindowsForm移動一個沒有標(biāo)題欄的窗口的方法
這篇文章主要介紹了WindowsForm移動一個沒有標(biāo)題欄的窗口的方法,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-07-07