簡體   English   中英

用於渲染大量立方體的剔除技術

[英]Culling techniques for rendering lots of cubes

我正在開展個人學習項目,以制作Minecraft克隆。 除了一件事,它的工作非常好。 類似於我的世界,我的地形有很多立方體堆疊在Y上,所以你可以挖掘。 雖然我做了截頭剔除,但這仍然意味着我無用地在我下面畫出所有層的立方體。 立方體是X,Y和Z有序的(雖然只在1個方向,所以從技術上講,它不是Z訂購到相機)。 我基本上從玩家的位置只添加指向玩家周圍的立方體的指針。 然后,我對這些進行了截擊。 我不做oct樹細分。 我想只是沒有渲染玩家下面的圖層,除非玩家向下看到一個洞時這不起作用。 鑒於此,我怎么能避免在我下面渲染我看不到的立方體,或者還有其他立方體隱藏的立方體。

謝謝

void CCubeGame::SetPlayerPosition()
{
PlayerPosition.x = Camera.x / 3;
PlayerPosition.y = ((Camera.y - 2.9) / 3) - 1;
PlayerPosition.z = Camera.z / 3;
}

void CCubeGame::SetCollids()
{

SetPlayerPosition();

int xamount = 70;
int zamount = 70;
int yamount = 17;

int xamountd = xamount * 2;
int zamountd = zamount * 2;
int yamountd = yamount * 2;
PlayerPosition.x -= xamount;

PlayerPosition.y -= yamount;

PlayerPosition.z -= zamount;


collids.clear();
CBox* tmp;

    for(int i = 0; i < xamountd; ++i)
    {
        for(int j = yamountd; j > 0; --j)
        {
            for(int k = zamountd; k > 0; --k)
            {

                tmp = GetCube(PlayerPosition.x + i, PlayerPosition.y + j, PlayerPosition.z + k);



                if(tmp != 0)
                {
                    if(frustum.sphereInFrustum(tmp->center,25) != NULL)
                    {
                        collids.push_back(tmp);
                    }
                }

            }
        }

}

這是我在編寫自己的克隆時學到的:

  1. 不要只是將每個多維數據集轉儲到OpenGL中,也不要擔心自己完成所有可見性修剪。 如另一個答案所述,檢查所有6個面以查看它們是否被相鄰塊完全遮擋。 僅渲染可見的面。 這大致減少了從立方項(立方體體積n * n * n)到平方項(表面僅約n * n)的面數。
  2. OpenGL可以比你更快地查看截頭剔除。 將所有曲面面渲染到顯示列表或VBO后,只需將整個blob發送到OpenGL即可。 如果你將幾何體分成切片(或Minecraft稱之為塊),你可能會避免繪制你可以很容易地確定在相機背后的塊。
  3. 將整個幾何體渲染到顯示列表(或列表)中,並每次重繪。 如果您使用立即模式,這是一個簡單的步驟,因為您只需將現有代碼包裝在glNewList / glEndList中並使用glCallList重繪。 減少OpenGL調用計數(每幀)將比減少要渲染的多邊形總量產生更大的影響。
  4. 一旦你看到生成顯示列表需要多長時間而不是繪制它們,你將開始考慮如何將更新放入一個線程。 這是轉換為VBO的回報:線程呈現為普通的舊數組(例如,向數組添加3個浮點數而不是調用glVertex3f)然后GL線程只需要使用glBufferSubData將它們加載到卡中。 你贏了兩次:代碼可以在一個線程中運行,並且可以用3個數組寫入而不是3個函數調用“繪制”一個點。

我注意到的其他事情:

VBO和顯示列表具有非常相似的性能。 給定的OpenGL實現很可能在內部使用VBO來存儲顯示列表。 我跳過了頂點數組(一種客戶端VBO)所以我不確定那些。 使用ARO擴展版本的VBO而不是GL 1.5標准,因為英特爾驅動程序僅實現擴展(盡管聲稱支持1.5)並且nvidia和ATI驅動程序不關心。

紋理地圖集規則。 如果您在每張臉上使用一個紋理,請查看地圖集的工作原理。

如果你想看我的代碼,請在github上找到我。

從前到后渲染。 為此,您不需要排序,使用八叉樹。 葉子不是單獨的立方體,而是更大的群體。

每個這樣的葉子的網格應該緩存在顯示列表中(如Bobmitch建議的那樣),或者在頂點緩沖區中更好(更新更便宜)。 生成此網格時, 不要以強力方式生成所有立方體。 相反,對於每個立方體面,檢查它是否在同一個葉子中有一個不透明的鄰居,如果是這樣,你根本不需要生成這個面。 您還可以將具有相同材質的相鄰面統一到一個長矩形中。 您還可以將網格分成六組,每個主方向一組:+/- XYZ面。 僅繪制可能面向相機的那些面部組。

從前到后渲染本身並沒有幫助。 但是,您可以使用現代硬件提供的遮擋剔除來受益於此排序。 在渲染八叉樹葉之前,檢查其bbox是否通過了遮擋查詢。 如果它沒有通過你根本不需要繪制它。

遮擋查詢的替代方法可以是光線跟蹤。 光線跟蹤有利於渲染這樣的環境 您可以投射一組稀疏的光線來近似可見的葉子並僅繪制那些葉子。 但是,這會低估可見性集。

像其他人一樣,我一直在玩一個使用Ogre的塊世界“引擎”,並在我去的時候寫一些文章(參見Block World Articles )。 我一直在采取的基本方法是:

  • 僅創建塊的可見面(不是塊之間的面)。
  • 將世界分成更小的塊(僅用於更快地更新單個塊)。
  • 將塊紋理組合到一個紋理文件(紋理圖集)中。

只需使用這些就可以在大型簡單塊世界中獲得非常好的性能(例如,在體面的硬件上為1024x1024x1024)。

我目前正在使用python / pyglet進行一個Minecraft克隆,僅僅是為了好奇。

我將數據分解成塊,就像在minecraft中一樣,然后為每個塊創建一個基於立方體可見性的opengl displaylist。 然后,我在這些塊上執行簡單的2d視錐體剔除,並在播放器的一定距離內調用每個顯示列表。

在添加/刪除多維數據集時,我重新創建塊的displaylist。

除了完全被其他立方體包圍的立方體之外,沒有遮擋剔除。

對於簡單的場景,這可以在適度的gfx卡上達到600fps以上,視距約為200立方。

Octtree等肯定會起作用,但解決特定問題的另一種可能方法可能是存儲以向每個多維數據集對象添加usigned char visible visible字段的值計算如下:

  • 如果右側(沿x軸看)沒有鄰居,則將設置第一位(1)。
  • 如果左側(沿負x軸看)沒有鄰居,則第二位(2)將被置位。
  • 如果正面(沿z軸看)沒有鄰居,那么將設​​置第3位(4)
  • ...等等,這樣你就可以為立方體的6個邊各占1位

每當玩家挖掘一個立方體時,你必須更新它所有鄰居立方體的visible區域。

那么,這會有什么幫助呢? 如果一個立方體的visible值為0,則很容易 - 該立方體將永遠不會顯示。 但是,假設立方體的visible值為1.然后,如果Xplayer < Xcube ,則立方體(可能)僅可見。 其他方面的工作方式類似,我認為決定一個多維數據集是否可見的這樣一個函數會非常快,並且能夠跳過很多隱藏的多維數據集。

缺點是,此測試只是每個多維數據集測試,您不能跳過完整的組。 因此,可能是一個octtree(用於跳過完整區域)和像這里描述的這樣的可見字段,用於跳過大量隱藏的立方體(由於這些立方體被堆疊,隱藏立方體的數量將遠遠高於可見的數量在該地區內部可能是一個很好的解決方案。

你可以使用PVS(潛在可見集) ,盡管它通常用於地形,同樣的原則適用,剔除無法看到的東西。 Gamedev.net還有一個地形變形文章也涵蓋了這一點。

如果只有繪圖是問題(而不是旋轉未使用的頂點),可能不像c-buffer那樣有用嗎? 我使用它非常成功,它需要排序多邊形(例如通過畫家的算法)和幾乎零內存(與z緩沖區相反)。

僅跟蹤描述表面的立方體。 您可以通過一個簡單的數據結構來實現這一點,其中每個多維數據集都保持對它的鄰居的引用。 在任何現代圖形卡上推動所有這些三角形應該不是問題。 從后到前渲染。 此外,只渲染立方體,然后距觀察者特定距離。 “世界”可以從巨大的“立方體立方體”開始,立方體的外殼由立方體制成。 如果有人挖掘,你可以檢查鄰居位置是否已包含多維數據集,如果不是,則創建這些多維數據集並將其鏈接。

示例:向下挖掘一個平面:移除位於挖掘位置的立方體,在下面添加9個新立方體(但檢查這些位置是否已在使用中,以防使用這些位置),將表面鏈接在一起但將新立方體鏈接到刪除的鄰居多維數據集。

所以:對於包含1000x1000x1000多維數據集的世界,您將獲得:1000 * 1000 * 2 + 998 * 999 * 4 = 5988008而不是1000 * 1000 * 1000 = 1000000000,或者因子數量減少167個。

當然你不應該繪制所有這些立方體,從與觀察者的簡單距離開始做一個子選擇。

您還可以將8個多維數據集(組)組合在一起作為1組,然后繼續這樣,直到最高級別您只有一個多維數據集組(已提到的oct-tree)。 此樹可用於光線跟蹤您需要繪制而不是繪制的世界的哪個部分。 如果一個組包含對其他8個多維數據集組的引用,那么后面的那些不顯示。 后面是這些立方體組,它們不會從用戶開始與光線跟蹤錐體相交或放置,並且僅通過用於測試的組的邊緣。 (不好描述,但我希望你能得到一些關於可以為優化做些什么的提示)。 無論如何,今天的顯卡可能不需要這樣做。

祝你的項目好運。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM