[英]What is the most efficient way of rendering 2D game with the possibility of changing the resolution?
[英]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的代碼非常難看。 我看過類似的東西:
對我來說看起來很昂貴。 而且我不了解如何刪除某個條目(如果實體移出屏幕等),也無法理解如何操縱某個條目(實體移出)。 而且,如果我必須以這種方式在每個渲染調用中更新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_a
和quad_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.