2012-03-26 44 views
23

我已經使用OpenGL和C++進行了各種演示項目,但他們都涉及簡單地渲染一個有一些有趣效果的單個立方體(或類似的簡單網格)。對於這樣的簡單場景,立方體的頂點數據可以存儲在不雅觀的全局數組中。我現在正在研究渲染更復雜的場景,以及不同類型的多個對象。OpenGL和OOP程序結構

我覺得很有道理,爲不同類型的對象(RockTreeCharacter等)的不同的類,但我不知道如何幹淨地打破了數據和場景中的對象渲染功能。每個類將存儲它自己的頂點位置,紋理座標,法線等數組。然而,我不確定在哪裏放置OpenGL調用。我想我會有一個循環(在WorldScene類中)遍歷場景中的所有對象並呈現它們。

應該渲染它們涉及調用每個對象中的渲染方法(Rock::render(), Tree::render(),...)或將對象作爲參數的單個渲染方法(render(Rock), render(Tree),...)?後者看起來更清晰,因爲我不會在每個類中都有重複的代碼(儘管可以通過繼承一個RenderableObject類來緩​​解這個問題),並且如果我想稍後將端口轉換爲的DirectX。另一方面,我不確定是否可以將它們分開,因爲無論如何,我可能都需要存儲在對象中的OpenGL特定類型(例如,頂點緩衝區)。另外,將渲染功能與對象分開似乎有點麻煩,因爲它必須調用大量的Get()方法才能從對象中獲取數據。最後,我不確定這個系統如何處理必須以不同方式繪製的對象(不同的着色器,不同的變量傳遞給着色器等)。

這些設計之一明顯比其他設計更好嗎?我可以通過哪些方式改進他們,以使我的代碼組織良好並且高效?

回答

22

首先,現在甚至不打擾平臺獨立性。等到你對架構有更好的瞭解。

做很多繪製調用/狀態更改很慢。你在引擎中執行的方式通常是希望有一個可以繪製自己的可渲染類。這種可渲染將與它需要的任何緩衝區(例如頂點緩衝區)和其他信息(如頂點格式,拓撲結構,索引緩衝區等)相關聯。着色器輸入佈局可以與頂點格式相關聯。

你會想要一些原始的地理類,但延遲任何複雜的一些類型的網格類,它處理索引tris。對於高性能應用程序,您需要在着色管道中爲相似的輸入類型批量調用(以及可能的數據),以儘量減少不必要的狀態更改和管道刷新。

着色器參數和紋理通常通過與可呈現相關聯的某個材質類進行控制。

場景中的每個可渲染對象通常是層次場景圖中節點的一個組件,其中每個節點通常通過某種機制繼承其祖先的變換。您可能需要一個使用空間分區方案的場景調色板來快速進行可視性確定,並避免出現視圖調用開銷。

大多數交互式3D應用程序的腳本/行爲部分與其場景圖節點框架和事件/消息傳遞系統緊密連接或掛鉤。

這一切都集中在一個高級循環中,您可以根據時間更新每個子系統並在當前幀處繪製場景。

顯然有一小堆細節遺漏了,但它可能會變得非常複雜,這取決於您想要的泛化和性能以及您瞄準的視覺複雜程度。

您的問題draw(renderable),或renderable.draw()或多或少是無關緊要的,直到您確定所有部件如何配合在一起爲止。

[更新]在這個空間多一點的工作之後,一些額外的洞察力

話雖如此,在商業引擎,其通常更喜歡draw(renderBatch)其中每個渲染批次對象的集合由於在異構對象(在純粹的「OOP場景圖形通過多態性)上迭代並且一個接一個地調用obj.draw()具有可怕的緩存局部性並且通常是GPU資源的低效使用,所以它們以某種有意義的方式與GPU一致。採用面向數據的方法來設計引擎如何以儘可能最有效的方式與底層圖形API進行對話,儘可能多地分配事務而不會對代碼結構/可讀性產生負面影響是非常有用的。

一個實際的建議是編寫第一個引擎使用天真/「純」的方法來真正熟悉域空間。然後在第二遍(或者可能重寫)時,專注於硬件:諸如內存表示,緩存局部性,流水線狀態,帶寬,批處理和並行性等。一旦你真正開始考慮這些事情,你會意識到,你的初步設計大部分都在窗外。好開心。

+1

謝謝,這給了我幾個想法。我不太瞭解的一件事是可提供的類和你提到的網格類之間的區別。我不希望網格類是可以繪製自己的可渲染的嗎?在更高層次上,我認爲設計將比我預期的更復雜。你知道任何提供設計渲染系統的好介紹的在線資源嗎?我找到的大多數OpenGL教程都介紹了繪製,紋理和點亮幾個三角形的過程,而沒有對大圖片架構進行太多討論。 – Jeff 2012-03-26 20:00:56

+0

@Jeff:沒有。網格只是頂點數據的集合。單獨的網格*是不夠的。爲了渲染某些東西,你需要一個網格,你想要渲染的着色器,以及其他各種狀態(紋理等)。 – 2012-03-27 00:37:52

+0

@Jeff尼科爾說的是正確的。並非所有繪製的東西都是網格物體(例如,您可能還想繪製線條或其他像四邊形網格物體可能會過度殺傷的其他原始物體)。一個網格類應該描述幾何體(有時候每三層都有材料索引,分組/層次結構),但是沒有其他的東西。看看有關遊戲引擎開發的書籍(即使你沒有製作遊戲)。一個好的是「遊戲引擎架構」,也是「遊戲編程寶石」和「遊戲引擎寶石」有很多很好的信息。您可能還想潛伏gamedev.net論壇 – 2012-03-27 01:26:04

3

我認爲OpenSceneGraph是一種回答。看看它和它的implementation。它應該爲您提供一些有關如何使用OpenGL,C++和OOP的有趣見解。

+0

感謝您的建議;我會檢查一下,看看我能從中得到什麼。然而,我認爲我真正需要的是規模稍小一點的東西,這是典型的OpenGL教程(例如渲染光照,紋理,旋轉立方體)與完整圖形庫之間的墊腳石。 – Jeff 2012-03-26 20:07:11

0

這是我爲物理仿真所實現的功能,以及工作得很好,並且處於良好的抽象層次。首先,我想分開功能分爲類,如:

  • 對象 - 容器保存所有必需的對象信息
  • AssetManager - 加載模型和紋理,擁有它們(的unique_ptr),返回原始指針對象的資源
  • 渲染器 - 處理所有OpenGL調用等,在GPU上分配緩衝區並返回資源的渲染句柄給對象(當需要渲染器繪製對象時,我稱渲染器爲它提供模型渲染處理,紋理句柄和模型矩陣),渲染器應該彙總這些信息o能夠批量繪製它們
  • 物理 - 使用物體及其資源的計算(特別是頂點)
  • 場景 - 連接上述所有物體,也可以容納一些場景圖形,取決於應用程序的性質(可以有多個圖形,用於碰撞的BVH,其他繪圖優化等)

問題是GPU現在是GPGPU(通用gpu),所以OpenGL或Vulkan不再只是一個渲染框架。例如物理計算正在GPU上執行。因此,渲染器現在可能轉換成諸如GPUManager和其上的其他抽象。最好的繪製方式是在一次調用中。換句話說,整個場景的一個大緩衝區也可以通過計算着色器進行編輯,以防止CPU通信過多。