Terrain 讀書筆記 Chapter 5

2021-03-31 17:32:28 字數 3974 閱讀 8742

chapter 5. fundamental 3d objects

經過了漫長的前戲(rpwt -_-|||),終於到了講核心技術的時候了。這是最後一章基礎課了(基礎課不是在part i的時候都講完了麼?),講的就是3d裡面非常基礎的乙個話題——空間分割,果然是基礎。

空間分割就是把world分成若干個部分,然後確定出哪些部分引擎應該去渲染,而哪些部分不需要。而且還可以用來確定每個部分的細節(就是該用什麼級別的細節去渲染)。在gaia中,空間分割是用四叉樹來實現的。

the motivation behind scene anization

任何render pipeline的第一步都是要確定哪些物體需要被渲染,這就是我們做空間分割的動機。檢視乙個物體是否可見,就是檢視這個物體是否在視錐(frustum)當中。上次有人在bbs上問:那個三角形的東西是什麼?我立即ft了。

物體只要有任何一部分在frustum中,就是可見的。比較簡單的方法是用乙個邊界的box裝住物體,那麼乙個物體只要測6次就可以知道它是否可見了(box的6個面)。

視錐中的每個面都可以看成是空間中的平面。每個都用乙個法線(指向視錐內部)來表示正的半平面。如果乙個物體的某個部分都是在這些半平面的正半面方向,那就是可見了。

有種簡化的方法:把乙個大空間分成小矩形,叫sector。那麼只需要確定sector是否可見,如果可見,那麼sector裡面所有的object都要送去渲染。

這種方法獲得了效率,卻丟掉了精度。因為很多可見的sector中的object也是不可見的。那麼有個改進方法:所有和frustum邊界相交的sector都要再進一步的測試其中的每個object。

如果物體足夠分散的話,其實還是相當於test了所有的object,這一點兒也沒有效率上的提高。那麼繼續改進:把sector分成大塊,然後再細分,變成一棵樹。如果雙親不可見,那麼孩子一定不可見。如果雙親可見,就繼續test他們的孩子,遞迴下去。

the basic quadtree

四叉樹和八叉樹都是用樹來表示空間關係。四叉樹用於2d,將乙個矩形分成4等分,每個可以繼續細分。八叉樹用於3d,把每個立方體分成8等分,然後繼續細分。

因為gaia中的垂直高度比較低,所以可以看成是乙個平面,這也是不用octree而用quadtree的原因。不過以後我們可以對quadtree擴充套件,讓它變成乙個偽3d的樹。

理論上quadtree中的節點數目是最小化的,就是說,如果乙個分支上沒有物體,它就是null了,它下面的節點也都被忽略了。但是這樣做雖然節省空間,但是卻缺乏動態效率。一旦有運動物體的話,增加刪除節點的操作就太頻繁了。

為了避免這種情況,gaia中使用的是表示全部節點的quadtree,哪怕是null節點也要表示出來。這樣就不用考慮增刪節點了,不過得耗不少記憶體。

其實quadtree應該可以看成是乙個2維的線段樹。查詢乙個物體的algo如下:

step 1.檢視當前節點所有的孩子。如果沒孩子,goto step 3。

step 2.如果該物體被其中乙個孩子節點完全包住,那麼把這個孩子節點作為當前節點,然後goto step 1。

step 3.這個物體就是屬於這個節點了,新增,然後exit。

enhancing the quadtree

因為查詢新增節點的過程太耗時間了,如果是乙個動態性很強的遊戲的話,那麼大部分的時間都要用於查詢節點。所以,如果有一種直接能夠確定節點插入位置的方法就好了。所幸的是matt pritchard給我們提供了乙個這樣的方法。(為了弄明白這個我還特意去看的)

如果乙個四叉樹每一層都可以用乙個二維陣列來表示的話,那麼每個節點應該這麼表示:

node[level][x][y]

另外,對於這種方法有兩個限制,不過pritchard說這些都不算限制:

1)座標軸必須是2的冪,比如256x256。如果不是的話是不是就不能用呢?哎,縮放一下就好了啊。

2)樹的層數要提前確定。這個對於很多情況下都是提前確定了的。記最大層數為maxlevel。

對於乙個物體,如何確定它的level和xy的值呢?比如我們的座標是256x256的,maxlevel=7,有乙個矩形物體,左上角是(190,110),右下角是(195,125)。那麼我們需要計算兩個量,乙個是它在x軸上的兩端的值取異或,乙個是它在y軸上的兩端的值取異或。如下:

10111110 (190)

xor  11000011 (195)

--------------------

01111101

01101110 (110)

xor  01111101 (125)

--------------------

00010011

這時候,檢視他們的最高位所在的位置,然後用最大層數去減,確定在特定軸上的層數:

levelx = maxlevel - highbitset(1111101) = 7 - 6 = 1

levely = maxlevel - highbitset(10011)   = 7 - 4 = 3

然後這個物體的層數是他們的較小者:

level = min( levelx, levely ) = 1

這樣就確定了它的層數。下面就需要確定它的位置了。位置是使用物體的任意乙個點作右移,右移的位數應為:

shiftbit = maxlevel - level + 1 = 7 - 1 + 1 = 7

然後,分別計算xy的值(取的任意點為物體左上角的點,x1=190,y1=110):

x = x1>>shiftbit = 1

y = y1>>shiftbit = 0

則這個物體所屬的節點就是node[1][1][0]了。

都是位運算,看上去都覺得有效率了……

adding another dimension to the quadtree

如果想給空間加上z軸的話,就要使用octree了。但是這樣的話效率就大打折扣了(quadtree總比octree複雜度低吧)。那麼,採用乙個比較折衷的方法來建立乙個偽z軸,就是在z軸上設32個層,用32bit來描述。如果乙個物體在第4567層的話,它的高度就是11110000(前24位都是0)。

那麼如果插入乙個物體的話,就用or一下節點的高度域。如果測試物體是否屬於特定層的話,就and一下(得到非零值就是有了)。

又是位運算,看來引擎的確是個追求效率的東西。

fast quadtree searches

想查詢乙個3d的體積,就得把它轉化為乙個2d的shape和乙個32bits的高度,然後用shape和這個高度查詢。

比如有個給定的體積,那麼就先查根。如果這個節點的z包括了這個體積的z,那麼就查它的四個孩子。這樣一直查下去,如果這個節點的某個object和這個體積相交了,就把這個節點加到乙個link list後面。當查詢完成的時候,這個link list就是最後的結果了。

另外,如果乙個節點的z-mask改變了的話,它的祖先也要相應進行調整。

slow quadtree searches

有快的為啥要慢的?慢的意味著更多的比較和操作。其實,用這個的主要原因就是用來查詢視錐中的物體集合的。

視錐的形狀不規矩,是乙個錐形的。那麼你可以用乙個box來包住視錐,然後用box + fast search進行查詢,這樣的話效率是有了,但是會錯誤的查到很多本不屬於視錐但是卻屬於box的物體。所以,為了避免這種情況,就直接用視錐去查了。

這個是可選的。如果使用快速渲染的話,就可以用fast search,因為多出來的物體就算渲染了也費不了太多時間。但是如果是使用一大堆shader作高階渲染的話,還是採用slow search的好,因為這樣會節省更多的渲染時間。

學過了這章,至少明白了什麼是quadtree,雖然還沒有機會使用它,卻已經感受到了它的強大。本來這章不需要看這麼久的,只是這周忽然莫名其妙的大病了一場,所以耽誤了許久,今天終於把剩下的一點點看完。基礎知識都學完了,以後就要進入真正的地形學習了。

mysql運維 讀書筆記 Mysql 讀書筆記

mysql儲存時間有兩種型別 datetime和timestamp。分別說一下兩者的區別。datetime,以8位元組儲存時間,理論上可以從0000年儲存到9999年。並且沒有時區的概念,它儲存的就是乙個時間點的概念。timestamp和datetime最主要的不同就是,它是以4個位元組儲存,由19...

struts in action讀書筆記

struts in action 學習筆記 一 struts的控制流 因為web 應用是動態的,所以很難表現 乙個真正固定的控制流 取決於環境,不同的方式下有很多不同的事情發生 特別是在web 應用中。但是事情仍然有乙個通用的秩序。如果你是個struts,應用框架,甚至web 應用的新手,這些流程剛...

中 斷(讀書筆記)

裝置的中斷會打斷核心中程序的正常排程和執行,系統對更高吞吐率的追求勢必要求中斷服務程式盡可能地短小精悍。但是這個良好的願望往往與現實並不吻合。在大多數的系統中,當中斷到來時,要完成的工作往往並不是短小的,它可能要求進行較大量的耗時處理。為了在中斷執行時間盡可能短和中斷處理需要完成大量工作之前找乙個平...