簡體   English   中英

OpenGL> v3、2D游戲高效渲染

[英]OpenGl > v3, 2d game efficient rendering

我對VBO和現代的openGL感到困惑。 這篇文章的末尾有一個直接的問題,然后有很多問題。 如果您對此有任何建議,我將不勝感激。 如果您答復,請不加任何知識將我視為完全的白痴。

所以,我的歷史是這樣的:

我有一個游戲,這是一個自上而下的2D游戲。 我已經使用了酰亞胺化模式來渲染2D精靈。 我的紋理地圖集的實際紋理坐標是靜態的,並且在單獨的類中進行了預定義。 在每個實體中定義了四邊形坐標,並隨着游戲的進行而更新。 渲染時,我只綁定了一個特定的紋理,稱為glBegin(triangles),然后稱為每個可見對象的render方法。 依次將四邊形坐標和紋理坐標發送到我的Renderer類,該類進行了openGl調用。 然后,我刷新了紋理,該紋理僅調用glEnd()。

我針對所有不同的地圖集並按順序進行了此操作,以便獲得適當的深度。

但是時代確實在改變。 我想使用VBO和着色器。 我過去嘗試過幾次,但失敗了。 我在Google上找不到的一些事情可以使我對其有一個完整的了解,以及如何使用它來加快我的游戲速度。

我知道基本知識。 不必在每個渲染調用時通過總線將所有信息發送到gpu,而是可以簡單地存儲初始化階段所需的一切,然后使用着色器計算最終結果。 但...

我對紋理坐標有了一個想法。 這些將是靜態的,因為它們永遠不會改變。 最好將它們存儲在GPU上。 但是我怎么知道哪個坐標對應於每個QUAD / TRIANGLE。 我在想,游戲中的每個可渲染對象可以代替四個浮點數,而可以具有某種索引,並將其作為屬性傳遞給頂點着色器。 頂點着色器使用索引在VBO中查找四個紋理坐標。 這是可行的解決方案嗎? 您將如何實現這樣的目標?

但至於四方證明書,我迷失了。 這些將不斷移動。 它們將是可見的,然后消失。等等。這意味着我的Quad VBO將在每次渲染調用時更改,並且我所看到的更新VBO的代碼非常難看。 我看過類似的東西:

  • 將4個四邊形坐標存儲在數組中。
  • 創建一個floatbuffer,將它們放在那里
  • 操作緩沖區。
  • 發送緩沖區到VBO

對我來說看起來很昂貴。 而且我不了解如何刪除某個條目(如果實體移出屏幕等),也無法理解如何操縱某個條目(實體移出)。 而且,如果我必須以這種方式在每個渲染調用中更新VBO,那么性能會有什么提高? 看起來更像是對我的損失...

另外,如何跟蹤結果圖像的“深度”。 我正在執行2d,但是“深度”是指渲染的順序,例如,確保object2在object1的頂部渲染。 每個深度都有不同的VBO嗎? 還是我應該使用z坐標來擴大深度。 后者會不會給表演帶來打擊?

還有2d因素。 我對3d表示最崇高的敬意,但我想使用2d並充分利用它在理論上應能產生更好性能的事實。 但是,從我收集的數據來看,情況似乎並非如此。 在opengl 3+中,似乎要讓我渲染2d內容,我需要先將其轉換為3d,因為這就是硬件的處理過程。 對我來說似乎很奇怪,因為屏幕上的最終結果是2d。 有沒有辦法避免這種情況,並將GPU保存為2d-> 3d-> 2d的工作?

換句話說,我該如何有效地改變這一點:

class main{

void main(){
while(true){
Renderer.bind();
//call render in all gameObjects
Renderer.flush();
}
}
}

class GameObject{

private float X1, X2, Y1, Y2;
private TexureCoordinate tex;

render(float dt){
//update X1, X2...
Renderer.render(tex.getX1(), tex.getX2()... X1, X2 ...);
}

}

class Renderer{

//called once
void bind(Texture texture){
    texture.bind();
    glBegin(GL_TRIANGLES)

}

//called "nr of visable objects" times
void render(texX1, texX2, texY1, texY2, quadX1, quadX2, quadY1, quadY2){

glTexCoo2d(texX1, texY1)
....
etc.
....
}

void flush(){
glEnd();
}
}

變成使用現代openGl的東西嗎?

首要而又最重要的關鍵見解是, 頂點不僅僅是位置 頂點是用於在調用glVertex之前在即時模式圖形調用中預設的屬性的整個元組。 如果僅更改其中一個屬性,則最終得到的頂點將非常不同。

讓我們從VBO退后一會兒,以使整個glBuffer [Sub] Data脫離干擾,並查看普通的舊客戶端頂點數組(大約與立即模式一樣長)。

假設您有兩個位置數組,它們的布局完全相同,但是值不同:

GLfloat quad_pos_a[2][4] = {
  {1,2}, {2,2}, {2,3}, {1,3}
};

GLfloat quad_pos_b[2][4] = {
  {5,5}, {10,5}, {10,20}, {5,20}
};

除了它們的值之外,它們的布局是相同的:依次包含四個2元素屬性。 這可以輕松地使用通用的紋理坐標數組,以匹配這兩個四邊形的布局:

GLfloat quad_texc[2][4] = {
  {0,0},{1,0},{1,1},{0,1}
};

我認為如何使用立即模式調用繪制quad_pos_aquad_pos_b共享quad_texc對您來說應該顯而易見。 如果不是很明顯,現在是時候解決了。 這個答案是有耐心的,將等待您完成……


間斷


…由於將幾何數​​據放入數組是顯而易見的事情,因此OpenGL很快引入了一個稱為頂點數組的概念:您可以告訴OpenGL從何處獲取頂點數據,然后只告訴它有多少個頂點繪制,或在給定索引列表的情況下從數組中選取哪些頂點。

使用VA如下所示:

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glVertexPointer(
  2 /* = number of elements per attribute */,
  GL_FLOAT /* type of attribute elements */,
  0 /* = the byte distance between attributes OR zero if tightly packed */,
  quad_pos_a );
glTexCoordPointer(
  2 /* = number of elements per attribute */,
  GL_FLOAT /* type of attribute elements */,
  0 /* = the byte distance between attributes OR zero if tightly packed */,
  quad_texc );

glDrawArrays(
  GL_QUADS /* what to draw */,
  0 /* which index to start with */,
  4 /* how many vertices to process*/ );

或者,如果您只想繪制第0,第1和第3個頂點的三角形:

GLushort indices[] = {0,1,3};
glDrawElements(
  GL_TRIANGLES /* what */,
  3 /* how many */,
  GL_UNSIGNED_SHORT /* type of index elements */,
  indices );

現在,普通的舊頂點數組和VBO之間的主要區別在於,VBO將數據放在OpenGL的保管中–就是這樣。 如果您了解VA,則可以理解VBO。 但是,與VA不同,您不能輕易更改VBO的內容。 着色器的區別在於不再定義屬性的類型。 而是使用glEnableVertexAttribArray (而不是glEnableClientState )和glVertexAttribPointer設置通用的頂點屬性。

那么如何節省上傳更新數據的開銷呢? 好吧,這取決於您認為昂貴的東西:數據最終必須通過GPU。 因此,將其打包到合並的緩沖區中的數據上傳傳輸可能是有益的,因為它節省了將每個glVertex調用分塊的每次調用開銷。

暫無
暫無

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

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