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
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 25 |
uniform sampler2D texture0; uniform float filtersize; uniform float width; uniform float height; void main() { int nfiltersize = int( filtersize ); float stepx = 1.0 / width; float stepy = 1.0 / height; vec3 colorsum = vec3( 0, 0, 0 ); unsigned int count = unsigned int( 0 ); for( int dx = -nfiltersize; dx <= nfiltersize; ++dx ) { for( int dy = -nfiltersize; dy <= nfiltersize; ++dy ) { vec2 offset = vec2( float( dx ) * stepx, float( dy ) * stepy ); vec2 coord = gl_TexCoord[0].st + offset; if( coord.x < 0.0 || coord.x > 1.0 || coord.y < 0.0 || coord.y > 1.0 ) continue; colorsum += vec3( texture2D( texture0, coord ) ); ++count; } } gl_FragColor = vec4( colorsum / float( count ), 1.0 ); } |
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 25 26 27 28 |
uniform sampler2D texture0; uniform float filtersize; uniform float width; uniform float height; void main() { int nfiltersize = int( filtersize ); float stepx = 1.0 / width; float stepy = 1.0 / height; vec3 colorsum = vec3( 0, 0, 0 ); unsigned int count = unsigned int( 0 ); // warum so viel gecaste, bleib doch einfach in float // dynamische Filtergröße verursacht Dynamic Branching, tödlich! Such dir eine feste Größe aus. for( int dx = -nfiltersize; dx <= nfiltersize; ++dx ) { for( int dy = -nfiltersize; dy <= nfiltersize; ++dy ) { vec2 offset = vec2( float( dx ) * stepx, float( dy ) * stepy ); vec2 coord = gl_TexCoord[0].st + offset; // Tödlich: Dynamic Branching ist DER Performance-Killer. Noch schlimmer: die Abfrage ist Quatsch, Textur-Clamping anschalten und weglassen, die GPU kann das im Bruchteil der Zeit! if( coord.x < 0.0 || coord.x > 1.0 || coord.y < 0.0 || coord.y > 1.0 ) continue; colorsum += vec3( texture2D( texture0, coord ) ); ++count; } } gl_FragColor = vec4( colorsum / float( count ), 1.0 ); } |
Zitat von »"the[V«
oid"]Wenn ich den folgenden Fragmentshader zwecks Bluring benutze, bricht meine FPS völlig ein:
[...]
Selbst wenn ich als nfiltersize nur die Werte 1 oder 2 verwende.
Zitat von »"the[V«
oid"]Nun meine Frage: Ist dieser Shader wirklich so leistungsfressend, oder muss ich den Fehler an anderer Stelle suchen?
Falls das erstere der Fall ist: Wie wird Bluring denn performanter implementiert?
Zitat von »"the[V«
oid"]Eine Frage habe ich da nur: Was genau ist jetzt Dynamic Branching? Und vorallem: Warum ist es tödlich?
Zitat von »"the[V«
oid"]Und: Was spricht dagegen, statt 2 Renderpasses mit unterschiedlicher Anwendung des Blur-Filters einen einzigen zu verwenden, wobei der Shader die Anwendung erst in die eine, dann in die anderen Richtung durchführt?
Zitat von »"the[V«
oid"]Eine Frage habe ich da nur: Was genau ist jetzt Dynamic Branching? Und vorallem: Warum ist es tödlich?
Zitat von »"the[V«
oid"]Und: Was spricht dagegen, statt 2 Renderpasses mit unterschiedlicher Anwendung des Blur-Filters einen einzigen zu verwenden, wobei der Shader die Anwendung erst in die eine, dann in die anderen Richtung durchführt?
Zitat von »"CodingCat"«
Als Dynamic Branching bezeichnet man verschiedene Code-Pfade (Branches), die durch zur Compile-Zeit nicht auflösbare Bedingungen in Abhängigkeit von irgendwelchen veränderlichen Shader-Konstanten oder gar Pixel-Werten ausgeführt werden. Die Stärke der GPU liegt darin, immer wieder dieselben Operationen parallel in Massen auszuführen. Eine Bedingung stört diese einheitliche Repetivität. Gezielt eingesetzt kann Dynamic Branching durchaus sinnvoll sein. Du hast aber gleich einen ganzen Haufen Bedingungen in deinem Code, die überflüssig sind, spätestens, wenn du dich zur Compile-Zeit auf eine fester Filtergröße festlegst.
C-/C++-Quelltext |
|
1 |
const float width = 800; |
Zitat von »"CodingCat"«
Der Witz dabei ist, dass du das bereits horizontale geblurte Bild auch noch vertikal blurst. Wenn du n Pixel horizontal und n vertikal zusammenrechnest, brauchst du in einem Pass für das Rechteck n*n Texturzugriffe. Rechnest du erst horizontal, dann vertikal n Pixel zusammen, brauchst du dagegen für dasselbe Rechteck nur 2n Zugriffe. Dies lässt sich nicht zu einem Pass zusammenfassen, da der zweite Blur-Pass ja die Ergebnisse des ersten benötigt.
Quellcode |
|
1 2 3 4 5 6 7 |
void main() { for( int i=0; i < N; ++i ) { // Texturzugriff! } } |
Quellcode |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void impl() { for( int i=0; i < N; ++i ) { // Texturzugriff! } } void main() { // setze Variablen impl(); // setze Variablen impl(); } |
Zitat von »"the[V«
oid"]Und das dann mit nur einem Renderpass. Das wären doch ebenso 2N Texturzugriffe, oder bin ich völlig blöde?! :?
Zitat von »"dot"«
Zitat von »"the[V«
oid"]Und das dann mit nur einem Renderpass. Das wären doch ebenso 2N Texturzugriffe, oder bin ich völlig blöde?! :?
Korrekt, 2N Zugriffe aber wenn dus ausprobierst wirst du sehen dass der Blur so nur in die letzte der beiden Richtungen gemacht wird. Der Witz an der Sache mit dem hintereinander ist ja dass der zweite Blur auf den schon in eine Richtung geblurten Daten arbeitet, dazu musst du das Zwischenergebnis aber in einer separaten Textur haben
C-/C++-Quelltext |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
vec3 impl() { vec3 color; for( int i=0; i < N; ++i ) { // Texturzugriff! } return color; } void main() { // setze Variablen vec3 color = impl(); // setze Variablen color += impl(); gl_FragColor = vec4( color / 2, 1.0 ); } |
Werbeanzeige