激情六月丁香婷婷|亚洲色图AV二区|丝袜AV日韩AV|久草视频在线分类|伊人九九精品视频|国产精品一级电影|久草视频在线99|在线看的av网址|伊人99精品无码|午夜无码视频在线

高校合作1:010-59833514 ?咨詢電話:400-810-1418 服務(wù)與監(jiān)督電話:400-810-1418轉(zhuǎn)接2

「游戲開發(fā)」游戲后期特效 2:相交高亮(掃描效果)

發(fā)布時(shí)間:2024-01-16 14:02:24 瀏覽量:168次

關(guān)注“indienova”,挖掘獨(dú)立游戲的更多樂趣

1介紹

大萌喵現(xiàn)在還只是學(xué)生黨一枚, 對(duì)圖形學(xué)和渲染技術(shù)的理解依然比較膚淺, 如果文章中有不明確甚至出錯(cuò)的地方, 煩請(qǐng)前輩們斧正啦~

OK, 我們進(jìn)入Warming Up環(huán)節(jié)。

2相交高亮(Intersection Highlight)是個(gè)啥

相交高亮, 是一種附加在Mesh上的著色器特效, 其功能是將所有其他穿過該Mesh表面的截面輪廓繪制出來, 產(chǎn)生一種類似于掃描一樣的效果。 多用于科幻類游戲中。

在這里大萌喵要檢討下 ... 這種相交高亮的特效出現(xiàn)的頻次真心不低, 我能確切想起來的實(shí)際應(yīng)用游戲便有殺戮地帶系列,質(zhì)量效應(yīng)系列,泰坦隕落系列和死亡空間系列. 不過大萌喵在youtube上找了好幾圈也沒有找到一個(gè)包含了這個(gè)效果的視頻 ... 所以說只能貼上這張圖啦.。(喵, 下次玩游戲要邊玩邊截圖了哈哈哈哈)

3所以說我們要干啥?

根據(jù)攝像機(jī)的CameraDepthTexture(深度紋理? 不知道這么翻譯對(duì)不對(duì))繪制相交區(qū)域的高亮顏色。

4想看懂這篇文章, 我得知道啥?

對(duì)著色器的混合模式, 深度測(cè)試, 點(diǎn)元著色器和片元著色器有一定了解. 寫作過程中我也會(huì)貼上一些可供查閱的資料。

我順帶著也打算講解下一個(gè)坐標(biāo)轉(zhuǎn)換的原理, 如果想要看懂的話需要一定的線性代數(shù)基礎(chǔ)。

5看完了這篇文章, 我能得到啥?

你會(huì)知道一種優(yōu)雅地使用DepthBuffer的方法。

以及, 說好的源代碼。

大萌喵.不正常模式.SetStatus(false);

大萌喵.SetFace (Face.嚴(yán)肅臉);

6相交高亮著色器工作原理

獲取當(dāng)前攝像機(jī)渲染的場(chǎng)景的DepthBuffer, 在渲染當(dāng)前模型的時(shí)候判斷每一個(gè)經(jīng)過坐標(biāo)變換的片元的世界坐標(biāo)Z是否和DepthBuffer的對(duì)應(yīng)點(diǎn)深度足夠接近. 如果足夠接近, 則將其渲染成另一種顏色.

7首先, 假設(shè)我們什么都不知道

還是那個(gè)熟悉的水壺, 只不過加上了一臺(tái)優(yōu)雅的Macbook(不過為毛那個(gè)桌面長(zhǎng)得有點(diǎn)像OpenSUSE)和一個(gè)凌空飛舞放蕩不羈的鍵盤。當(dāng)然了這不關(guān)鍵, 關(guān)鍵的是后面的那個(gè)黃色的正方體。

我們要實(shí)現(xiàn)的就是那個(gè)正方體的材質(zhì). 從圖中我們清楚的看到, 水壺, 電腦和鍵盤在正方體外面的部分是非常正常的, 在正方體內(nèi)部的部分蒙上了一層黃色。 但是和正方體的相交截面的外輪廓被繪制成了藍(lán)顏色。

到此, 我們能夠推斷出來的事實(shí)有:

  1. Blend Mode為: Blend SrcAlpha OneMinusSrcAlpha 原因很簡(jiǎn)單, 因?yàn)槲覀兡軌蛲ㄟ^正方體看到其后面的物體, 這說明正方體本身的顏色和原本的ColorBuffer的Alpha值被"平分秋色"后進(jìn)行了混合。 依然看不懂的童鞋請(qǐng)參見Unity官方文檔(http://link.zhihu.com/?target=
    https%3A//docs.unity3d.com/Manual/SL-Blend.html).

  2. RenderQueue為Transparent 很明顯, 我們當(dāng)然是希望這個(gè)正方體在Geometry后渲染出來, 這樣才能透過它看到優(yōu)先渲染的Opaque Materials. 關(guān)于Render Order的詳細(xì)描述可以看Unity官方文檔(http://link.zhihu.com/?target=
    https%3A//docs.unity3d.com/462/Documentation/Manual/SL-SubshaderTags.html)。

  3. 正因?yàn)槲覀兊恼襟w是被后渲染出來的, 所以我們可以通過當(dāng)前的ColorBuffer或者是DepthBuffer等資源來以某種方式處理相交截面。


但是不管截面到底是怎么被處理出來的, 我們必須得知道屏幕上某點(diǎn)的世界坐標(biāo)相對(duì)于正方體某個(gè)片元的世界坐標(biāo)的相對(duì)關(guān)系。

很明顯, 我們要做的就是優(yōu)雅地解決第四個(gè)問題。

8如何優(yōu)雅地比較坐標(biāo)

可以通過DepthBuffer, 攝像機(jī)Near Clip Plane, Far Clip Plane, Field of View來計(jì)算出屏幕上每一個(gè)點(diǎn)的世界坐標(biāo), 但是傳統(tǒng)的在片元著色器中計(jì)算世界坐標(biāo)的方式是處理后依次乘以世界-視圖矩陣的逆, 效率堪憂。 就算利用點(diǎn)元著色器預(yù)先計(jì)算視椎體射線, 效率有了些許提升, 也遠(yuǎn)遠(yuǎn)達(dá)不到"優(yōu)雅"的水準(zhǔn)。

(PS: 我會(huì)在后面的文章中詳細(xì)介紹Global Fog后期處理特效, 其中會(huì)對(duì)在片元著色器中通過DepthBuffer計(jì)算世界坐標(biāo)的方法展開討論。 )

說了這么多, 我們發(fā)現(xiàn)直接求世界坐標(biāo)這種套路最直接, 最好理解, 但似乎并不太可取. 那么我們就要思考一個(gè)問題: 我們真的必須得知道具體的世界坐標(biāo)嘛?

通過觀察上面的那張圖, 我們發(fā)現(xiàn)為了確定如何渲染并混合顏色, 我們只需要知道相對(duì)于攝像機(jī)來講, 正方體的片元和原本場(chǎng)景中對(duì)應(yīng)位置的像素誰(shuí)離得更遠(yuǎn)就行了。 也就是說, 我們只需要知道兩個(gè)三維向量的長(zhǎng)度, 也就是兩個(gè)實(shí)數(shù), 而并不需要知道這兩個(gè)三維向量的xyz都分別是什么。

所以說, 求世界坐標(biāo)的話有點(diǎn)兒殺雞用牛刀了。

8如何獲取一個(gè)片元所在屏幕位置的DepthBuffer

如果你不知道DepthBuffer, 或者是Unity的CameraDepthTexture, 那么強(qiáng)烈建議你谷歌下, 要不然接下來的東東就都GG了。

我們是如何知道一個(gè)片元的投影坐標(biāo)的呢? 恐怕下面這段代碼你都看爛了:

o.pos = mul ( UNITY_MATRIX_MVP, v.vertex );

我甚至不用說出o和v的變量聲明以及這段代碼出自何處, 你就知道我在說什么了。 (語(yǔ)氣頗像 ... 額, 專欄還是要辦下去的, 打住)

所以說我們要怎么通過世界坐標(biāo)來將其xy映射到[0, 1]區(qū)間呢? 畢竟只有這樣我們才能采樣DepthBuffer啊! 不用擔(dān)心, Unity都替我們做好了: 在UnityCG.cginc中, 有這么個(gè)函數(shù):

當(dāng)然了并不是要調(diào)用它, 而是要使用ComputeScreenPos函數(shù):

吶, 帶著編譯器指令原封不動(dòng)地搬過來, 大家看起來肯定有點(diǎn)方. 其實(shí)大多數(shù)情況下, ComputeScreenPos函數(shù)可以重寫成以下形式:

傳入Clip Space坐標(biāo)pos, 最終輸出xy在[0, 1]之間, z值為Camera Space深度的結(jié)果。

不過 ... 這個(gè)函數(shù)什么鬼 ... 拿到了Clip Space坐標(biāo)先乘個(gè)0.5 ... 然后 ... 還要加上w分量的二分之一?

大萌喵接下來打算稍微介紹下這個(gè)函數(shù)的原理. 如果你之前對(duì)坐標(biāo)轉(zhuǎn)換不是很了解, 大萌喵提供了幾個(gè)鏈接, 可供參考:

learnOpenGL(神啟蒙教程):

http://link.zhihu.com/?target=http%3A//learnopengl.com/%23%21Getting-started/Coordinate-Systems

scratchapixel.com :

http://link.zhihu.com/?target=http%3A//www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/projection-matrix-GPU-rendering-pipeline-clipping

神書:

http://link.zhihu.com/?target=https%3A//books.google.co.uk/books%3Fid%3DmNw_CQAAQBAJ%26pg%3DPA14%26dq%3Dhomogeneous%2Bcoordinate%2Bin%2Bthe%2Bfixed-function%2Bpipeline%26hl%3Den%26sa%3DX%26ved%3D0ahUKEwiE7-rk8crJAhUDPhQKHSzSCJQQ6AEIIzAA%23v%3Donepage%26q%3Dhomogeneous%2520coordinate%2520in%2520the%2520fixed-function%2520pipeline%26f%3Dfalse

如果你覺得Math = Mental Abuse To Human(對(duì)人類的精神侮辱), 那暫時(shí)略過也無所謂。 ComputeScreenPos當(dāng)成黑盒子使用也沒什么問題。

10如無需要可略過

首先上一張圖:

在Unity中,mul ( UNITY_MATRIX_MVP, v.vertex )和UnityObjectToClipPos(float4 ( v.vertex.xyz, 1.0 ) )干的差不多都是一回事兒, 就是將模型坐標(biāo)轉(zhuǎn)換到攝像機(jī)的Homogeneous Clip Space. 詳情參加官方文檔(http://link.zhihu.com/?target=
https%3A//docs.unity3d.com/Manual/SL-BuiltinFunctions.html)。

但是, 一般渲染管線不會(huì)立刻將Clip后的坐標(biāo)標(biāo)準(zhǔn)化(也就是除以w分量. 不知道w分量代表什么的童鞋 ... 請(qǐng)先補(bǔ)課), 而是在點(diǎn)元著色函數(shù)結(jié)束以后將其標(biāo)準(zhǔn)化. 這個(gè)地方有點(diǎn)坑.

(原文摘錄如下: Once all the vertices are transformed to clip space a final operation called perspective division is performed where we divide the x, y and z components of the position vectors by the vector's homogeneous w component; perspective division is what transforms the 4D clip space coordinates to 3D normalized device coordinates. This step is performed automatically at the end of each vertex shader run.)

所以, 可以認(rèn)為我們現(xiàn)在得到的是已經(jīng)經(jīng)過Clipping, 但是還沒有標(biāo)準(zhǔn)化的投影坐標(biāo). 我們的目的是要將這個(gè)坐標(biāo)轉(zhuǎn)化為xy在[0, 1]之間, 而z反映深度的屏幕坐標(biāo).

既然是[0, 1]之間, 那么我們自然就不用向上圖一樣乘以ViewPort寬高了. 同時(shí)要注意ViewPort坐標(biāo)原點(diǎn)的問題: Unity中是左下角, 而上圖采用的是左上角. 所以具體到我們的情況下y和x的處理方式應(yīng)該是相同的.

為了將[-1, 1]映射到[0, 1]上, 將原坐標(biāo)加1然后除2是顯而易見的. 但是要注意我們的x和y都比人家多乘著一個(gè)w分量. 因?yàn)檫\(yùn)算到這個(gè)時(shí)候我們依然在點(diǎn)元著色器函數(shù)中, 因此最終的標(biāo)準(zhǔn)化過程還沒有執(zhí)行.

所以, 我們就得到了下面這段代碼(其實(shí)也是上面那段)

float4 o = pos * 0.5;

o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w;

如果沒想清楚是怎么轉(zhuǎn)過這個(gè)彎來的 ... 對(duì)比上圖倒數(shù)第二個(gè)框框和上面的文字就OK了.

11千呼萬(wàn)喚始出來的點(diǎn)元著色器函數(shù)

(如果我不是手賤翻了下ComputeScreenPos的源代碼, 也就沒這么多麻煩事兒了哈哈哈)

12實(shí)際上非常簡(jiǎn)單的片元著色器函數(shù)

在片元著色器中, 我們只需要提取出對(duì)應(yīng)屏幕位置的深度信息, 然后和點(diǎn)元著色器的輸出深度信息作比較, 根據(jù)相差結(jié)果進(jìn)行插值即可.

不知道那個(gè)插值是怎么回事兒的童鞋, 請(qǐng)動(dòng)用C語(yǔ)言的思考模式, 寫個(gè)if出來, 然后想辦法消除掉這個(gè)if.

雖然話說回來就算這有個(gè)if也不算動(dòng)態(tài)分支, 對(duì)性能的影響不太大 ... 但還是養(yǎng)成良好的習(xí)慣吧.

13最終成果(其實(shí)一般再加上個(gè)Texture糊到Quad上實(shí)現(xiàn)掃描的特效)

14后記

其實(shí)這個(gè)特效的原理真心一點(diǎn)也不復(fù)雜, 只是用到了DepthTexture來獲取屏幕中每個(gè)像素的深度信息來進(jìn)行比對(duì)以決定模型最終的顏色. 但是UnityCG.cginc里面的ComputeScreenPos函數(shù)那個(gè)奇怪的外觀引發(fā)了我極大的好奇心.

15FIN

大萌喵是個(gè)學(xué)生黨, 非常熱切地希望能和諸位前輩們交流! 如果文章中存在任何疏漏, 不足, 或錯(cuò)誤之處, 希望您能批評(píng)指正! 謝謝!

Preview: 大萌喵最近對(duì)DepthTexture有點(diǎn)著迷呀, 下幾次打算講講Global Fog, Volumetric Light Scattering和Edge Detection. 不過中間也會(huì)夾雜一些小的好玩兒的著色器效果 ~

想了解更多?請(qǐng)點(diǎn)擊下方

閱讀原文

熱門課程推薦

熱門資訊

請(qǐng)綁定手機(jī)號(hào)

x

同學(xué)您好!

您已成功報(bào)名0元試學(xué)活動(dòng),老師會(huì)在第一時(shí)間與您取得聯(lián)系,請(qǐng)保持電話暢通!
確定