OpenGL - Einfacher Blur Effekt

thekiller

Viceinator
Einen sonnigen Sonntag =)

also ich würde gerne einen Blur Effect in meine Engine einbauen für Menüelemente oder fürs HUD etc.
Ich habe mir das in etwa so gedacht (hier für einen einfachen Menübutton).

1. Frame ganz normal rendern
2. Den zu blurenden Bildausschnitt in einen anderen Buffer kopieren
3. Bildausschnitt blurren
4. Bildausschnitt zurück in Colorbuffer schreiben/überschreiben
5. Button mit Blending drüberzeichnen

Ist das schon in etwa der Richtige Weg?

MfG Manuel
 
Hallo

Blur Effekte werden in der Regel im Rahmen eines Postprocessing Frameworks umgesetzt. Du speicherst dir zum Beispiel die Transformationsmatrizen des letzten Frames und berechnest für jeden Vertex die Geschwindigkeit mit der Transformation des aktuellen Frames. Daraus entsteht ein Geschwindigkeitsbuffer den du dann Sampeln kannst und daraus dann sogleich auch den entsprechenden Blurfaktor berechnen.

Um noch Artefakte zu vermeiden kannst du den Geschwindigkeitsbuffer des letzten Frames noch in Betracht ziehen und dann daraus interpolieren.

/Edit:
Ein Ansatz, der weniger genau ist dafür schneller implementiert ist ist dass du die ganze Szene 2 Mal zeichnest. Einmal in ein externes Rendertarget das du dann im zweiten Durchgang sampeln kannst. Du nimmst aus der Umgebung Farben aus der alten Szene und interpolierst, dann erhälst du auch einen einfachen Blureffekt. Dieses zweite Rendertarget kannst du dann beispielsweise mit der halben Grösse belegen da die Genauigkeit bzw. Verpixelung beim Blureffekt nicht oberste Priorität hat. Ist da halt dann auch mal wieder abwägen zwischen Performance und Genauigkeit.

Gruss
Muepe
 
Zuletzt bearbeitet:
Das bei dir klingt aber irgendwie nach Motion Blur. Dass will ich aber gar nicht. Einfach nur einen Unschärfeeffekt eines bestimmten Bildausschnittes.

EDIT.: Sozusagen ne Gaußsche Unschärfe.
 
Zuletzt bearbeitet:
Hallo

Ja, da empfehle ich dir den zweiten Ansatz:
1. Renderdurchgang rendert die Szene auf eine Textur
2. Textur wird auf die Graphikkarte als Resource gebunden.
3. Zweiter Renderdurchgang verwendet die Textur zum sampeln der Umgebung
4. Für jedes Pixel wird dann die Umgebung gesampelt und der Durchschnitt genommen.

-> Nette Unschärfe ;)
 
Ah ok, dann hab ich dich erst falsch verstanden^^
Aber warum ein 2. mal rendern? Und was genau meinst du mit "samplen der Umgebung"? Die umgebenden Pixel?
Achja ich habe noch keine Erfahrung mit Shadern also würde ich das ganzer ERSTMAL über CPU machen wollen, es seidenn mit Shadern ist die Umsetzung nicht all zu komplex.
 
Hallo Manuel,

Muepe hat das so gemeint, dass du beim zweiten Rendervorgang nur ein Rechteck (an die richtige Stelle im Viewport) zeichnest, welches mit der Textur versehen ist, in welche du in Schritt 1 gerendert hast.

Das Blurring auf der CPU zu machen ist sicher möglich. Ist nur wahrscheinlich nicht allzu schnell, weil du ständig Daten zwischen Grafikkarten- und Hauptspeicher kopieren musst.

Grüße,
Matthias
 
So, jetzt hab ich etwas mehr Zeit zum erklären :). Ein Unschärfeeffekt versucht ja eben Schärfe zu vermeiden. Eine Möglichkeit dies zu tun ist dass du für alle Pixel die Farbe ihrer anliegenden Pixel nimmst und dann zusammen mit der eigenen Farbe einen Durchschnitt errechnest. Dadurch werden die Farben der einzelnen Pixel näher zusammen rücken und Kanten verschwimmen während eher gleichfarbige Teile davon nicht betroffen sind und du so einen Unschärfeeffekt bekommst.

Da du aber auf der Graphikkarte in der Regel ja die umliegenden Pixel noch nicht kennst (oder sie sogar gar noch nicht berechnet wurden) kannst du sie noch nicht verwenden um die Kontraste zu minimieren. Daher renderst du die Szene zwei Mal. Beim ersten renderst du sie auf einen Textur die nicht angezeigt wird. Dadurch hast du die ganze Szene als Textur und übergibst sie an den Shader, der die finale Szene erzeugt. Anschliessend berechnest du im finalen Rendergang für jedes gerenderte Pixel seine Texturkoordinate auf der vorher berechneten Szenentextur (float2(pixel.x / Bildschirmbreite, pixel.y / Bildschirmhöhe)) und nimmst dann jeweils zum Beispiel die 8 umliegenden Koordinaten noch dazu und errechnest einen Durchschnitt. Das ist dann der Output des Pixelshaders.

Allgemein würde ich solche Sachen nicht auf der CPU machen. Du hast es da praktisch nur mit Flops zu tun und da schlagen selbst miese Graphikkarten extreme High-End CPUs um Längen. Berechnest du das auf der CPU hast du viel Frustration für nichts.
 
Okay also ist das Einarbeiten in Shader an dem Punkt auf jedenfall Sinnvoll. Hoffe, dass das nicht allzu Umfangreich ist. Ich will ja vorankommen und mich nich Tagelang mit einer Sache beschäftigen die noch gar nicht sooo wichtig ist.

Vielen Dank für die Hilfe!

MfG Manuel
 
Shader sind ein absoluter Segen! Damit erleichtert sich so vieles und es geht plötzlich alles so schnell (Auch wenn es manchmal Stolpersteine gibt). Zum Beispiel einen dynamischen Himmel zeichnen, dessen Färbung sich je nach Winkel verändert. Geht äusserst simpel. Ich rendere eine Kugel und habe folgenden Pixelshader (HLSL von DirectX):
C:
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
	float3 diff = input.PosOld;
	float viewDist = 400.0f; // TODO: replace by variable that holds dynamic view distance
    
	float coordTmp = diff.y / viewDist;
	float coord = (coordTmp + 1) / 2.0f;
    
	return tex1D(ColorSampler, coord);
}

ColorSampler ist dabei eine dynamisch erzeugte 1x180 Textur welche einen Gradient für jedes Grad der Neigung die entsprechende Blaufärbung in dem Pixel enthält.

Die sieht zum Beispiel dann so aus
attachment.php


Und das Ergebnis siehst du unten.
 

Anhänge

  • SkyTexture.jpg
    SkyTexture.jpg
    377 Bytes · Aufrufe: 516
  • Screenshot_23-15-24.png
    Screenshot_23-15-24.png
    484,3 KB · Aufrufe: 58
Zurück