Tutorials - Bloom

Sprachenübersicht/Programmierung/C / C++/ C#/Spieleprogrammierung/Grafik/Effekte

Bloom

Diese Seite wurde 10175 mal aufgerufen.

Dieser Artikel wurde in einem Wikiweb System geschrieben, das heißt, Sie können die Artikel jederzeit editieren, wenn Sie einen Fehler gefunden haben, oder etwas hinzufügen wollen.

Editieren Versionen Linkpartnerschaft Bottom Printversion

Keywords: Bloom, Lichtquelle, Effekt, Grafik

Inhaltsverzeichnis



Was ist Bloom? Top



Unter Bloom versteht man meist den Effekt den übermässig helles Licht bei unserem Auge erzeugt.

Um diesen Effekt nachvollziehen zu können sollte man für 1 Minute seine Augen verdecken und dann in eine helle Lichtquelle schauen. Man wird bemerken dass das gesamte Blickfeld ziemlich hell erscheint und sich die Helligkeit über das gesamte Blickfeld verteilt. Man wird vom Licht geblendet.

Genau diesen Effekt möchte man mit Bloom simulieren.

Was soll dieses Script zeigen? Top



Dieses Script soll zeigen wie man den Bloomeffekt schnell und effektiv bei seinen Anwendungen einfügen kann, dabei wird nicht auf HDR Texturen eingegangen.

Die meisten Codeschnippsel werden Pseudocode enthalten der sich stark an C anschmiegt.

Die meiste Zeit wird sich dieses Script um die Renderloop kümmern, da dort der interessanteste Aspekt dieses Effektes statt findet.

Eine typische Renderloop: Top



- Renderbuffer löschen (ZBuffer, StencilBuffer, ...)
- SkyBox rendern
- Meshobjekte rendern
- UIElemente rendern

Da sich der Bloomeffekt nicht auf die UIElemente auswirken sollte findet die Berechnung und das Rendern genau davor statt:

- Renderbuffer löschen (ZBuffer, StencilBuffer, ...)
- SkyBox rendern
- Meshobjekte rendern
- berechne BloomTextur
- rendere ScreenMask mit BloomTextur
- UIElemente rendern

Das Rendern der Screenmask sollte dabei das einfachste sein:

Code:


// initialisieren (OnCreate)
// ScreenMask erstellen die den ganzen Bildschirm einnimmt
screenMask = ErstelleQuad(-1.0, -1.0, 1.0, 1.0);
// Die ScreenMask soll dabei schon transformierte Vertexe besitzen
screenMask->SetTransformed(true);
// den Blendmodus für das Quad einstellen (Additive)
screenMask->SetBlend(One, One);
...
// vorbereiten und rendern(OnRender)
// Unsere ScreenMask soll dabei die BloomTextur enthalten
screenMask->SetBaseTexture(BloomTextur);
// Nun die ScreenMask rendern
screenMask->Draw();



Das berechnen der BloomTextur: Top



Hier kommt der Hauptteil des ganzen Effektes, wobei die Verwendung von Fragment/Pixelshadern empfohlen wird.

Code:


// initialisieren (OnCreate)
// Texturen erstellen
// geringere Aufloesungen der beiden texturen kann den Bloomeffekt verstärken
// aber es koennte auch zu Grafikartefakten kommen
BloomTextur = ErstelleTextur(256, 256);
TempTextur = ErstelleTextur(256, 256);
currentScreen = ErstelleTextur(FensterBreite, FensterHoehe, FensterBitsPerPixel);
// ScreenMask erstellen die den ganzen Bildschirm einnimmt
bloomMask = ErstelleQuad(-1.0, -1.0, 1.0, 1.0);
// Die ScreenMask soll dabei schon transformierte Vertexe besitzen
bloomMask->SetTransformed(true);
...
// beim berechnen der BloomTextur
// Die ScreenMask soll unseren aktuellen FrameBuffer als Textur benutzen
// dazu kopieren wir zuerst diesen in eine dafür vorgesehene Textur
CopyFrameBuffer(currentScreen);
// Nun können wir die Textur verwenden
bloomMask->SetBaseTexture(currentScreen);
// Blur Filter der ScreenMask zuweisen damit unser ergebnis anständig aussieht
bloomMask->SetShader("HorizontalerBlurFilter");
// ab jetzt können wir endlich damit beginnen zu rendern, insgesammt wird 3 mal gerendert
RenderToTexture(BloomTextur);
// den nächsten Shader
bloomMask->SetShader("VertikalerBlurFilter");
// die neue Textur
bloomMask->SetBaseTexture(BloomTextur);
// wieder rendern, diesmal auf eine andere Textur weil ansonsten Fehler auftreten könnten
RenderToTexture(TempTextur);
// Nun wird der eigentliche BloomShader zugewiesen
// dies könnte man auch in einen der anderen Shader zuweisen, aber um den Vorgang
// etwas zu verdeutlichen zeige ich das hier so.
bloomMask->SetShader("BloomShader");
// die neue Textur
bloomMask->SetBaseTexture(TempTextur);
// nun der letzte Rendervorgang
RenderToTexture(BloomTextur);



Der RenderToTexture Befehl verwendet dabei eine eigene RenderLoop, da es dabei aber zu Problemen mit dem aktuellen RenderBuffern kommen kann, sollte evtl. überlegt werden ob es nötig ist das berechnen ausserhalb der aktuellen Renderloop zu legen.

RenderToTexture Renderloop: Top



- Buffer löschen (Texturebuffer, ZBuffer,...)
- bloomMask rendern


Die verbesserte RenderLoop die Bufferfehler vermeidet: Top



- berechne BloomTextur
- Renderbuffer löschen (ZBuffer, StencilBuffer, ...)
- SkyBox rendern
- Meshobjekte rendern
- aktuellen Framebuffer in die dazugehörige Textur kopieren
- rendere ScreenMask mit BloomTextur
- UIElemente rendern

Ideen für den BloomShader: Top



- glühende Objekte mit Z-Write: Equal additiv mit der Glowfarbe über die Szene erneut rendern
- per Programm übergebenen Kontrast auf das Bild anwenden
- per Programm übergebene Helligkeit auf das Bild anwenden
- das Ergebniss Additiv (One, One) blenden

Beispielshadercode (GLSL): Top



Vertikaler Blur:

Code:


uniform sampler2D texture0_2D;
uniform float ddx;
uniform float ddy;

void main(void)
{
  //Initialisierungen
  vec4 outp = vec4(0.0, 0.0, 0.0, 0.0);

  // Texturen auslesen
  // und vertikal bluren (gauss)
  outp += 0.015625 * texture2D(texture0_2D, gl_TexCoord[0].xy + vec2(ddx*-3.0, 0.0) );
  outp += 0.09375 * texture2D(texture0_2D, gl_TexCoord[0].xy + vec2(ddx*-2.0, 0.0) );
  outp += 0.234375 * texture2D(texture0_2D, gl_TexCoord[0].xy + vec2(ddx*-1.0, 0.0) );
  outp += 0.3125 * texture2D(texture0_2D, gl_TexCoord[0].xy + vec2(0.0, 0.0) );
  outp += 0.234375 * texture2D(texture0_2D, gl_TexCoord[0].xy + vec2(ddx*1.0, 0.0) );
  outp += 0.09375 * texture2D(texture0_2D, gl_TexCoord[0].xy + vec2(ddx*2.0, 0.0) );
  outp += 0.015625 * texture2D(texture0_2D, gl_TexCoord[0].xy + vec2(ddx*3.0, 0.0) );

  gl_FragColor =  outp;
 }




Horizontaler Blur:

Code:


uniform sampler2D texture0_2D;
uniform float ddx;
uniform float ddy;

void main(void)
{
  //Initialisierungen
  vec4 outp = vec4(0.0, 0.0, 0.0, 0.0);
 
  // Texturen auslesen
  // und horizontal bluren (gauss)
  outp += 0.015625 * texture2D(texture0_2D, gl_TexCoord[0].xy + vec2(0.0, ddy*-3.0) );
  outp += 0.09375 * texture2D(texture0_2D, gl_TexCoord[0].xy + vec2(0.0, ddy*-2.0) );
  outp += 0.234375 * texture2D(texture0_2D, gl_TexCoord[0].xy + vec2(0.0, ddy*-1.0) );
  outp += 0.3125 * texture2D(texture0_2D, gl_TexCoord[0].xy + vec2(0.0, 0.0) );
  outp += 0.234375 * texture2D(texture0_2D, gl_TexCoord[0].xy + vec2(0.0, ddy*1.0) );
  outp += 0.09375 * texture2D(texture0_2D, gl_TexCoord[0].xy + vec2(0.0, ddy*2.0) );
  outp += 0.015625 * texture2D(texture0_2D, gl_TexCoord[0].xy + vec2(0.0, ddy*3.0) );

  gl_FragColor =  outp;
 }



Bloom:

Code:


uniform sampler2D texture0_2D;
uniform vec4 Contrast;
uniform vec4 Brightness;

vec4 saturate(vec4 inp)
{
  return clamp(inp, 0.0, 1.0);
}

void main(void)
{
  //Initialisierungen
  vec4 outp = vec4(0.0, 0.0, 0.0, 0.0);

  // Texturen auslesen
  outp = texture2D(texture0_2D, gl_TexCoord[0].xy );

  //Kontrast
  vec4 c = vec4(2.0,2.0,2.0,1.0) * (vec4(1.0,1.0,1.0,1.0) - Contrast);
  outp = saturate((outp - vec4(0.5,0.5,0.5,0.5)) * c + vec4(0.5,0.5,0.5,0.5));

  //Farben pushen
  outp *= Brightness;

  //Helligkeit
  vec4 b = (vec4(1.0,1.0,1.0,1.0) - Contrast * vec4(2.0,2.0,2.0,1.0));
  outp = saturate(outp + b);

  gl_FragColor =  outp;
 }



Schlusswort Top



Fragen, Kritik und andere Dinge an FallenAngel84[]at[]web.de

Mark Leutloff, Creative coder, Silent Dreams

Gibt es noch irgendwelche Fragen, oder wollen Sie über den Artikel diskutieren?

Editieren Versionen Linkpartnerschaft Top Printversion

Haben Sie einen Fehler gefunden? Dann klicken Sie doch auf Editieren, und beheben den Fehler, keine Angst, Sie können nichts zerstören, das Tutorial kann wiederhergestellt werden

Sprachenübersicht/Programmierung/C / C++/ C#/Spieleprogrammierung/Grafik/Effekte/Bloom