日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Unity URP中的多Pass Shader和Planer shadow

發布時間:2023/12/13 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Unity URP中的多Pass Shader和Planer shadow 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一 .Unity移動端軟陰影技術總結:

https://blog.csdn.net/jxw167/article/details/82422891

二. 平面陰影的原理

https://zhuanlan.zhihu.com/p/42781261

https://zhuanlan.zhihu.com/p/31504088

王者榮耀游戲使用的就是該方法,已經有上線產品驗證過的方法,這說明我們的游戲產品也可以使用,該技術叫平面投影陰影(Planar Projected Shadows)技術,由Jim Blinn 1988年提出。http://www.twinklingstar.cn/2015/1717/tech-of-shadows/#21_Blinns
它實現的原理是:通過相似三角形求一個物體每一個頂點在某個平面上的投影位置,說白了就是求直線在平面上的交點。進一步通俗點講:物體上的某一點,以直線光源的方向作為方向,從該點出發,移動一定距離,使得該點落在要顯示陰影的平面上(比如地表),隨后將該點顯示為陰影即可。

建議大家在平時可以閱讀一下幾個比較好的會議論文:GDC系列文章和Siggraph系列文章,這個兩個會議的論文都是代表當前比較超前的算法實現,這些算法我們可以將其用Unity或者UE4其他引擎實現出來增加渲染效果。

線段與平面的交點推導(很重要):

?

?三. 平面陰影的實現

1.第一個pass正常渲染物體,根據各項目的需求實現(跟陰影實現無關)

2.另一個pass渲染該物體的陰影

陰影pass的實現:

1.從C#腳本中傳入Shader需要投影的平面及一些相關信息

public Light mainLight;private Vector4 _ShadowFadeParams = new Vector4(0.0f, 1.5f, 0.7f, 0.0f);private void UpdateShader(){Vector4 worldpos = transform.position;Vector3 shadowPlaneNrm = transform.up;//計算平面法線與平面上某一點的點乘,由于人物行走在平面上,人物腳下的點必定在平面上float nrmDotPos = Vector3.Dot(shadowPlaneNrm, worldpos);// Vector4 projdir = new Vector4(-0.2f,-0.8f,-0.6f,0);Vector4 projdir = mainLight.transform.forward;//Debug.Log("projdir" + projdir);Material mat = Renderer.material;// foreach (var mat in mMatList)// {if (mat == null)return;mat.SetVector("_WorldPos", worldpos);mat.SetVector("_ShadowProjDir", projdir);// mat.SetVector("_ShadowPlane", new Vector4(2.289143f, -11.88877f, 28.79983f, 0.0f));mat.SetVector("_ShadowPlane", new Vector4(shadowPlaneNrm.x, shadowPlaneNrm.y, shadowPlaneNrm.z, nrmDotPos));mat.SetVector("_ShadowFadeParams", _ShadowFadeParams);mat.SetFloat("_ShadowFalloff", 1.35f);// }}

2.頂點Shader計算該點在陰影平面的投影

v2f vert(appdata v){v2f o;float3 lightdir = normalize(_ShadowProjDir);float3 worldpos = mul(unity_ObjectToWorld, v.vertex).xyz;// _ShadowPlane.w = p0 * n // 平面的w分量就是p0 * nfloat distance = (_ShadowPlane.w - dot(_ShadowPlane.xyz, worldpos)) / dot(_ShadowPlane.xyz, lightdir.xyz);worldpos = worldpos + distance * lightdir.xyz;o.vertex = mul(unity_MatrixVP, float4(worldpos, 1.0));o.xlv_TEXCOORD0 = _WorldPos.xyz;o.xlv_TEXCOORD1 = worldpos;return o;}

3.片段Shader進行模糊算法等處理,改善陰影效果

float4 frag(v2f i) : SV_Target{float3 posToPlane_2 = (i.xlv_TEXCOORD0 - i.xlv_TEXCOORD1);float4 color;color.xyz = float3(0.0, 0.0, 0.0);// 下面兩種陰影衰減公式都可以使用(當然也可以自己寫衰減公式)// 王者榮耀的衰減公式color.w = (pow((1.0 - clamp(((sqrt(dot(posToPlane_2, posToPlane_2)) * _ShadowInvLen) - _ShadowFadeParams.x), 0.0, 1.0)), _ShadowFadeParams.y) * _ShadowFadeParams.z);// 另外的陰影衰減公式//color.w = 1.0 - saturate(distance(i.xlv_TEXCOORD0, i.xlv_TEXCOORD1) * _ShadowFalloff);return color;}

其中計算核心的兩行代碼就是?

float distance = (_ShadowPlane.w - dot(_ShadowPlane.xyz, worldpos)) / dot(_ShadowPlane.xyz, lightdir.xyz); worldpos = worldpos + distance * lightdir.xyz;

對應的公式就是下式,其中P0和平面法線的點乘是由C#代碼計算后傳入的,存儲在_ShadowPlane的w分量(如果平面是水平的,即法線方向就是y軸的話,?_ShadowPlane的w分量可以直接傳入的是平面的y值)

?

?

四. 平面陰影在URP中的實現

URP中常規渲染是單Pass渲染,平面shadow需要兩個pass,為了實現平面shadow,需要先解決URP中的兩個Pass渲染。

https://blog.csdn.net/nxl76450106/article/details/101290283

在需要執行的第一個pass添加Tags{ "LightMode" = "LightweightForward(或者UniversalForward,或者Universal2D,根據當前正常渲染時使用的render設置)" },第二個pass添加Tags{ "LightMode" = "SRPDefaultUnlit" }即可讓這兩個pass同時生效。

比如我們項目目前用的是Universal2D渲染,即2D的光照渲染,就需要把第一個Pass的Tag設置為Universal2D,此時你會發現如果camera使用的Render不是Universal2D render,就無法渲染出物體。所以總結來講就是camera使用的Render要和Pass中的Tag對應。

解決兩個Pass渲染問題后,第一個pass我直接copy URP內置的SimpleLit函數的光照Pass,第二個Pass用HLSL語言重寫了上邊的CG語言代碼,替換了幾處API:

Pass{Tags{"LightMode" = "SRPDefaultUnlit"}Blend SrcAlpha OneMinusSrcAlphaZWrite OffCull BackColorMask RGBStencil{Ref 0Comp EqualWriteMask 255ReadMask 255//Pass IncrSatPass InvertFail KeepZFail Keep}//CGPROGRAMHLSLPROGRAM#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl"#pragma vertex vert#pragma fragment fragCBUFFER_START(UnityPerFrame)float4x4 unity_MatrixVP;CBUFFER_ENDCBUFFER_START(UnityPerDraw)float4x4 unity_ObjectToWorld;CBUFFER_END#define UNITY_MATRIX_M unity_ObjectToWorldfloat4 _ShadowPlane;float4 _ShadowProjDir;float4 _WorldPos;float _ShadowInvLen;float4 _ShadowFadeParams;float _ShadowFalloff;struct appdata{float4 vertex : POSITION;};struct v2f{float4 vertex : SV_POSITION;float3 xlv_TEXCOORD0 : TEXCOORD0;float3 xlv_TEXCOORD1 : TEXCOORD1;};v2f vert(appdata v){v2f o;float3 lightdir = normalize(_ShadowProjDir);//float3 worldpos = mul(unity_ObjectToWorld, v.vertex).xyz;//float3 worldpos = TransformObjectToWorld(v.vertex.xyz);float4 worldPos = mul(UNITY_MATRIX_M, float4(v.vertex.xyz, 1.0));// _ShadowPlane.w = p0 * n // 平面的w分量就是p0 * nfloat distance = (_ShadowPlane.w - dot(_ShadowPlane.xyz, worldPos.xyz)) / dot(_ShadowPlane.xyz, lightdir.xyz);worldPos = worldPos + distance * float4(lightdir.xyz, 0.0);//o.vertex = mul(unity_MatrixVP, float4(worldpos, 1.0));//o.vertex = TransformWorldToHClip(float4(worldpos, 1.0));o.vertex = mul(unity_MatrixVP, worldPos);o.xlv_TEXCOORD0 = _WorldPos.xyz;o.xlv_TEXCOORD1 = worldPos;return o;}float4 frag(v2f i) : SV_Target{float3 posToPlane_2 = (i.xlv_TEXCOORD0 - i.xlv_TEXCOORD1);float4 color;color.xyz = float3(0.0, 0.0, 0.0);// 下面兩種陰影衰減公式都可以使用(當然也可以自己寫衰減公式)// 王者榮耀的衰減公式color.w = (pow((1.0 - clamp(((sqrt(dot(posToPlane_2, posToPlane_2)) * _ShadowInvLen) - _ShadowFadeParams.x), 0.0, 1.0)), _ShadowFadeParams.y) * _ShadowFadeParams.z);// 另外的陰影衰減公式//color.w = 1.0 - saturate(distance(i.xlv_TEXCOORD0, i.xlv_TEXCOORD1) * _ShadowFalloff);return color;}//ENDCGENDHLSL}

項目鏈接:

https://github.com/Dejavu0709/Plane-Shadow-For-URP.git

?

?

?

總結

以上是生活随笔為你收集整理的Unity URP中的多Pass Shader和Planer shadow的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。