Unity URP Shader 實現(xiàn)幾種視差映射

代碼

陡峭視差映射?Steep Parallax Mapping

float2 SteepParallaxMapping(TEXTURE2D_PARAM(heightMap, sampler_heightMap), half3 viewDirTS, half scale, float2 uv)

{

? //determine number of layers from angle between V and N

? const float minLayers = 5;

? const float maxLayers = 15;

? float numLayers = lerp(minLayers, maxLayers, abs(dot(half3(0, 0, 1), viewDirTS)));


? //height of each layer

? float layerHeight = 1.0 / numLayers;

? //depth of current layer

? float currentLayerHeight = 0;

? //shift of texture coordinates for each iteration

? half2 dtex = scale * viewDirTS.xy / viewDirTS.z / numLayers;

? //current texture coordinates

? float2 currentTextureCoords = uv;

? //get first depth from heightmap

? float heightFromTexture = 1 - SAMPLE_TEXTURE2D(heightMap, sampler_heightMap, currentTextureCoords).g;

? for(int i = 0; i < 15; i++)

? {

? ? ? if(heightFromTexture <= currentLayerHeight)

? ? ? ? break;

? ? ? //to the next layer

? ? ? currentLayerHeight += layerHeight;

? ? ? //shift texture coordinates along vector viewDirTS

? ? ? currentTextureCoords -= dtex;

? ? ? //get new depth from heightmap

? ? ? heightFromTexture = 1 - SAMPLE_TEXTURE2D(heightMap, sampler_heightMap, currentTextureCoords).g;

? }


? return currentTextureCoords - uv;

}

浮雕視差映射?Relief Parallax Mapping

float2 ReliefParallaxMapping(TEXTURE2D_PARAM(heightMap, sampler_heightMap), half3 viewDirTS, half scale, float2 uv)

{

? // determine required number of layers

? const float minLayers = 10;

? const float maxLayers = 15;

? float numLayers = lerp(minLayers, maxLayers, abs(dot(half3(0, 0, 1), viewDirTS)));

? // height of each layer

? float layerHeight = 1.0 / numLayers;

? // depth of current layer

? float currentLayerHeight = 0;

? // shift of texture coordinates for each iteration

? half2 dtex = scale * viewDirTS.xy / viewDirTS.z / numLayers;

? // current texture coordinates

? float2 currentTextureCoords = uv;

? // depth from heightmap

? float heightFromTexture = 1 - SAMPLE_TEXTURE2D(heightMap, sampler_heightMap, currentTextureCoords).g;

? for(int i = 0; i < 15; i++)

? {

? ? ? if(heightFromTexture <= currentLayerHeight)

? ? ? ? break;

? ? ? // to the next layer

? ? ? currentLayerHeight += layerHeight;

? ? ? // shift texture coordinates along vector viewDirTS

? ? ? currentTextureCoords -= dtex;

? ? ? // get new depth from heightmap

? ? ? heightFromTexture = 1 - SAMPLE_TEXTURE2D(heightMap, sampler_heightMap, currentTextureCoords).g;

? }

? ///////////////////////////////////////////////////////////

? // Start of Relief Parallax Mapping

? // decrease shift and height of layer by half

? half2 deltaTexCoord = dtex / 2;

? float deltaHeight = layerHeight / 2;

? // return to the mid point of previous layer

? currentTextureCoords += deltaTexCoord;

? currentLayerHeight -= deltaHeight;

? // binary search to increase precision of Steep Paralax Mapping

? const int numSearches = 5;

? for(int j = 0; j < numSearches; j++)

? {

? ? ? // decrease shift and height of layer by half

? ? ? deltaTexCoord /= 2;

? ? ? deltaHeight /= 2;

? ? ? // new depth from heightmap

? ? ? heightFromTexture = 1 - SAMPLE_TEXTURE2D(heightMap, sampler_heightMap, currentTextureCoords).g;

? ? ? // shift along or agains vector V

? ? ? if(heightFromTexture > currentLayerHeight) // below the surface

? ? ? {

? ? ? ? currentTextureCoords -= deltaTexCoord;

? ? ? ? currentLayerHeight += deltaHeight;

? ? ? }

? ? ? else // above the surface

? ? ? {

? ? ? ? currentTextureCoords += deltaTexCoord;

? ? ? ? currentLayerHeight -= deltaHeight;

? ? ? }

? }

? // return results

? //parallaxHeight = currentLayerHeight;? ?

? return currentTextureCoords - uv;

}

視差遮蔽映射 Parallax Occlusion Mapping

float2 ParallaxOcclusionMapping(TEXTURE2D_PARAM(heightMap, sampler_heightMap), half3 viewDirTS, half scale, float2 uv)

{

? // determine optimal number of layers

? const float minLayers = 10;

? const float maxLayers = 15;

? float numLayers = lerp(minLayers, maxLayers, abs(dot(half3(0, 0, 1), viewDirTS)));

? // height of each layer

? float layerHeight = 1.0 / numLayers;

? // current depth of the layer

? float currentLayerHeight = 0;

? // shift of texture coordinates for each layer

? half2 dtex = scale * viewDirTS.xy / viewDirTS.z / numLayers;

? // current texture coordinates

? float2 currentTextureCoords = uv;

? // depth from heightmap

? float heightFromTexture = 1 - SAMPLE_TEXTURE2D(heightMap, sampler_heightMap, currentTextureCoords).g;

? for(int i = 0; i < 15; i++)

? {

? ? ? if(heightFromTexture <= currentLayerHeight)

? ? ? ? break;

? ? ? // to the next layer

? ? ? currentLayerHeight += layerHeight;

? ? ? // shift texture coordinates along vector viewDirTS

? ? ? currentTextureCoords -= dtex;

? ? ? // get new depth from heightmap

? ? ? heightFromTexture = 1 - SAMPLE_TEXTURE2D(heightMap, sampler_heightMap, currentTextureCoords).g;

? }

? /////////////////////////////////////////////////////////

? // previous texture coordinates

? half2 prevTCoords = currentTextureCoords + dtex;

? // heights for linear interpolation

? float nextH? ? = heightFromTexture - currentLayerHeight;

? float prevH? ? = 1 - SAMPLE_TEXTURE2D(heightMap, sampler_heightMap, currentTextureCoords).g

? ? ? ? ? ? ? ? ? ? ? ? ? - currentLayerHeight + layerHeight;

? // proportions for linear interpolation

? float weight = nextH / (nextH - prevH);

? // interpolation of texture coordinates

? float2 finalTexCoords = prevTCoords * weight + currentTextureCoords * (1.0-weight);

? return finalTexCoords - uv;

? //return currentTextureCoords - uv;

}

優(yōu)缺點總結(jié)

陡峭視差映射?Steep Parallax Mapping

如果層數(shù)很多,那性能就會低袖裕。但如果層數(shù)少曹抬,就會有明顯的鋸齒現(xiàn)象產(chǎn)生,可以根據(jù)攝像機(jī)向量V和多邊形法向N之間的夾角來動態(tài)的決定層的數(shù)量急鳄。

浮雕視差映射?Relief Parallax Mapping

可以使用較少的層數(shù)進(jìn)行一階段陡峭視差檢索

二階段的二分查找算法仍然消耗性能谤民,但相較陡峭視差映射可以得到更精確的結(jié)果

視差遮蔽映射 Parallax Occlusion Mapping

視差遮蔽映射可以使用相對較少的采樣次數(shù)產(chǎn)生很好的結(jié)果。但視差遮蔽映射比浮雕視差映射更容易跳過高度圖中的小細(xì)節(jié)疾宏,也更容易在高度圖數(shù)據(jù)產(chǎn)生大幅度的變化時得到錯誤的結(jié)果张足。

原理

視差映射技術(shù)的主要任務(wù)是修改紋理坐標(biāo),讓平面看起來像是立體的坎藐。主要計算都是在Fragment Shader中進(jìn)行为牍。看看下面的圖片顺饮。水平線0.0表示完全沒有凹陷的深度吵聪,水平線1.0表示凹陷的最大深度。實際的幾何體并沒改變兼雄,其實一直都在0.0水平線上吟逝。圖中的曲線代表了高度圖中存儲的高度數(shù)據(jù)。

設(shè)當(dāng)前點(譯者:原文中用的是Fragment赦肋,片元块攒。)是圖片中用黃色方塊高亮出來的那個點,這個點的紋理坐標(biāo)是T0佃乘。向量V是從攝像機(jī)到點的方向向量囱井。用坐標(biāo)T0在高度圖上采樣,你能得到這個點的高度值H(T0)=0.55趣避。這個值不是0庞呕,所以點并不是在表面上,而是凹陷下去的程帕。所以你得把向量V繼續(xù)延長直到與高度圖定義出來的表面最近的一個交點住练。這個交點我們說它的深度就是H(T1),它的紋理坐標(biāo)就是T1愁拭。所以我們就應(yīng)該用T1的紋理坐標(biāo)去對顏色和法線貼圖進(jìn)行采樣讲逛。

所以說,所有視差映射技術(shù)的主要目的岭埠,就是要精確的計算攝像機(jī)的向量V和高度圖定義出來的表面的交點盏混。

視差原理

陡峭視差映射?Steep Parallax Mapping

如圖所示把表面的深度切分成等距的若干層蔚鸥。然后從最頂端的一層開始采樣高度圖,每一次會沿著V的方向偏移紋理坐標(biāo)许赃。如果點已經(jīng)低于了表面(當(dāng)前的層的深度大于采樣出的深度)止喷,停止檢查并且使用最后一次采樣的紋理坐標(biāo)作為結(jié)果。

陡峭視差映射的工作方式在下面的圖片上舉例图焰。深度被分割成8個層启盛,每層的高度值是0.125。每層的紋理坐標(biāo)偏移是V.xy/V.z * scale/numLayers技羔。從頂層黃色方塊的位置開始檢查。

以下參照下圖給出算法的執(zhí)行步驟:

層的深度為0卧抗,高度圖深度H(T0)大約為0.75藤滥。采樣到的深度大于層的深度,所以開始下一次迭代社裆。

沿著V方向偏移紋理坐標(biāo)拙绊,選定下一層。層深度為0.125泳秀,高度圖深度H(T1)大約為0.625标沪。采樣到的深度大于層的深度,所以開始下一次迭代嗜傅。

沿著V方向偏移紋理坐標(biāo)金句,選定下一層。層深度為0.25吕嘀,高度圖深度H(T2)大約為0.4违寞。采樣到的深度大于層的深度,所以開始下一次迭代偶房。

沿著V方向偏移紋理坐標(biāo)趁曼,選定下一層。層深度為0.375棕洋,高度圖深度H(T3)大約為0.2挡闰。采樣到的深度小于層的深度,所以向量V上的當(dāng)前點在表面之下掰盘。我們找到了紋理坐標(biāo)Tp=T3是實際交點的近似點摄悯。

陡峭視差映射原理

浮雕視差映射?Relief Parallax Mapping

浮雕視差映射升級了陡峭視差映射。

算法一階段采用陡峭視差映射得到交點前后的兩個層庆杜,和對應(yīng)的深度值射众。在下面的原理圖中這兩個層分別對應(yīng)紋理坐標(biāo)T2和T3。

算法在二階段采用二分法來進(jìn)一步改進(jìn)你的結(jié)果晃财,每一次搜索迭代可以使精確度提升一倍叨橱。

以下參照下圖給出了算法的執(zhí)行步驟:

在陡峭視差映射之后典蜕,我們知道交點肯定在T2和T3之間。真實的交點在圖上用綠點標(biāo)出來了罗洗。

設(shè)每次迭代時的紋理坐標(biāo)變化量ST愉舔,它的初始值等于向量V在穿過一個層的深度時的XY分量。

設(shè)每次迭代時的深度值變化量SH伙菜,它的初始值等于一個層的深度轩缤。

把ST和SH都除以2。

把紋理坐標(biāo)T3沿著反方向偏移ST贩绕,把層深度沿反方向偏移SH火的,得到此次迭代的紋理坐標(biāo)T4和層深度H(T4)。

(*)采樣高度圖淑倾,把ST和SH都除以2馏鹤。

如果高度圖中的深度值大于當(dāng)前迭代層的深度H(T4),則將當(dāng)前迭代層的深度增加SH娇哆,迭代的紋理坐標(biāo)沿著V的方向增加ST湃累。

如果高度圖中的深度值小于當(dāng)前迭代層的深度H(T4),則將當(dāng)前迭代層的深度減少SH碍讨,迭代的紋理坐標(biāo)沿著V的相反方向增加ST治力。

從(*)處循環(huán),繼續(xù)二分搜索勃黍,直到規(guī)定的次數(shù)宵统。

最后一步得到的紋理坐標(biāo)就是浮雕視差映射取到的近似結(jié)果。

浮雕視差映射原理

視差遮蔽映射 Parallax Occlusion Mapping

視差遮蔽映射(POM)是陡峭視差映射的另一個改進(jìn)版本溉躲。

算法一階段采用陡峭視差映射得到交點前后的兩個層榜田,和對應(yīng)的深度值。在下面的原理圖中這兩個層分別對應(yīng)紋理坐標(biāo)T2和T3锻梳。

算法二階段對一階段獲得的兩個紋理偏移值進(jìn)行插值箭券。如原理圖所示,POM使用相交之后的層深度(0.375疑枯,陡峭視差映射停止迭代的層)辩块,上一個采樣深度H(T2)和下一個采樣深度H(T3)。從圖片中你能看到荆永,視差遮蔽映射的插值結(jié)果是在視向量V和H(T2)和H(T3)高度的連線的交點上废亭。這個交點已經(jīng)足夠接近實際交點(標(biāo)記為綠色的點)了。

視差遮蔽映射原理

參考資料

[譯] GLSL 中的視差遮蔽映射(Parallax Occlusion Mapping in GLSL)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末具钥,一起剝皮案震驚了整個濱河市豆村,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌骂删,老刑警劉巖掌动,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件四啰,死亡現(xiàn)場離奇詭異,居然都是意外死亡粗恢,警方通過查閱死者的電腦和手機(jī)柑晒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來眷射,“玉大人匙赞,你說我怎么就攤上這事⊙铮” “怎么了涌庭?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長欧宜。 經(jīng)常有香客問我脾猛,道長,這世上最難降的妖魔是什么鱼鸠? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮羹铅,結(jié)果婚禮上蚀狰,老公的妹妹穿的比我還像新娘。我一直安慰自己职员,他們只是感情好麻蹋,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著焊切,像睡著了一般扮授。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上专肪,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天刹勃,我揣著相機(jī)與錄音,去河邊找鬼嚎尤。 笑死荔仁,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的芽死。 我是一名探鬼主播乏梁,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼关贵!你這毒婦竟也來了遇骑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤揖曾,失蹤者是張志新(化名)和其女友劉穎落萎,沒想到半個月后亥啦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡模暗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年禁悠,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片兑宇。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡碍侦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出隶糕,到底是詐尸還是另有隱情瓷产,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布枚驻,位于F島的核電站濒旦,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏再登。R本人自食惡果不足惜楷兽,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望温亲。 院中可真熱鬧询吴,春花似錦、人聲如沸沽损。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绵估。三九已至炎疆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間国裳,已是汗流浹背形入。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留躏救,地道東北人唯笙。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像盒使,于是被迫代替她去往敵國和親崩掘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

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