在Unity中實(shí)現(xiàn)水體交互

本文轉(zhuǎn)自Unity Connect博主 dreamfairy

?效果圖

制作可交互的水體蝶押,大致分為三步

1.標(biāo)記水體碰撞的位置

2.計(jì)算水波的傳遞 通過波動(dòng)公式,3D或者2D 波動(dòng)公式都行

3.水面頂點(diǎn)采樣波動(dòng)傳遞結(jié)果計(jì)算結(jié)果做頂點(diǎn)Y軸偏移

本文參考的波動(dòng)相關(guān)資料https://en.wikipedia.org/wiki/Wave_equationhttps://www.amazon.com/Mathematics-Programming-Computer-Graphics-Third/dp/1435458869 流體 章節(jié)

相關(guān)公式

根據(jù)公式可知波的下次一次傳遞 z(i,j,k+1) 為 當(dāng)前波值+上一次波值+周圍波值

當(dāng)前波值 *= (4-8*c^2*t^2/d^2/d^2)/(u*t)

上一次波值 *= (ut-2) / (ut + 2)

四周波值 *= (2c^2t^2/d^2) / (ut + 2)

其中各參數(shù)含義為 c 波速竭沫, u 粘度, d 波的遞進(jìn)距離, t 為遞進(jìn)時(shí)間

ok~ 我們重頭開始

首先要建立水面

這里直接用Unity Wiki的已有輪子的創(chuàng)建平面膀捷,下載wiki上的代碼撕捍,傳到項(xiàng)目中https://wiki.unity3d.com/index.php/CreatePlane

這里我們直接創(chuàng)建一個(gè)寬10米拿穴,長(zhǎng)10米,間隔100的平面忧风, 間隔越多默色,水體的顆粒感越小

對(duì)應(yīng)本文開頭描述的三大步驟

創(chuàng)建3個(gè)紋理

對(duì)應(yīng)水體碰撞標(biāo)記,傳遞狮腿,渲染

? ? ? ? m_waterWaveMarkTexture = new RenderTexture(WaveTextureResolution, WaveTextureResolution, 0, RenderTextureFormat.Default);

? ? ? ? m_waterWaveMarkTexture.name = "m_waterWaveMarkTexture";

? ? ? ? m_waveTransmitTexture = new RenderTexture(WaveTextureResolution, WaveTextureResolution, 0, RenderTextureFormat.Default);

? ? ? ? m_waveTransmitTexture.name = "m_waveTransmitTexture";

? ? ? ? m_prevWaveMarkTexture = new RenderTexture(WaveTextureResolution, WaveTextureResolution, 0, RenderTextureFormat.Default);

? ? ? ? m_prevWaveMarkTexture.name = "m_prevWaveMarkTexture";

標(biāo)記水體碰撞位置

void WaterPlaneCollider()

? ? {

? ? ? ? hasHit = false;

? ? ? ? if (Input.GetMouseButton(0))

? ? ? ? {

? ? ? ? ? ? Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

? ? ? ? ? ? RaycastHit hitInfo = new RaycastHit();

? ? ? ? ? ? bool ret = Physics.Raycast(ray.origin, ray.direction, out hitInfo);

? ? ? ? ? ? if (ret)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? Vector3 waterPlaneSpacePos = WaterPlane.transform.worldToLocalMatrix * new Vector4(hitInfo.point.x, hitInfo.point.y, hitInfo.point.z, 1);

? ? ? ? ? ? ? ? float dx = (waterPlaneSpacePos.x / WaterPlaneWidth) + 0.5f;

? ? ? ? ? ? ? ? float dy = (waterPlaneSpacePos.z / WaterPlaneLength) + 0.5f;

? ? ? ? ? ? ? ? hitPos.Set(dx, dy);

? ? ? ? ? ? ? ? m_waveMarkParams.Set(dx, dy, WaveRadius * WaveRadius, WaveHeight);

? ? ? ? ? ? ? ? hasHit = true;

? ? ? ? ? ? }

? ? ? ? }

? ? }

由于我們默認(rèn)Raycast 獲取的是碰撞的世界坐標(biāo)腿宰,我們期望的是直接獲取到 [0-1] 范圍的數(shù)值用來(lái)映射到uv空間,直接在 m_waterWaveMarkTexture 進(jìn)行標(biāo)記缘厢, 因此我們乘以一個(gè) world2Local 矩陣變換到本地吃度, 又因?yàn)镃reatePlane默認(rèn)創(chuàng)建的Pivot 位于中心,再除以寬高縮放到1區(qū)間時(shí)贴硫,值域落在[-0.5,0.5]上椿每,因此我們還要做 + 0.5偏移

標(biāo)記水體碰撞Shader

? ? ? ? ? ? ? ? float dx = i.uv.x - _WaveMarkParams.x;

? ? ? ? ? ? ? ? float dy = i.uv.y - _WaveMarkParams.y;

? ? ? ? ? ? ? ? float disSqr = dx * dx + dy * dy;

? ? ? ? ? ? ? ? int hasCol = step(0, _WaveMarkParams.z - disSqr);

? ? ? ? ? ? ? ? float waveValue = DecodeHeight(tex2D(_MainTex, i.uv));

? ? ? ? ? ? ? ? if (hasCol == 1) {

? ? ? ? ? ? ? ? ? ? waveValue = _WaveMarkParams.w;

? ? ? ? ? ? ? ? }

根據(jù)傳入的_WaveMarkParams.xy 跟當(dāng)前uv 對(duì)比,在筆刷范圍內(nèi)的像素標(biāo)記位默認(rèn)波高度

波的傳遞Shader

? ? ? ? ? ? ? ? static const float2 WAVE_DIR[4] = { float2(1, 0), float2(0, 1), float2(-1, 0), float2(0, -1) };

? ? ? ? ? ? ? ? float dx = _WaveTransmitParams.w;

? ? ? ? ? ? ? ? float avgWaveHeight = 0;

? ? ? ? ? ? ? ? for (int s = 0; s < 4; s++)

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? avgWaveHeight += DecodeHeight(tex2D(_MainTex, i.uv + WAVE_DIR[s] * dx));

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? //(2 * c^2 * t^2 / d ^2) / (u * t + 2)*(z(x + dx, y, t) + z(x - dx, y, t) + z(x, y + dy, t) + z(x, y - dy, t);

? ? ? ? ? ? ? ? float agWave = _WaveTransmitParams.z * avgWaveHeight;


? ? ? ? ? ? ? ? // (4 - 8 * c^2 * t^2 / d^2) / (u * t + 2)

? ? ? ? ? ? ? ? float curWave = _WaveTransmitParams.x *? DecodeHeight(tex2D(_MainTex, i.uv));

? ? ? ? ? ? ? ? // (u * t - 2) / (u * t + 2) * z(x,y,z, t - dt) 上一次波浪值 t - dt

? ? ? ? ? ? ? ? float prevWave = _WaveTransmitParams.y * DecodeHeight(tex2D(_PrevWaveMarkTex, i.uv));

? ? ? ? ? ? ? ? //波衰減

? ? ? ? ? ? ? ? float waveValue = (curWave + prevWave + agWave) * _WaveAtten;

最后就是水體的呈現(xiàn),因?yàn)樾枰鲰旤c(diǎn)紋理采樣间护,因此需要至少ES3.0 硬體

v2f vert (appdata v)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? v2f o;

? ? ? ? ? ? ? ? float4 localPos = v.vertex;

? ? ? ? ? ? ? ? float4 waveTransmit = tex2Dlod(_WaveResult, float4(v.uv, 0, 0));

? ? ? ? ? ? ? ? float waveHeight = DecodeFloatRGBA(waveTransmit);

? ? ? ? ? ? ? ? localPos.y += waveHeight * _WaveScale;

? ? ? ? ? ? ? ? float3 worldPos = mul(unity_ObjectToWorld, localPos);

? ? ? ? ? ? ? ? float3 worldSpaceNormal = mul(unity_ObjectToWorld, v.normal);

? ? ? ? ? ? ? ? float3 worldSpaceViewDir = UnityWorldSpaceViewDir(worldPos);

? ? ? ? ? ? ? ? o.vertex = mul(UNITY_MATRIX_VP, float4(worldPos, 1));

? ? ? ? ? ? ? ? o.uv = v.uv;

? ? ? ? ? ? ? ? o.worldSpaceReflect = reflect(-worldSpaceViewDir, worldSpaceNormal);

? ? ? ? ? ? ? ? return o;

? ? ? ? ? ? }

github地址https://github.com/dreamfairy/interactivity-waterplane

原文鏈接:https://connect.unity.com/p/zai-unityzhong-shi-xian-shui-ti-jiao-hu?app=true

歡迎戳上方原文鏈接删壮,下載Unity官方技術(shù)社區(qū)app,發(fā)現(xiàn)更多資源干貨~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末兑牡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子税灌,更是在濱河造成了極大的恐慌均函,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件菱涤,死亡現(xiàn)場(chǎng)離奇詭異苞也,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)粘秆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門如迟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人攻走,你說(shuō)我怎么就攤上這事殷勘。” “怎么了昔搂?”我有些...
    開封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵玲销,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我摘符,道長(zhǎng)贤斜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任逛裤,我火速辦了婚禮瘩绒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘带族。我一直安慰自己锁荔,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開白布炉菲。 她就那樣靜靜地躺著堕战,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拍霜。 梳的紋絲不亂的頭發(fā)上嘱丢,一...
    開封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音祠饺,去河邊找鬼越驻。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的缀旁。 我是一名探鬼主播记劈,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼并巍!你這毒婦竟也來(lái)了目木?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤懊渡,失蹤者是張志新(化名)和其女友劉穎刽射,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體剃执,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡誓禁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肾档。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摹恰。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖怒见,靈堂內(nèi)的尸體忽然破棺而出俗慈,到底是詐尸還是另有隱情,我是刑警寧澤速种,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布姜盈,位于F島的核電站,受9級(jí)特大地震影響配阵,放射性物質(zhì)發(fā)生泄漏馏颂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一棋傍、第九天 我趴在偏房一處隱蔽的房頂上張望救拉。 院中可真熱鬧,春花似錦瘫拣、人聲如沸亿絮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)派昧。三九已至,卻和暖如春拢切,著一層夾襖步出監(jiān)牢的瞬間蒂萎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工淮椰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留五慈,地道東北人纳寂。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像泻拦,于是被迫代替她去往敵國(guó)和親毙芜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 標(biāo)準(zhǔn)表面著色器輸出結(jié)構(gòu) Unity5中争拐,也可以使用基于物理的照明模型腋粥。 使用方式: Surface Shader ...
    阿飛咯閱讀 3,236評(píng)論 0 1
  • 在C語(yǔ)言中,五種基本數(shù)據(jù)類型存儲(chǔ)空間長(zhǎng)度的排列順序是: A)char B)char=int<=float C)ch...
    夏天再來(lái)閱讀 3,340評(píng)論 0 2
  • Unity shader 官網(wǎng)文檔全方位學(xué)習(xí)(一)What?? Shader,看起來(lái)好高級(jí)的樣子架曹,是的灯抛,這是Uni...
    狼之獨(dú)步閱讀 6,025評(píng)論 0 12
  • 繪制虛線其實(shí)簡(jiǎn)單。繪制線段音瓷,然后通過線段的uv坐標(biāo),設(shè)置虛線貼圖就行夹抗。 或者用shader判斷uv坐標(biāo)決定好不要繪...
    SlimID閱讀 3,640評(píng)論 0 1
  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些閱讀 2,029評(píng)論 0 2