Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Schwarzefee

Treue Seele

  • »Schwarzefee« ist der Autor dieses Themas

Beiträge: 155

Wohnort: Ost-Sachsen

Beruf: Programmierer

  • Private Nachricht senden

1

20.03.2014, 10:58

OpenGL 2D Rendering optimieren

Hi,

Mein OpenGL 2D Renderer ist soweit erstmal funktionsfähig.
Eine minimale Font-Engine ist auch schon eingebaut, damit ich mir mal die FPS anzeigen lassen kann.
Alles in Allem habe ich aber nur knapp halb so viel FPS, wie auf dem gleichen Stand mit DirectX 11.

Als kleinen "Stresstest" hab ich mal 2000 Sprites gerendert, mit wechselnden Texture-Atlassen. D.h. knapp 2000x glDrawElements() pro Frame.
Erreicht habe ich damit knapp 100FPS.

Da ich mit OpenGL noch nicht soo vertraut bin, meine Frage: ist das so in Ordnung oder müsste da mehr drin sein?


Bei jeder Frame schreibe ich die Vertices in ein Array, was dann bei Bedarf (z.B. wenn sich der TextureAtlas ändert, ein anderer Shader verwendet werden soll, etc.) gerendert wird.

C-/C++-Quelltext

1
2
3
4
5
6
7
//Vertices in Array speichern
unsigned int n = this->VerticesInBuffer;
this->VertexData[n++] = *spriteset->GetSpriteVertex(this->Timer->GetTotalTime(),-1,0);
this->VertexData[n++] = *spriteset->GetSpriteVertex(this->Timer->GetTotalTime(),-1,1);
this->VertexData[n++] = *spriteset->GetSpriteVertex(this->Timer->GetTotalTime(),-1,2);
this->VertexData[n++] = *spriteset->GetSpriteVertex(this->Timer->GetTotalTime(),-1,3);
this->VerticesInBuffer += 4;


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//Rendern
glBindBuffer(GL_ARRAY_BUFFER, this->VertexBufferId);
glBufferData(GL_ARRAY_BUFFER, this->VerticesInBuffer * sizeof(Grafics::VERTEX), this->VertexData, GL_DYNAMIC_DRAW);
glEnableClientState(GL_VERTEX_ARRAY);

glBindBuffer(GL_ARRAY_BUFFER, this->VertexBufferId);
if (userectindexbuffer == true)
{
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->RectangleIndexBufferId);
}
glBindVertexArray(this->VertexArrayId);

if (this->CurrentPrimitiveTopology == PRIMITIVE_TRIANGLELIST)
{
    //Triangle - List
    int indexcount = this->VerticesInBuffer / 4 * 6;
    glDrawElements(GL_TRIANGLES, indexcount, GL_UNSIGNED_SHORT, 0);
}
else if (this->CurrentPrimitiveTopology == PRIMITIVE_LINE)
{
    //Lines
    glDrawArrays(GL_LINES, 0, this->VerticesInBuffer);
}
this->VerticesInBuffer = 0;


Gibt es vielleicht noch irgendwelche Funktionen, die man im 2D nicht braucht, und die Standardmäßig laufen?
GL_CULL_FACE und GL_DEPTH_TEST sind schon disabled.


Gruß

Legend

Alter Hase

Beiträge: 731

Beruf: Softwareentwickler

  • Private Nachricht senden

2

20.03.2014, 11:04

Bei jedem Frame glBufferData aufzurufen dürfte nicht optimal sein: http://stackoverflow.com/questions/14155…th-glbufferdata
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

Netzwerkbibliothek von mir, C#, LGPL: https://sourceforge.net/projects/statetransmitt/

Schwarzefee

Treue Seele

  • »Schwarzefee« ist der Autor dieses Themas

Beiträge: 155

Wohnort: Ost-Sachsen

Beruf: Programmierer

  • Private Nachricht senden

3

20.03.2014, 11:24

Hi,

danke für die Antwort.

Heist das, ich sollte lieber glMapBufferRange() benutzen?


Gruß

Legend

Alter Hase

Beiträge: 731

Beruf: Softwareentwickler

  • Private Nachricht senden

4

20.03.2014, 11:33

Das wäre die Entsprechung zu dem wie ich es unter DX11 machen würde und nach dem was ich bei Stackoverflow lese, soll das wohl eine schnellere Methode sein. Also würde ich sagen, ja, das solltest du mal ausprobieren.

Mich hatte halt stutzig gemacht, dass man bei glBufferData die Größe des Puffers mit übergibt und ja, es scheint so zu sein als ob intern der Puffer dabei neu erstellt werden kann. Und sowas ist unabhängig von der API keine schnelle Operation.
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

Netzwerkbibliothek von mir, C#, LGPL: https://sourceforge.net/projects/statetransmitt/

Sc4v

Alter Hase

Beiträge: 376

Beruf: Student

  • Private Nachricht senden

5

20.03.2014, 12:00

In dem Fall, dass du verschiedene Polygone hast, fülle die /den Buffer mit glMapBufferRange.

Wenn du jedoch immer Sprites zeichnest, welche texutrierte Quads sind (entspricht meiner Vorstellung von Sprites), dann brauchst du nur 4 Vertices in einem Buffer. Verschiebe (und Skaliere, Rotiere) dann mit einer Matrix die Vertices an die Position des Sprites. Damit sparst du dir sehr viel Datenübertragung vom CPU zur GPU weil du alle Sprites mit den Daten aus dem selben Buffer zeichnen kannst.


edit :
Siehe auch glBufferData

Zitat

glBufferData — creates and initializes a buffer object's data store.


Das ist nicht das, was du willst ;)

Edit 2:
Ausdruck verändert um meinen Standpunkt klarer zu machen :rolleyes:

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Sc4v« (20.03.2014, 12:07)


Schwarzefee

Treue Seele

  • »Schwarzefee« ist der Autor dieses Themas

Beiträge: 155

Wohnort: Ost-Sachsen

Beruf: Programmierer

  • Private Nachricht senden

6

20.03.2014, 12:21

Hi,


Wenn du jedoch immer Sprites zeichnest, welche texutrierte Quads sind (entspricht meiner Vorstellung von Sprites), dann brauchst du nur 4 Vertices in einem Buffer. Verschiebe (und Skaliere, Rotiere) dann mit einer Matrix die Vertices an die Position des Sprites. Damit sparst du dir sehr viel Datenübertragung vom CPU zur GPU weil du alle Sprites mit den Daten aus dem selben Buffer zeichnen kannst.

das versteh ich nicht so ganz.
Wenn ich nur 1 Quad im Buffer habe, muss ich doch für jede Sprite ein glDrawElements() aufrufen, oder?
Ich hab bisher gedacht, dass man das so wenig wie möglich aufrufen soll.
Oder hab ich was falsch verstanden? Ein Beispiel wäre nützlich.

Gruß

Legend

Alter Hase

Beiträge: 731

Beruf: Softwareentwickler

  • Private Nachricht senden

7

20.03.2014, 12:25

Mit Instancing könnte das funktionieren.
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

Netzwerkbibliothek von mir, C#, LGPL: https://sourceforge.net/projects/statetransmitt/

Sc4v

Alter Hase

Beiträge: 376

Beruf: Student

  • Private Nachricht senden

8

20.03.2014, 12:47

Wenn ich nur 1 Quad im Buffer habe, muss ich doch für jede Sprite ein glDrawElements() aufrufen, oder?



Ich vermute, dass das viel schneller ist als jedesmal Vertices auf die GPU zu laden

Mit Instancing könnte das funktionieren.


Dadurch würde man nur einen Aufruf von glDrawElementsInstanced pro Textur-Atlas brauchen, wenn ich nicht irre. Kompensiert also das erste Problem.

Schwarzefee

Treue Seele

  • »Schwarzefee« ist der Autor dieses Themas

Beiträge: 155

Wohnort: Ost-Sachsen

Beruf: Programmierer

  • Private Nachricht senden

9

20.03.2014, 14:55

Hi,

mit Instancing hab ich bisher noch nichts gemacht.
Wie muss ich mir das vorstellen? Woher weis der Shader dann, welche Position und Texture-Koordinaten das Vertex hat?



Gruß

Sc4v

Alter Hase

Beiträge: 376

Beruf: Student

  • Private Nachricht senden

10

20.03.2014, 15:18

Du füllst Array Buffer mit den Matrizen und bindest die als Vertex Attribute an den VAO mit einem glVertexAtttibDivisor.
Siehe hier

Werbeanzeige