视差图转为深度图_Parallax Mapping视差映射:模拟冰块
繼續(xù)練習(xí)一個(gè)模擬冰塊的效果,模擬的是一個(gè)不透明內(nèi)部有雜質(zhì)的冰塊,內(nèi)部雜質(zhì)用視差映射來實(shí)現(xiàn),表面就是簡(jiǎn)單的法線貼圖+Cubemap反射采樣,也可以直接只計(jì)算高光不反射圖案。文章會(huì)把視差映射講一下,算是對(duì)學(xué)習(xí)的記錄和總結(jié)。
Parallax Mapping視差映射
好多人的文章里都寫到:
視差映射是法線映射的增強(qiáng)版,不止改變了光照作用,還在平坦的多邊形上創(chuàng)建了3D細(xì)節(jié)的假象。其實(shí)我們看原理和代碼能看出來,視差映射只是增加了高低錯(cuò)落的感覺,并沒有擾動(dòng)表面法線改變光照結(jié)果,所以在需要的時(shí)候我們還是要通過法線貼圖+視差映射來渲染出想要的視覺效果。
視差映射只需要用到一個(gè)浮點(diǎn)值,也就是只需要貼圖中的一個(gè)通道就可以表達(dá),所以經(jīng)常保存在法線貼圖的A通道或者其他貼圖的其中一個(gè)通道中。這個(gè)通道中的值保存的是對(duì)應(yīng)的每個(gè)點(diǎn)要沉入物體表面多少深度而不是高出表面的高度,所以也可以叫做深度圖。
視差映射只是對(duì)視向量進(jìn)行了偏移,對(duì)主貼圖進(jìn)行偏移采樣來達(dá)到讓平面看起來是立體的效果。物體表面本身還是原來的樣子,頂點(diǎn)并沒有發(fā)生偏移,高低落差只是一個(gè)假象。
當(dāng)前片元是圖中的T0,視向量為V,紋理左邊對(duì)深度圖采樣得到當(dāng)前的深度是0.55,所以V碰到的并不是T0,而是繼續(xù)向前延伸碰到的高度為0.15的點(diǎn),對(duì)應(yīng)的紋理坐標(biāo)是T1,所以應(yīng)該使用T1的紋理坐標(biāo)進(jìn)行主紋理和法線的采樣。簡(jiǎn)單視差映射 Parallax Mapping
帶偏移上限的視差映射 Parallax Mapping With Offse Limiting
只取一步近似計(jì)算得到新紋理坐標(biāo)是最簡(jiǎn)單的視差映射,被直接成為視差映射。
視差映射只有在高度相對(duì)平滑,并且不存在復(fù)雜細(xì)節(jié)時(shí),才能得到相對(duì)可以接受的結(jié)果。如果視向量和表面法線夾角過大的話就會(huì)出現(xiàn)嚴(yán)重錯(cuò)誤的結(jié)果。
偏移紋理坐標(biāo)的方法:
切線空間是沿著物體表面建立的,法線垂直于表面,而TB分量和紋理坐標(biāo)的xy分量重合,所以視向量V的z分量為法線分量,xy分量和紋理的xy分量重合,所以視向量的xy分量可以不加換算的直接用作紋理坐標(biāo)來計(jì)算偏移。用xy除以z,就是視差映射技術(shù)中對(duì)紋理坐標(biāo)偏移的原始計(jì)算。
如果不除以z,得到的就是帶偏移上限的視差映射,帶偏移上線的視差映射可以避免在向量V和法向量N夾角太大時(shí)的一些錯(cuò)誤的結(jié)果。
然后把V的xy分量加到T0的紋理坐標(biāo)上,并且和T0紋理的深度值H(T0)相乘,就得到了沿著V方向的新的紋理坐標(biāo)。
然后用一個(gè)scale系數(shù)來控制視差映射效果的幅度。把scale乘給V的xy分量。最有意義的值在0-0.5之間。更高的值會(huì)得到錯(cuò)誤的映射計(jì)算。也可以把scale設(shè)為負(fù)數(shù),這樣的話法向量的z分量需要反轉(zhuǎn)過來進(jìn)行計(jì)算。
從上圖中可以看出,視向量正確的交點(diǎn)和偏移后的采樣點(diǎn)Tp差距還是很大的,所以視差映射和帶偏移上限的視差映射在視向量與法線的夾角越大的情況下誤差就會(huì)越大。
陡峭視差映射 Steep Parallax Mapping
陡峭視差映射,不是簡(jiǎn)單的視差近似,不只是簡(jiǎn)單粗暴的對(duì)紋理坐標(biāo)進(jìn)行偏移而不進(jìn)行合理性檢查,會(huì)檢查結(jié)果是否接近于正確值。陡峭視差映射是將深度分割為等距的若干層,然后從0層開始采樣高度圖,每一次會(huì)沿著V的方向偏移紋理坐標(biāo),如果采樣的深度已經(jīng)大于當(dāng)前層的深度,停止檢查并使用最后一次采樣的紋理坐標(biāo)作為結(jié)果。
以上圖為例,深度被分割為8層,每層高度為0.125,每層的紋理坐標(biāo)偏移是V.xy/V.z*sclae/numLayer,從黃色方塊開始檢查:
- 0層開始,層深為0,采樣深度圖得到值為0.75,采樣的結(jié)果大于層的深度,開始下一次迭代
- 沿著V方向偏移紋理坐標(biāo),1層開始,層深為0.125,采樣深度圖的值為0.625,采樣結(jié)果大于層的深度,開始下一次迭代
- 沿著V方向偏移紋理坐標(biāo),2層開始,層深為0.25,采樣高度圖的值為0.4,采樣結(jié)果大于層的深度,開始下一次迭代
- 沿著V方向偏移紋理坐標(biāo),3層開始,層深為0.375,采樣高度圖的值為0.2,采樣結(jié)果小于層的深度,所以得到了實(shí)際交點(diǎn)的近似點(diǎn),采樣本次使用的紋理坐標(biāo)。
可以看出T3的坐標(biāo)離實(shí)際交點(diǎn)還是有距離的,但是這種方式可以檢查偏移采樣的正確性,如果想得到更精確的結(jié)果,可以增加層的數(shù)量,提高采樣的精確度。層數(shù)的提高會(huì)降低性能,降低層數(shù)會(huì)有明顯的鋸齒現(xiàn)象,可以根據(jù)視向量V和表面法向量N的夾角來動(dòng)態(tài)決定層的數(shù)量。
vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir) { //高度層數(shù)float numLayers = 5;//每層高度float layerHeight = 1.0 / numLayers;// 當(dāng)前層級(jí)高度float currentLayerHeight = 0.0;//視點(diǎn)方向偏移總量vec2 P = viewDir.xy / viewDir.z * heightScale; //每層高度偏移量vec2 deltaTexCoords = P / numLayers;//當(dāng)前 UVvec2 currentTexCoords = texCoords;float currentHeightMapValue = texture(heightMap, currentTexCoords).r;while(currentLayerHeight < currentHeightMapValue){// 按高度層級(jí)進(jìn)行 UV 偏移currentTexCoords += deltaTexCoords;// 從高度貼圖采樣獲取的高度currentDepthMapValue = texture(depthMap, currentTexCoords).r; // 采樣點(diǎn)高度currentLayerHeight += layerHeight; }return finalTexCoords; }浮雕視差映射 Relief Parallax Mapping
浮雕視差映射是在陡峭視差映射的基礎(chǔ)上做出的升級(jí)優(yōu)化,先進(jìn)行陡峭視差映射,可以得到準(zhǔn)確交點(diǎn)的前后兩個(gè)層,和對(duì)應(yīng)的深度值,然后在兩層之間使用二分法進(jìn)行迭代查找。
執(zhí)行步驟:
- 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),知道達(dá)到規(guī)定的次數(shù),或者兩個(gè)深度偏差達(dá)到一個(gè)閾值
- 得到的紋理坐標(biāo)就是浮雕視差映射的結(jié)果
視差遮蔽映射 Parallax Occlusion Mapping
視差遮蔽映射是陡峭視差映射的另一個(gè)優(yōu)化版本,浮雕映射使用二分法來提升精度,但是會(huì)降低性能。視差遮蔽性能比陡峭映射好,但是效果比浮雕映射要差。
視差遮蔽映射是使用陡峭映射得到的最后一次采樣的H(T3)、UV和前一次采樣的到的層深H(T2)、UV,進(jìn)行一次插值的到的結(jié)果。
float2 ParallaxMapping(float2 texCoords, float3 viewDir) { //高度層數(shù)float numLayers = 50;//每層高度float layerHeight = 1.0 / numLayers;// 當(dāng)前層級(jí)高度float currentLayerHeight = 0.0;//視點(diǎn)方向偏移總量float2 P = viewDir.xy / viewDir.z * _ParallaxStrength; //每層高度偏移量float2 deltaTexCoords = P / numLayers;//當(dāng)前 UVfloat2 currentTexCoords = texCoords;float currentHeightMapValue = tex2D(_ParallaxMap, currentTexCoords).r;while(currentLayerHeight < currentHeightMapValue){// 按高度層級(jí)進(jìn)行 UV 偏移currentTexCoords += deltaTexCoords;// 從高度貼圖采樣獲取的高度currentHeightMapValue = tex2Dlod(_ParallaxMap, float4(currentTexCoords,0,0)).r; // 采樣點(diǎn)高度currentLayerHeight += layerHeight; }//前一個(gè)采樣的點(diǎn)float2 prevTexCoords = currentTexCoords - deltaTexCoords;//線性插值float afterHeight = currentHeightMapValue - currentLayerHeight;float beforeHeight = tex2D(_ParallaxMap, currentTexCoords).r - (currentLayerHeight - layerHeight);float weight = afterHeight / (afterHeight - beforeHeight);float2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);return finalTexCoords; }完成后的冰塊效果:
知乎視頻?www.zhihu.com雖然完成了效果,但是對(duì)視差映射一直還是有一些沒有搞懂的地方,為什么簡(jiǎn)單視差和陡峭視差在計(jì)算的時(shí)候偏移使用的是V.xy/V.z,而在帶偏移上限的計(jì)算中偏移使用的是V.xy。在看過的很多文章中都是對(duì)所有視差映射的原理方法和代碼進(jìn)行了描述,并沒有對(duì)這部分的講解。
后來 @夢(mèng)旅人 給我發(fā)了一篇文章:
https://catlikecoding.com/unity/tutorials/rendering/part-20/?catlikecoding.com在這篇文章中詳細(xì)的講解了視差映射的相關(guān)內(nèi)容,在這篇文章中找到了關(guān)于我的疑問的講解,看過以后發(fā)現(xiàn)大家的文章中沒有對(duì)于這部分的講解估計(jì)是因?yàn)榇_實(shí)太基礎(chǔ)了.....
從上圖中可以看出,深度采樣H的值肯定是在0-1之間的:
- V.xy*H就可以得到一個(gè)一定范圍內(nèi)的偏移量,所以帶偏移上限的視差映射使用的V.xy來計(jì)算偏移量的
- 那為什么correct offset的偏移距離,也就是陡峭中的總偏移距離為什么是V.xy/V.z呢,將我們的數(shù)學(xué)功力發(fā)揮到初中水平就可以得到結(jié)果,∵ ∠a=∠b,∴ cot∠a=cot∠b,∴ xy/z = correct offset / 最大深度1,∴ correct offset = xy/z,這樣xy分量除以z分量得到的就是總的UV坐標(biāo)偏移量了........
結(jié)合陡峭的算法也就能想明白為什么要取UV的總偏移量.....
文章中部分內(nèi)容、插圖和代碼參考和轉(zhuǎn)自:
[譯] GLSL 中的視差遮蔽映射(Parallax Occlusion Mapping in GLSL)?segmentfault.com吳洲:視差貼圖(Parallax Mapping)學(xué)習(xí)筆記?zhuanlan.zhihu.com夢(mèng)旅人:Unity Shader基于視差映射的云海效果?zhuanlan.zhihu.comGEngine:視差映射(Parallax Mapping)?zhuanlan.zhihu.com總結(jié)
以上是生活随笔為你收集整理的视差图转为深度图_Parallax Mapping视差映射:模拟冰块的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 交强险包括哪些
- 下一篇: 新手做什么生意稳定 推荐投资小市场大