有趣的深度圖:可見性問題的解法

0x00 前言

說起深度朦乏,朋友們一定都不陌生绳匀。為了解決渲染場(chǎng)景時(shí)哪部分可見投放,哪部分不可見的問題(即可見性問題,也被稱為隱藏面移除問題绒北,hidden surface removal problem黎侈,從術(shù)語這個(gè)角度看,技術(shù)的發(fā)展有時(shí)也會(huì)帶動(dòng)心態(tài)向積極的方向的變化)闷游,計(jì)算機(jī)圖形學(xué)中常使用畫家算法或深度緩沖的方式峻汉。

這也是在處理可見性問題時(shí)的兩個(gè)大方向上的思路:Object space方式和Image space方式。在后文的描述中脐往,各位應(yīng)該能夠體驗(yàn)到這兩種方式的異同休吠。
下圖就是在Unity引擎中將深度緩沖的數(shù)據(jù)保存成的圖片。


QQ截圖20170529165355.png
QQ截圖20170529125238.png

而利用深度圖我們又可以實(shí)現(xiàn)很多有趣的視覺效果业簿,例如一些很有科幻感的效果等等蛛碌。

QQ截圖20170602193326.png

不過在說到這些有趣的效果之前,我們先來看看所謂的可見性問題和深度圖的由來吧辖源。

0x01 人類的本能和畫家算法

在計(jì)算機(jī)圖形學(xué)中蔚携,有一個(gè)很重要的問題需要解決,即可見性問題克饶。因?yàn)槲覀円獙⒁粋€(gè)3D模型投影到2D的平面上酝蜒,這個(gè)過程中哪些多邊形是可見的,哪些是不可見的必須要正確的處理矾湃。
按照人類的天性亡脑,一個(gè)最簡(jiǎn)單的解決方案就是先繪制最遠(yuǎn)的場(chǎng)景,之后從遠(yuǎn)及近邀跃,依次用近處的場(chǎng)景覆蓋遠(yuǎn)處的場(chǎng)景霉咨。這就好比是一個(gè)畫家畫畫一樣。

Painter's_algorithm.png

(圖片來自維基百科)
而計(jì)算機(jī)圖形學(xué)中的畫家算法的思想便是如此:

  • 首先將待渲染的場(chǎng)景中的多邊形根據(jù)深度進(jìn)行排序拍屑。
  • 之后按照順序進(jìn)行繪制途戒。

這種方法通常會(huì)將不可見的部分覆蓋,這樣就可以解決可見性問題僵驰。
但是喷斋,世界上就怕但是二字唁毒,使用畫家算法這種比較樸素的算法的確能解決簡(jiǎn)單的可見性問題,不過遇到一些特殊的情況就無能為力星爪。例如下面這個(gè)小例子:

QQ截圖20170529174402.png

在這個(gè)例子中浆西,三個(gè)多邊形A、B顽腾、C互相重疊近零,那么到底如何對(duì)它們進(jìn)行排序呢?此時(shí)我們無法確定哪個(gè)多邊形在上抄肖,哪個(gè)多邊形在下久信。在這種情況下,多邊形作為一個(gè)整體進(jìn)行深度排序已經(jīng)不靠譜了憎瘸,因此必須用一些方法對(duì)這些多邊形進(jìn)行切分入篮、排序。

我們可以看到幌甘,這種方式是以場(chǎng)景中的對(duì)象或者說多邊形為單位進(jìn)行操作的潮售。因而常常被稱為Object space 方法或者稱為Object precision 方法,我個(gè)人更喜歡后者這個(gè)稱呼锅风,因?yàn)檫@是一個(gè)關(guān)于操作精度的區(qū)別酥诽。這種方式主要是在對(duì)象或多邊形這個(gè)級(jí)別的,即對(duì)比多邊形的前后關(guān)系皱埠。除了畫家算法之外肮帐,背面剔除也是Object Space的方法。它通過判斷面的法線和觀察者的角度來確定哪些面需要被剔除边器。

0x02 切分多邊形的Newell算法

既然作為整體互相重疊導(dǎo)致難以排序训枢,那么是否可以對(duì)多邊形進(jìn)行切分呢?Newell算法早在1972年就已經(jīng)被提出了忘巧,所以算不得是什么新東西恒界。但是它的一些思路還是很有趣的,倒也值得我們學(xué)習(xí)砚嘴。

和畫家算法一樣十酣,Newell算法同樣會(huì)按照深度對(duì)場(chǎng)景內(nèi)的對(duì)象進(jìn)行排序并對(duì)排序后的多邊形從遠(yuǎn)及近的依次繪制,不過有時(shí)會(huì)將場(chǎng)景內(nèi)的多邊形進(jìn)行切割成多個(gè)多邊形际长,之后再重新排序耸采。

簡(jiǎn)單來說,首先我們可以將參與排序的結(jié)構(gòu)定義為各個(gè)多邊形上頂點(diǎn)的最大Z值和最小Z值[Zmax工育,Zmin]虾宇。

我們會(huì)以多邊形上距離觀察者最遠(yuǎn)的頂點(diǎn)的Z值對(duì)場(chǎng)景內(nèi)的多邊形進(jìn)行一個(gè)粗略的排序(因?yàn)榇藭r(shí)只是依據(jù)每個(gè)多邊形距離觀察者最遠(yuǎn)的那一個(gè)頂點(diǎn)的Z值進(jìn)行排序),這樣我們就獲得了一個(gè)多邊形列表翅娶。

QQ截圖20170601000402.png

之后文留,取列表中的最后一個(gè)多邊形P(它的某個(gè)頂點(diǎn)是距離觀察者最遠(yuǎn)的頂點(diǎn))和P之前的一個(gè)多邊形Q好唯,之后通過對(duì)比來確定P是否可以被寫入幀緩沖區(qū)竭沫。
這個(gè)對(duì)比簡(jiǎn)單的說就是是否符合下面這個(gè)條件:

多邊形P的Zmin > 多邊形Q的Zmax

如果符合該條件燥翅,則P不會(huì)遮蓋Q的任何部分,此時(shí)可以將P寫入幀緩沖區(qū)蜕提。

tmp3189325_thumb (1).png

即便答案是否森书,P和Q也有可能不發(fā)生遮蓋。例如它們?cè)趚谎势、y上并無重疊凛膏。但是,Q還是有可能會(huì)被分割成若干個(gè)多邊形{Q1脏榆,Q2...}猖毫。此時(shí)有可能會(huì)針對(duì)下面的幾條測(cè)試結(jié)果,對(duì)最初的多邊形列表進(jìn)行重新排序(也有可能生成新的多邊形须喂,將新的多邊形也納入最初的列表中)并決定渲染的順序吁断。

  • 多邊形P和多邊形Q在X軸上是否可區(qū)分?
  • 多邊形P和多邊形Q在Y軸上是否可區(qū)分坞生?
  • 多邊形P是否完全在多邊形Q的后方仔役?
  • 多邊形Q是否完全在多邊形P的前方?
  • 判斷兩個(gè)多邊形的投影是否重疊是己?

如果這幾條測(cè)試全部都沒有通過又兵,則需要對(duì)Q或P進(jìn)行切割,例如將Q切割成Q1卒废、Q2沛厨,則Q1和Q2將被插入多邊形列表代替Q。

但是摔认,我們可以發(fā)現(xiàn)逆皮,這種對(duì)深度進(jìn)行排序后再依次渲染的方式會(huì)使得列表中多邊形的每個(gè)點(diǎn)都被渲染,即便是不可見的點(diǎn)也會(huì)被渲染一遍级野。因此當(dāng)場(chǎng)景內(nèi)的多邊形過多時(shí)页屠,畫家算法或Newell算法會(huì)過度的消耗計(jì)算機(jī)的資源。

0x03 有趣的Depth Buffer

正是由于畫家算法存在的這些缺點(diǎn)蓖柔,一些新的技術(shù)開始得到發(fā)展辰企。而深度緩沖(depth buffer或z-buffer)就是這樣的一種技術(shù)。Depth Buffer技術(shù)可以看作是畫家算法的一個(gè)發(fā)展况鸣,不過它并非對(duì)多邊形進(jìn)行深度排序牢贸,而是根據(jù)逐個(gè)像素的信息解決深度沖突的問題,并且拋棄了對(duì)于深度渲染順序的依賴镐捧。

因而潜索,Depth Buffer這種方式是一種典型的Image space 方法臭增,或者被稱為Image precision方法,因?yàn)檫@種方式的精度是像素級(jí)的竹习,它對(duì)比的是像素/片元級(jí)別的深度信息誊抛。

QQ截圖20170602192314.png

這樣,除了用來保存每個(gè)像素的顏色信息的顏色緩沖區(qū)之外整陌,我們還需要一個(gè)緩沖區(qū)用來保存每個(gè)像素的深度信息拗窃,并且兩個(gè)緩沖區(qū)的大小顯然要一致。

圖片5.png

該算法的過程并不復(fù)雜:

  • 首先泌辫,需要初始化緩沖區(qū)随夸,顏色緩沖區(qū)往往被設(shè)置為背景色。而深度緩沖區(qū)則被設(shè)為最大深度值震放,例如經(jīng)過投影之后宾毒,深度值往往在[0,1]之間殿遂,因此可以設(shè)置為1诈铛。

  • 經(jīng)過光柵化之后,計(jì)算每個(gè)多邊形上每個(gè)片元的Z值勉躺,并和對(duì)應(yīng)位置上的深度緩沖區(qū)中的值作比較癌瘾。
    如果z <= Zbuffer[x][y](即距離觀察者更近),則需要同時(shí)修改兩個(gè)緩沖區(qū):將對(duì)應(yīng)位置的顏色緩沖區(qū)的值修改為該片元的顏色饵溅,將對(duì)應(yīng)位置的深度緩沖區(qū)的值修改為該片元的深度妨退。即:Color[x][y] = color; Zbuffer[x][y] = z;

下面是一個(gè)小例子的圖示蜕企,當(dāng)然由于沒有經(jīng)過標(biāo)準(zhǔn)化咬荷,因此它的各個(gè)坐標(biāo)和深度值沒有在[0-1]的范圍內(nèi),不過這不影響:

圖片6.png

第一個(gè)多邊形轻掩,深度都為5幸乒。

圖片7.png

第二個(gè)多邊形,它的三個(gè)頂點(diǎn)的深度分別為2唇牧、7罕扎、7,因此經(jīng)過插值丐重,各頂點(diǎn)之間的片元的深度在[2-7]之間腔召,具體如右上角。我們還可以看到右下角是最后結(jié)果扮惦,紫色的多邊形和橘色的多邊形正確的互相覆蓋臀蛛。

0x04 來算算頂點(diǎn)的深度值

眾所周知,渲染最終會(huì)將一個(gè)三維的物體投射在一個(gè)二維的屏幕上。而在渲染流水線之中浊仆,也有一個(gè)階段是頂點(diǎn)著色完成之后的投影階段客峭。無論是透視投影還是正交投影,最后都會(huì)借助一個(gè)標(biāo)準(zhǔn)立方體(CVV)抡柿,來將3維的物體繪制在2維的屏幕上舔琅。
我們就先來以透視投影為例,來計(jì)算一下經(jīng)過投影之后某個(gè)頂點(diǎn)在屏幕空間上的坐標(biāo)吧沙绝。

QQ截圖20170603095703.png

由于我們使用左手坐標(biāo)系搏明,Z軸指向屏幕內(nèi)鼠锈,因此從N到F的過程中Z值逐漸增大闪檬。依據(jù)相似三角形的知識(shí),我們可以求出投影之后頂點(diǎn)V在屏幕上的坐標(biāo)购笆。


QQ截圖20170603095916.png

我們可以通過一個(gè)實(shí)際的例子來計(jì)算一下投影后點(diǎn)的坐標(biāo)粗悯,例如在一個(gè)N = 1,v的坐標(biāo)為(1同欠,0.5样傍,1.5),則v在近裁剪面上的投影點(diǎn)v'的坐標(biāo)為(0.666,0.333)铺遂。

但是衫哥,投影之后頂點(diǎn)的Z值在哪呢?而在投影時(shí)如果沒有頂點(diǎn)的深度信息襟锐,則兩個(gè)不同的頂點(diǎn)投影到同一個(gè)二維坐標(biāo)上該如何判定使用哪個(gè)頂點(diǎn)呢撤逢?

QQ截圖20170603100051.png

(v1,v2投影之后都會(huì)到同一個(gè)點(diǎn)v')

為了解決保存Z值的信息這個(gè)問題,透視變換借助CVV引入了偽深度(pseudodepth)的概念粮坞。

QQ截圖20170603100212.png

即將透視視錐體內(nèi)頂點(diǎn)的真實(shí)的Z值映射到CVV的范圍內(nèi)蚊荣,即[0,1]這個(gè)區(qū)間內(nèi)莫杈。需要注意的是互例,CVV是左手坐標(biāo)系的,因此Z值在指向屏幕內(nèi)的方向上是增大的筝闹。

為了使投影后的z'的表達(dá)式和x’媳叨、y‘的表達(dá)式類似,這樣做更易于用矩陣以及齊次坐標(biāo)理論來表達(dá)投影變換关顷,我們都使用z來做為分母糊秆,同時(shí)為了計(jì)算方便,我們使用一個(gè)z的線性表達(dá)式來作為分子解寝。

QQ截圖20170603101114.png

之后扩然,我們要做的就是計(jì)算出a和b的表達(dá)式。

在CVV中處于0時(shí)聋伦,對(duì)應(yīng)的是透視視錐體的近裁剪面(Near)夫偶,z值為N界睁;

     0 = (N * a + b) / N

而CVV中1的位置,對(duì)應(yīng)的是視錐體的遠(yuǎn)裁剪面(Far)兵拢,z值為F翻斟;

     1 = (F * a + b) / F

因此,我們可以求解出a和b的值:

     a = F / (F - N)
     b = -FN / (F - N)

有了a和b的值说铃,我們也就求出來視錐體中的Z值映射到CVV后的對(duì)應(yīng)值访惜。


QQ截圖20170603101914.png

0x05 Unity中的深度

最后來說說Unity中的Depth,它的值在[0腻扇,1]之間债热,并且不是線性變化的。
QQ截圖20170603101720.png

因此有時(shí)我們需要在Shader中使用深度信息時(shí)幼苛,往往需要先將深度信息轉(zhuǎn)化成線性的:

  float linearEyeDepth = LinearEyeDepth(depth);

  float linear01Depth = Linear01Depth(depth);

我們根據(jù)Unity場(chǎng)景中的深度信息渲染成一張灰度圖窒篱,就得到了本文一開頭的深度圖。


QQ截圖20170529125238.png

-分割線-
最后打個(gè)廣告舶沿,歡迎支持我的書《Unity 3D腳本編程》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末墙杯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子括荡,更是在濱河造成了極大的恐慌高镐,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,222評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件畸冲,死亡現(xiàn)場(chǎng)離奇詭異嫉髓,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)召夹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,455評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門岩喷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人监憎,你說我怎么就攤上這事纱意。” “怎么了鲸阔?”我有些...
    開封第一講書人閱讀 157,720評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵偷霉,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我褐筛,道長(zhǎng)类少,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,568評(píng)論 1 284
  • 正文 為了忘掉前任渔扎,我火速辦了婚禮硫狞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己残吩,他們只是感情好财忽,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,696評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著泣侮,像睡著了一般即彪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上活尊,一...
    開封第一講書人閱讀 49,879評(píng)論 1 290
  • 那天隶校,我揣著相機(jī)與錄音,去河邊找鬼蛹锰。 笑死深胳,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的宁仔。 我是一名探鬼主播稠屠,決...
    沈念sama閱讀 39,028評(píng)論 3 409
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼翎苫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起榨了,我...
    開封第一講書人閱讀 37,773評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤煎谍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后龙屉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體呐粘,經(jīng)...
    沈念sama閱讀 44,220評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,550評(píng)論 2 327
  • 正文 我和宋清朗相戀三年转捕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了作岖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,697評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡五芝,死狀恐怖痘儡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情枢步,我是刑警寧澤沉删,帶...
    沈念sama閱讀 34,360評(píng)論 4 332
  • 正文 年R本政府宣布,位于F島的核電站醉途,受9級(jí)特大地震影響矾瑰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜隘擎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,002評(píng)論 3 315
  • 文/蒙蒙 一殴穴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦采幌、人聲如沸恍涂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,782評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽再沧。三九已至,卻和暖如春尊残,著一層夾襖步出監(jiān)牢的瞬間炒瘸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,010評(píng)論 1 266
  • 我被黑心中介騙來泰國打工寝衫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留顷扩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,433評(píng)論 2 360
  • 正文 我出身青樓慰毅,卻偏偏與公主長(zhǎng)得像隘截,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子汹胃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,587評(píng)論 2 350

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