這篇文章主要介紹“Unity3D中的水特現(xiàn)模擬雨天”,在日常操作中,相信很多人在Unity3D中的水特現(xiàn)模擬雨天問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Unity3D中的水特現(xiàn)模擬雨天”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
站在用戶的角度思考問題,與客戶深入溝通,找到松溪網(wǎng)站設(shè)計(jì)與松溪網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個性化、用戶體驗(yàn)好的作品,建站類型包括:網(wǎng)站建設(shè)、成都做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、主機(jī)域名、虛擬空間、企業(yè)郵箱。業(yè)務(wù)覆蓋松溪地區(qū)。
在寫實(shí)類游戲制作時,常需要下雨場景的制作,由于日常生活中幾乎所有物體都會被淋濕,所以下雨的制作其實(shí)需要考慮的方面有很多,我們將從粒子,材質(zhì),腳本控制等方面,分析一下應(yīng)該如何渲染一個下雨的場景。
材質(zhì)高光:
Unity的Standard Lighting中,使用GGX作為BRDF的高光算法,GGX具有拖尾感,可以較好的模擬潮濕物體表面的反光效果,首先我們來看一下這張故宮下雨時的照片(圖侵刪):
在普通游客的眼里,地面變得“濕滑”了,然而在渲染工程師的眼里,我們應(yīng)該將這個“濕滑”的效果在PBR中分成四部分:Smoothness的提高,Specular Color的變亮以及GI Occlusion的降低和法線貼圖比重的降低。首先,提高Smoothness是毫無疑問的,要讓物體表面光滑首先要降低粗糙度,但是僅僅降低粗糙度是不行的,水停留在物體表面,這時反射光線的是水而不是物體本身,因此物體本身的漫反射會被降低,因此被淋水的物體看起來顏色會變深,根據(jù)物理反射定律,物體本身色彩無變化,即光線反射比例無變化的情況下,高光程度應(yīng)提高,所以會表現(xiàn)出高光率提高的現(xiàn)象。同樣,因?yàn)榉e水在物體表面的停留,物體受環(huán)境光影響會增大,這時我們應(yīng)該適當(dāng)降低Occlusion Map的影響,并降低法線貼圖的偏移強(qiáng)度,這些在Unity的Standard Shader中都有提供,不需要手動寫Shader,當(dāng)然,如果要處理一個大場景,希望通過全局變量控制,還是應(yīng)該手寫shader進(jìn)行精確優(yōu)化的,因此,希望讀者能夠不依賴Shader Forge, Unity Surface Shader等輔助功能,獨(dú)立編寫基于PBR Shader。至于反射圖像的處理,我們一般通過Reflection Probe, Screen Space Reflection & Planar Reflection等方法實(shí)現(xiàn),這并不在本文討論的范圍內(nèi),我們將會在本專欄的其他文章中詳細(xì)討論。
接下來就是雨水的制作了,雨水本身的粒子效果制作雖然屬于比較初級的粒子制作,甚至Assets Store上也有大量的資源,但是對美術(shù)制作能力有比較高的要求。如果像我一樣,美術(shù)功底奇差無比,完全可以直接買一個效果實(shí)現(xiàn)#手動斜眼#,然后在粒子發(fā)射器上綁定一個腳本,使其始終在攝像機(jī)上方懸停,可以看到在示例中,我們使用粒子碰撞防止穿幫:
在攝像機(jī)第一視角效果如下:
到此,一個簡單的雨水渲染就出來了,然而,整個畫面看起來僵硬死板,這是因?yàn)槲覀儧]有表現(xiàn)出雨滴打在地上的效果,因此,我們需要模擬一個動態(tài)的法線貼圖,讓地面的法線“動起來”,解決的方法有許多,最簡單的方法就是序列幀,在CG軟件(如Houdini,Substance Painter等)中制作序列幀并且渲染,然后在Unity中播放,這當(dāng)然是一種比較簡單的方法,但是同樣也無法實(shí)現(xiàn)真正的實(shí)時與隨機(jī),我們這里則是使用Unity自帶的CommandBuffer進(jìn)行比較底層的圖形繪制,實(shí)現(xiàn)隨機(jī)的雨點(diǎn)特效。
學(xué)習(xí)過渲染管線基礎(chǔ)的朋友都知道,Unity的攝像機(jī)其實(shí)并不是繪制RenderTexture的唯一方法,它只是封裝的比較上層的方法,其實(shí)攝像機(jī)的工作流程就是(剔除->繪制網(wǎng)格->后處理)這三部分,無論是Forward path或是Deferred Shading path,亦或是Unity 2018最新提供的HDRP和LWRP,本質(zhì)上都是這三部,區(qū)別僅僅在于,deferred shading會將光照作為后處理運(yùn)算,而forward path會直接將燈光信息傳入shader中進(jìn)行光影運(yùn)算并直接輸出色彩,而我們這里并不需要動態(tài)剔除,只需要使用command buffer在一個指定的Render Target上進(jìn)行GPU Instance,使用指定的材質(zhì)繪制大量面片即可。有朋友問我為何不使用Unity 2017推出的CustomRenderTexture進(jìn)行繪制,我認(rèn)為,CustomRenderTexture只是給不會渲染底層的程序提供的一個上層封裝,實(shí)際功能不如使用Graphics類或CommandBuffer直接進(jìn)行繪制,后者雖然門檻較高但是功能更加強(qiáng)大,大概相當(dāng)于美圖秀秀和PhotoShop的關(guān)系(只是個人看法,別懟別懟)。
首先我們需要手動生成一個正方形Mesh,并將indexBuffer設(shè)置為四邊形繪制,實(shí)現(xiàn)非常簡單,代碼如下:
由于我們是直接往屏幕上繪制的,所以根本不需要考慮ViewProjectionMatrix的問題,直接用NDC坐標(biāo)(-1, 1)進(jìn)行繪制即可,如果直接將這個mesh繪制到RenderTarget上,就是一個覆蓋全屏的Mesh。
接下來我們要讓這個mesh縮小并且隨機(jī)分布在RenderTarget上,實(shí)現(xiàn)雨滴隨機(jī)散落的效果,這時候就需要使用矩陣進(jìn)行變換了,然而,雨滴數(shù)量眾多,在本例中我們繪制了1023個雨點(diǎn),所以很難依靠CPU進(jìn)行迭代繪制,無論是計(jì)算還是Drawcall,消耗都是難以接受的。所以我們使用Compute Shader與Gpu Instance進(jìn)行繪制,大幅度提高運(yùn)算效率。
首先是Compute Shader,這里不贅述如何使用Compute Shader,只是提供Compute Shader的實(shí)現(xiàn)目標(biāo)與過程。實(shí)現(xiàn)目標(biāo):生成1023個隨機(jī)分配位置的矩陣并執(zhí)行1023個計(jì)時器。為何要用計(jì)時器呢,原因很簡單,當(dāng)一個雨點(diǎn)散落到地上時,漣漪應(yīng)該是越來越淺直到消失的,在漣漪消失時更新位置信息,使面片在另一個位置繪制。實(shí)現(xiàn)代碼如下:
這里來解釋一下這段代碼的意義,MatrixBuffer是我們需要使用的1023個坐標(biāo)矩陣,而timeSliceBuffer則是我們需要使用的計(jì)時器,其中float2的x值是計(jì)時器數(shù)值而y值是計(jì)時器速度。_DeltaFlashSpeed則是由腳本傳入的每幀的更新,即Time.DeltaTime * X; 然后是兩個LocalRand函數(shù),使用魔數(shù)運(yùn)算輸出一個偽隨機(jī)數(shù)。其中第一個函數(shù)會輸出一個(-1, 1)區(qū)間的float2隨機(jī)數(shù),用于隨機(jī)生成一個平面位置,而第二個函數(shù)則會輸出一個(0, 1)區(qū)間的float隨機(jī)數(shù),用于生成一個隨機(jī)的計(jì)時器速度。
下面的CSMain函數(shù)就比較簡單了,當(dāng)計(jì)時器數(shù)值>1時,歸0并重新生成隨機(jī)的速度與位置。根據(jù)線代基礎(chǔ),矩陣的M03, M13決定了xy軸的位置,M00,M11則決定了xy軸的Scale,而這里為了偷懶,果斷省略了雨滴大小的隨機(jī),直接用同樣大小的面片。
在ComputeShader中運(yùn)算完畢后,就可以在腳本里獲取計(jì)算的結(jié)果,并且使用運(yùn)算結(jié)果進(jìn)行繪制了,當(dāng)然,在此之前我們需要先進(jìn)行初始化:
這里初始化了Compute Shader,Compute Buffer以及需要用到的GPU Instance材質(zhì)與高斯模糊材質(zhì)(之后會用到)。
接下來就是調(diào)用Compute Shader并使用CommandBuffer進(jìn)行繪制:
首先,指定renderTarget并初始化為(0.5,0.5,1)也就是標(biāo)準(zhǔn)的法線貼圖格式,然后使用Compute Shader輸出的矩陣進(jìn)行Gpu Instance,最后經(jīng)過高斯高斯模糊,使畫面順滑一些。
有了輸入的計(jì)時器與輸入的矩陣,就可以開始繪制波紋了,波紋繪制實(shí)際非常簡單,直接用Alpha Blend實(shí)現(xiàn)減弱效果,用三角函數(shù)實(shí)現(xiàn)波動即可,直接上代碼:
Shader "Unlit/Wave"
{
SubShader
{
Tags { "RenderType"="Opaque" }
ZWrite Off
ZTest Always
Cull Off
Blend oneMinusSrcAlpha srcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#include "UnityCG.cginc"
#pragma target 5.0
#define MAXCOUNT 1023
StructuredBuffer timeSliceBuffer;
struct appdata
{
float4 vertex : POSITION;
float4 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 vertex : SV_POSITION;
float timeSlice : TEXCOORD0;
float2 uv : TEXCOORD1;
};
v2f vert(appdata v, uint instanceID : SV_InstanceID)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
o.vertex = mul(unity_ObjectToWorld, v.vertex);
o.timeSlice = timeSliceBuffer[instanceID].x;
o.uv = v.uv;
return o;
}
#define PI 18.84955592153876
float4 frag(v2f i) : SV_Target
{
float4 c = 1;
float2 dir = i.uv - 0.5;
float len = length(dir);
bool ignore = len > 0.5;
dir /= max(len, 1e-5);
c.xy = (dir * sin(-i.timeSlice * PI + len * 20)) * 0.5 + 0.5;
c.a = ignore ? 1 : i.timeSlice;
return c;
}
ENDCG
}
}
}
shader非常簡單,只是繪制了一個大致效果,最后生成的法線貼圖效果如下:
可以看到,這張對密集恐患者非常友好的圖片,已經(jīng)有了深淺不一的漣漪花紋(雖然比較難看),我們將這張renderTarget放到地面上,效果如下:
可以看到,地面已經(jīng)有了法線的漣漪,最近放假回國探親,只能用家里的古董筆記本寫文章,不過從粒子到動圖繪制,在這臺古董上也只需要4ms左右的運(yùn)算時間,drawcall也因?yàn)間pu instance的原因并沒有額外增加,可以說性能表現(xiàn)比較令人滿意。
到此,關(guān)于“Unity3D中的水特現(xiàn)模擬雨天”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!