Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Fr Jul 18, 2025 11:20

Foren-Übersicht » Programmierung » OpenGL
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 13 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Performanceprobleme bei 65k+ Spheres
BeitragVerfasst: Fr Okt 21, 2011 16:42 
Offline
DGL Member

Registriert: Mi Okt 16, 2002 15:06
Beiträge: 1012
Hallo,

ich bastel gerade an einer Fluid Partikel Simulation basierend auf PhysX und habe probleme mit dem Rendering.
Sobald ich um die 65k Spheres Rendere welches die Fluid Partikel darstellen soll bricht die Framerate ein. GTX580M 2GB, 16 GB DDR3, Core i7 Extreme Edition.

Habe es auch mal simpel ohne PhysX ausprobiert, einfach mit Freeglut 64x64x64 Spheres Rendern lassen mit folgenden konstrukt:

Code:
  1.  
  2. void RenderManyParticles()
  3. {
  4.     float centerX = 0.0f;
  5.     float centerY = 0.0f;
  6.     float centerZ = 3.0f;
  7.  
  8.     int numX = 64;
  9.     int numY = 64;
  10.     int numZ = 64;
  11.  
  12.     float dX = gFluidParticleDistance * numX;
  13.     float dY = gFluidParticleDistance * numY;
  14.     float dZ = gFluidParticleDistance * numZ;
  15.  
  16.     int numParticles = numX * numY * numZ;
  17.  
  18.     gTotalFluidParticles = numParticles;
  19.  
  20.     PxVec3* particlePositionBuffer = new PxVec3[numParticles];
  21.     int idx = 0;
  22.  
  23.     float ypos = centerY - (dY / 2.0f);
  24.     for (int y = 0; y < numY; y++)
  25.     {
  26.         float xpos = centerX - (dX / 2.0f);
  27.         for (int x = 0; x < numX; x++)
  28.         {
  29.             float zpos = centerZ - (dZ / 2.0f);
  30.             for (int z = 0; z < numZ; z++)
  31.             {
  32.                 particlePositionBuffer[idx].x = xpos;
  33.                 particlePositionBuffer[idx].y = zpos;
  34.                 particlePositionBuffer[idx].z = ypos;
  35.                 idx++;
  36.                 zpos += gFluidParticleDistance;
  37.             }
  38.             xpos += gFluidParticleDistance;
  39.         }
  40.         ypos += gFluidParticleDistance;
  41.     }
  42.  
  43.     for (int i = 0; i < numParticles; i++)
  44.     {
  45.         glPushMatrix();
  46.         glTranslatef(particlePositionBuffer[i].x, particlePositionBuffer[i].y, particlePositionBuffer[i].z);
  47.         glCallList(gSphereListID); // Display zur Kompilierten Sphere (0.05, 8, 8)
  48.         glPopMatrix();
  49.     }
  50.  
  51.     delete particlePositionBuffer;
  52. }
  53.  


Was kann man denn hier tun, um wirklich mehr als 65k Partikel zu Rendern? Oder packt die Karte das einfach nicht, kann ich mir ja fast nicht vorstellen.

Hab da mal eine liste angefertigt für sachen die mir einfallen, ich aber nichts davon ausprobiert habe.
Wollte lieber mal fragen, nacher mach ich wieder unnötigen mist rein, der eh nix bringt oder es noch schlimmer macht.

- glPush/PopMatrix ersetzten durch eigene Matrix routinen (GL3 Kompatibel)
Würde das viel Performance bringen?

- glutSolidSphere() durch was eigenes ersetzten?

- VBO anstatt Displayliste?
Ob ich jetzt nen VBO nehme, oder ne Displayliste, macht das hier an der Stelle einen großen Unterschied?

- Idee die Partikelpositionen zur Laufzeit in eine Texture zu schreiben und mit GLSL die eigentlichen Partikel rendern
Das klingt für mich nach einem sinnvollen aber aufwendigen weg, bin ich mir hier auch nicht sicher ob das soviel bringen könnte.
Weil ich ja für jedes Frame, oder bzw in einem bestimmten Zeitinterval die Partikelpositionen in eine Texture schreiben müsste.
Vermutlich wäre hier PBO und FBO der richtige ansatz? PBO habe ich schonmal benutzt, FBO allerdings nicht.

- Eigenlich hätte ich ja gerne richtig aussehendes wasser, siehe: http://www.geeks3d.com/20100809/siggraph-2010-screen-space-fluid-rendering-for-games/
Wie ich schon oben geschrieben habe, von FBO habe ich noch keine Ahnung, und wie das später alles dann zusammenfügen kann ebenso wenig
Klingt für mich ähnlich wie das Deffered Rendering...

- Point Sprites? Anstatt Spheres??

- Occlusion Culling um nicht sichtbare Spheres nicht zeichnen zu müssen?
Also z.b. die Spheres die in der Mitte vom Wasser sind z.b.

Gruß,
Final


Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 21, 2011 17:33 
Offline
DGL Member

Registriert: Fr Okt 03, 2008 13:32
Beiträge: 367
Das beste wäre wohl, wenn man Instancing und eine Textur oder ein Texture Buffer Object benutzt um die Positionen via Shader zu verändern.

Ansonsten gibt es noch ein paar kleine Sachen die man schnell mal probieren kann:
Man könnte das glPush- und glPopMatrix aus der Schleife entfernen (das verbraucht auch einiges an Zeit) und vllt gegen ein glLoadMatrix ersetzen.

65k mal glCallList dürfte auch einiges an geschwindigkeit fressen. Das ist das selbe bei VBOs. Wenn die zu wenig Vertices haben lohnt sich das nicht wirklich. Möglicherweise wäre es sogar schneller die ganzen Kugeln in einen großen glBegin...glEnd Block zu zeichnen. Kommt aber wohl auf den Detailgrad an.

Billboards statt Kugeln dürften auch einiges bringen. Damit man die später auch ordentlich beleuchten kann, packt man da einfach eine Normalmap drauf. Wenn man der einen Alphakanal gibt, kann man auch die Grenzen von den Partikeln verschwimmen lassen, wodurch man einen "flüssigen" Übergang erhält und keinen Haufen Kugeln. Das Problem dabei ist bloß die Sortierung nach der Tiefe. Wenn man das nicht machen will, kann man auch harte Übergänge nehmen (Alpha-Test) und das resultierende Bild blurren.

Occlusion Culling macht denke ich nur Sinn, wenn die zu zeichnende Geometrie aufwändiger ist als ihr Bounding Volume, was bei einer Kugeln nicht wirklich gegeben ist. Ansonsten wüsste ich nicht wie man in Hardware testen will ob eine Kugel sichbar ist ohne sie nicht selbst gleich zu zeichnen.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Okt 21, 2011 23:28 
Offline
DGL Member

Registriert: Do Jun 28, 2007 17:58
Beiträge: 193
Programmiersprache: Pascal, C
Kugeln kann man im Shader sehr einfach und effizient per Raytracing berechnen - alles was du benötigst sind parallel zur Kamera ausgerichtete Quads. Dabei kann man Z-Test, Alphakanal, Normale komplett im Shader ohne Textur durchführen. Damit erreicht man selbst auf integrierter Grafik und >60k Kugeln interaktive Frameraten.

Siehe: http://web4.cs.ucl.ac.uk/staff/t.weyric ... /pbg06.pdf

_________________
http://audorra.sourceforge.net//http://andorra.sourceforge.net


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Okt 22, 2011 09:27 
Offline
DGL Member

Registriert: Mi Jan 21, 2009 09:05
Beiträge: 13
Hallo,

NVIDIA hat in einer CUDA Demo einen Shader benutzt um Punkte als Kugeln zu rendern (http://developer.download.nvidia.com/co ... ation.html die Particles Demo). Vielleicht einfach mal reinschaun aber mit der Methode sind >300K Kugeln kein Problem.

Der Shader:
Code:
  1. const char *vertexShader = STRINGIFY(
  2. uniform float pointRadius;  // point size in world space
  3. uniform float pointScale;   // scale to calculate size in pixels
  4. uniform float densityScale;
  5. uniform float densityOffset;
  6. void main()
  7. {
  8.     // calculate window-space point size
  9.     vec3 posEye = vec3(gl_ModelViewMatrix * vec4(gl_Vertex.xyz, 1.0));
  10.     float dist = length(posEye);
  11.     gl_PointSize = pointRadius * (pointScale / dist);
  12.  
  13.     gl_TexCoord[0] = gl_MultiTexCoord0;
  14.     gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz, 1.0);
  15.  
  16.     gl_FrontColor = gl_Color;
  17. }
  18. );
  19.  
  20. // pixel shader for rendering points as shaded spheres
  21. const char *spherePixelShader = STRINGIFY(
  22. uniform vec3 lightDir = vec3(0.577, 0.577, 0.577);
  23. void main()
  24. {
  25.     // calculate normal from texture coordinates
  26.     vec3 N;
  27.     N.xy = gl_TexCoord[0].xy*vec2(2.0, -2.0) + vec2(-1.0, 1.0);
  28.     float mag = dot(N.xy, N.xy);
  29.     if (mag > 1) discard;   // kill pixels outside circle
  30.     N.z = sqrt(1-mag);
  31.  
  32.     // calculate lighting
  33.     float diffuse = max(0.0, dot(lightDir, N));
  34.  
  35.     gl_FragColor = gl_Color * diffuse;
  36. }
  37. );


Die Rendermethode:
Code:
  1.  
  2.         glEnable(GL_POINT_SPRITE_ARB);
  3.         glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
  4.         glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_NV);
  5.         glDepthMask(GL_TRUE);
  6.         glEnable(GL_DEPTH_TEST);
  7.  
  8.         glUseProgram(m_program);
  9.         glUniform1f( glGetUniformLocation(m_program, "pointScale"), m_window_h / tan(m_fov*0.5*M_PI/180.0) );
  10.         glUniform1f( glGetUniformLocation(m_program, "pointRadius"), m_particleRadius );
  11.  
  12.         glColor3f(1, 1, 1);
  13.         glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_vbo);
  14.         glVertexPointer(4, GL_FLOAT, 0, 0);
  15.         glEnableClientState(GL_VERTEX_ARRAY);                
  16.  
  17.         if (m_colorVBO) {
  18.             glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_colorVBO);
  19.             glColorPointer(4, GL_FLOAT, 0, 0);
  20.             glEnableClientState(GL_COLOR_ARRAY);
  21.         }
  22.  
  23.         glDrawArrays(GL_POINTS, 0, m_numParticles);
  24.  
  25.         glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
  26.         glDisableClientState(GL_VERTEX_ARRAY);
  27.         glDisableClientState(GL_COLOR_ARRAY);
  28.  
  29.         glUseProgram(0);
  30.         glDisable(GL_POINT_SPRITE_ARB);
  31.  


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Okt 22, 2011 12:43 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Dein Bottleneck dürften die DrawCalls sein. Mit Instancing dürftest du daher schon recht weit kommen. Einfach deine Partikel-Positionen in einem TBO speichern und im Vertexshader darauf zugreifen. In der Shadersammlung gibts sogar ein Beispiel.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Okt 23, 2011 11:52 
Offline
DGL Member

Registriert: Mi Okt 16, 2002 15:06
Beiträge: 1012
Ich habe ein interessantes Instancing Paper gefunden und direkt umgesetzt.
Das paper habe ich von hier: http://www.slideshare.net/acbess/instancing-presentation

Aber es funktioniert nicht, er zeichnet irgendwie nur ein bruchteil davon was er zeichnen soll.

Habe mal den kompletten source (VC++ 2010) dazu gepackt, bitte schaut euch das teil mal an.
Das meiste in main.cpp, und VBO, GLSL kram ist seperate files umgeteilt.

Mit 'R' könnt ihr zwischen Instancing und nicht Instancing Rendern wechseln.
Nicht instancing funktioniert einwandfrei und ist bei 32k Spheres sogar wesentlich flotter als mit...

Habs so umgesetzt wie in dem Paper gestanden ist, aber dennoch tut es nicht wirklich.

Siehe Bilder für Vergleiche oder schaut euch einfach die demo an. SM 4.0 ist voraussetzung.

Hier der source: http://xenorate.com/tl_files/somekram/Instancing.zip

Danke fürs Helfen bisher,
Final

Achja, das Instancing Beispiel in der Shadersammlung basiert ja auch auf dem Instancing was hier verwendet wird,
nur das halt die Positionen in ner Texture gespeichert werden und nicht einfach direkt im Speicher.

Wenn das mit dem Instancing klappt, dann werd ich das mitem TBO´s noch zusätzlich einbauen um herauszufinden, was am schnellsten ist,
weil ich am ende ja in PhysX die Positionsdaten pro frame eh irgendwo hinschreiben muss, ob jetzt ein TBO oder direkt im speicher ist eigentlich egal.


Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Okt 23, 2011 20:06 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
ob jetzt ein TBO oder direkt im speicher ist eigentlich egal.

Was meinst du mir direkt im Speicher? Ein TBO ist doch einfach nur ein Array auf das du per Index zugreifen kannst? Haben die mittlerweile noch was direkteres erfunden? (Edit: Oder meinst du Uniforms?)

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Okt 23, 2011 20:21 
Offline
DGL Member

Registriert: Mi Okt 16, 2002 15:06
Beiträge: 1012
Coolcat hat geschrieben:
Zitat:
ob jetzt ein TBO oder direkt im speicher ist eigentlich egal.

Was meinst du mir direkt im Speicher? Ein TBO ist doch einfach nur ein Array auf das du per Index zugreifen kannst? Haben die mittlerweile noch was direkteres erfunden?


Jop, über Uniform Buffer das ebenfalls ab OGL 3.1 verfügbar ist.
Aber um ehrlich zu sein, weiss ich zu wenig darüber um da genau was zu sagen.

Das Paper hat sich relativ einfach und verständlich gelesen, daher habe ich es nicht wirklich hinterfragt.
Das werde ich wohl jetzt nachholen.... da es ja nicht läuft :(

Und dann werd ich das mit dem TBO und dem texelFetchBuffer probieren.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Okt 23, 2011 20:45 
Offline
DGL Member

Registriert: Mi Okt 16, 2002 15:06
Beiträge: 1012
k ich habe wohl eine einfache Antwort auf mein Problem.

Max Uniform Buffer Größe ist bei meiner GTX 580M - 65536 Bytes.

Brauche aber für 262144 Spheres exakt 4194304 bytes, stell ich die Anzahl der Spheres runter so das ich im bereich der 65kb bleibe...
...geht das instancing einwandfrei.

Das reicht genau für 4096 Spheres (Wegen alignment problem, kann man nicht vec3 nehmen), ist also zuwenig.

Ich werd das nun mit den TBO´s umsetzten. Das unterstützt 128MB und mehr speicher =)

Gruß,
Final


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Okt 24, 2011 07:57 
Offline
DGL Member
Benutzeravatar

Registriert: Di Dez 27, 2005 12:44
Beiträge: 393
Wohnort: Berlin
Programmiersprache: Java, C++, Groovy
Hallo,

ich nehme mal an, dass die 65k Spheres nicht zur selben Zeit sichtbar sind. Front-To-Back sorting und Occlusion Culling (mit einfacher Bounding-Box) dürften auch hilfreich sein.

Viele Grüße
dj3hut1

_________________
Wenn Gauß heute lebte, wäre er ein Hacker.
Peter Sarnak, Professor an der Princeton University


Zuletzt geändert von dj3hut1 am Mo Okt 24, 2011 16:27, insgesamt 1-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Okt 24, 2011 12:34 
Offline
DGL Member

Registriert: Mi Okt 16, 2002 15:06
Beiträge: 1012
Yay, habs hingekriegt mit den TBO´s. Funktioniert wunderbar.

Nachdem ich meinen PPL shader durch einen normalen GL Directional Light getauscht habe ist auch die TBO methode immer schneller =)

Aber am meisten bringt es, wenn mein VBO nicht so viele dreiecke hat.

Daher eine Frage, wie kann man eine halbweg gutaussehende Kugel Rendern mit wenigen Dreiecken.
Aktuell mach ich das über eine Erzeugung von einem Octahedron mittels Subdivision.

Hier ein paar infos...

262144 Instanzen mit 288 Dreiecken:
Ohne TBO: max 12 fps
Mit TBO: 25 fps

262144 Instanzen mit 72 Dreiecken:
Ohne TBO: max 12 fps
Mit TBO: 80-90 fps

Habe mal den Source + Demo hochgeladen, könnt ihr gerne mal ausprobieren und verbessern =)
Ich bau das auf jedenfall mal in meine PhysX Fluid Simulation ein...

http://xenorate.com/tl_files/somekram/Instancing.zip


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Okt 24, 2011 16:41 
Offline
DGL Member
Benutzeravatar

Registriert: Di Dez 27, 2005 12:44
Beiträge: 393
Wohnort: Berlin
Programmiersprache: Java, C++, Groovy
Hast du es schon mal mit entfernungsabhängigem Level of Detail probiert? Dabei zeichnet man nähere Objekte mit mehr und weiter entfernte mit weniger Dreiecken. Wenn man die Dreiecksanzahl für jede Detailstufe optimiert, müsste die Gesamtanzahl an Dreiecken runtergehen (ganz weit entfernte Kugeln würden dann nur noch als Punkte gezeichnet werden). Vielleicht lassen sich Kugeln mit irgendeinem Trick auch mit einem Geometry-Shader erzeugen :?:

_________________
Wenn Gauß heute lebte, wäre er ein Hacker.
Peter Sarnak, Professor an der Princeton University


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Okt 24, 2011 17:22 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
Daher eine Frage, wie kann man eine halbweg gutaussehende Kugel Rendern mit wenigen Dreiecken.

Lass dir z.B. mit Blender eine Kugel erzeugen und lade diese als Mesh (Add -> Mesh -> Icosphere)

Level of Detail ist schwierig, weil die Idee von Instancing ja ist das alles gleich ist.

Culling könnte man aber im Geometry-Shader mit Transform-Feedback implementieren. D.h. du jagst deine Partikel-Positionen durch den Geometry-Shader, d.h. deinen TBO als VBO mit GL_POINT interpretieren. Sichtbare Punkte werden dann via Transform-Feedback in einen neuen Buffer (TBO) geschrieben. Der Fragmentshader kann hier abgeschaltet werden. Das eigentliche Rendern passiert dann in einem zweiten Pass ganz normal, nur eben mit dem neuen TBO.

Die Kugeln im Geometryshader zu erzeugen ist weniger sinnvoll, da man hier nur wenige Vertices schreiben darf. Der Tesselierungs-Shader bringt hier wohl schon mehr, da geht wahrscheinlich auch Level-of-Detail. Ist aber Shader-Modell 5.0, habe ich noch nicht benutzt.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 13 Beiträge ] 
Foren-Übersicht » Programmierung » OpenGL


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 18 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.010s | 15 Queries | GZIP : On ]