2017-06-02 101 views
0

我使用渲染循環如下;各種頂點格式和vbo

  1. 孤立數據並映射緩衝區。
  2. 記錄命令並將生成的頂點寫入緩衝區。
  3. 取消映射緩衝區。
  4. 迭代可以改變狀態,綁定紋理或繪製的命令。

此刻我使用了一個交叉點頂點格式(SoA),它具有我的任何着色器可以使用的所有屬性。

struct OneSizeFitAllVertex 
{ 
    float pos[3]; 
    float uv0[2]; 
    float uv1[2]; 
    float col[4]; 
}; 

當使用簡單的着色器僅使用位置和顏色,例如,我只寫我在乎的映射內存和shader代碼會簡單地忽略所有未使用的屬性的屬性。

因爲這感覺很浪費,所以我正在考慮對每個着色器使用不同的頂點格式。

struct SimpleVertex 
{ 
    float pos[3]; 
    float col[4]; 
}; 

而另一些人,多紋理對象,將使用多紋理着色器進行渲染和使用MultitextureVertex:使用簡單的着色器將使用SimpleVertex呈現

簡單對象

struct MultitextureVertex 
{ 
    float pos[3]; 
    float uv0[2]; 
    float uv1[2]; 
}; 

我應該如何處理這些不同的格式?

我應該在繪製前將所有不同格式的頂點寫入同一個映射緩衝區並更改我的AttribPointers嗎?這將節省一些空間。

我應該爲每個頂點格式映射不同的緩衝區嗎?也許更有效率。

或者我應該保持'一個尺寸適合所有'頂點格式?這很容易。

我很想知道什麼是這種情況下的最佳做法。 謝謝。

+0

除了我最喜歡的建議「任何讓你的生活變得最簡單,並且能夠最快地完成工作」,如果移動到多個頂點結構會導致你重複數據(例如,你會使用相同的位置值兩個單獨的數組),那會很糟糕。有一點不清楚的是,如果您對相同的數據使用不同的着色器(例如,如果您有對象,並通過切換着色器在不同的外觀之間切換),或者每個着色器都有自己的數據。但是,如果所有着色器都使用來自同一陣列的數據,則您的方法是最簡單的。 – radical7

回答

0

根據您的底層系統架構,可能會有很多變體,但假設您正在使用具有專用圖形內存的獨立GPU(例如AMD或NVIDIA)。

如果你在一個陣列結構的交錯您的屬性(AOS)你不提(也許是類似以下內容):

struct Vertex { 
    float position[3]; 
    float normal[3]; 
    float uv[2]; 
    ... 
}; 

或屬性組相似的一起(通常稱爲結構陣列或(SoA的))

struct VertexAttributes { 
    float positions[N][3]; 
    float normals[N][3]; 
    float uv[N][2]; 
    ... 
}; 

這是相關的,因爲你是緩衝區映射方法。當你映射整個緩衝區時,GPU可能需要將其版本的緩衝區複製到CPU,CPU爲您提供更新值的指針。當您取消映射緩衝區時,驅動程序會將緩衝區複製回GPU。通過佈局和技巧,您將觸及整個緩衝區的小部分,並且由於GPU驅動程序不知道您更新了哪些內存位,所以唯一的辦法是將整個事件複製回GPU。根據大小,這可能會在多個級別產生重大影響(較差的CPU高速緩存讀取利用率,消耗大量CPU到GPU總線帶寬等)。不幸的是,如果只更新一小部分頂點屬性,沒有好的選擇。但是,如果要更新所有屬性,則此方法可行(儘管通常建議使用glBufferSubData或類似命令,這些命令可將讀回從GPU保存到CPU)。相反,如果您使用的是SoA方法,則將整個緩衝區映射到相同的問題將導致類似的問題,但情況會更好。由於特定屬性的值在內存中是連續的,因此您可以使用類似於glMapBufferRange的內容來映射您所需的內存(但是,我仍然推薦使用glBufferSubData來達到上述原因)。鑑於你目前的情況,這是我的建議。

+0

我正在使用AoS,但這不重要。我的問題是關於我應該做什麼,如果我有程序,使用* struct vert_uv {float pos [3]; float uv [2]}; *和* struct vert_col {float pos [3]; float col [4]}; *?對不起的解釋,我會嘗試更新我的問題,當我找出一種方式來更清楚地表達它。 –