let’s dev

Blog

Top!

let’s dev | Scroll to top
let’s dev | Scroll to next content item

Hello

let’s dev | Scroll to previous content item
let’s dev Blog | Blur-Effekte unter iOS 7
by Katja
24. April 2014

Blur-Effekte unter iOS 7

Mit der Einführung von iOS 7 kam durch den Einsatz von geblurrten Menus auch in der Entwicklergemeinde ein gesteigertes Interesse am Thema Blur auf.

Möchte man als Entwickler seine eigene App an das neue Look & Feel anpassen ist der Einsatz des Blur-Effekts unumgänglich. In einfachen statischen Szenarien kann das geblurrte Menu mit Hilfe der von Apple gelieferten Core Image Bibliothek und deren Filter implementiert werden [1].

Blur-Effekt vs. normale Darstellung

Abbildung 1: Blur-Effekt vs. normale Darstellung

Werden dynamische oder gar dreidimensionale Inhalte verwendet stößt man allerdings schnell an die Grenzen der Bibliothek. Muss der Blur zur Laufzeit berechnet werden, sorgt dies für unzumutbare Wartezeiten für den Benutzer.

Eine effizientere Möglichkeit zur Berechnung ist die Verwendung der Graphikhardware mittels OpenGL ES in dem von Apple zur Verfügung gestellten GLKViewController aus dem GLKit Framework [2]. Bevor wir hierauf näher eingehen, soll zunächst das Konzept des Blur-Effekts erläutert werden.

Der Blur-Effekt, besser bekannt als Weichzeichner, durchläuft alle Pixel eines Bildes und berechnet den neuen Farbwert unter Berücksichtigung der benachbarten Pixel. Dazu wird eine Filtermatrix verwendet die festlegt mit welcher Gewichtung benachbarte Pixel in den resultierenden Farbwert einfließen. Einer der bekanntesten Filter dieser Art ist wohl der Gaußfilter, dessen Matrix wie folgt definiert ist:

Mathematische Formel zur Berechnung des Gaußfilters

Abbildung 2: Mathematische Formel zur Berechnung des Gaußfilters

Detailliertere Informationen über die Funktionsweise und die mathematischen Hintergründe des Gaußfilters sind in den nachfolgenden Referenzen [3] oder [4] zu finden.

Abgesehen von der verwendeten Filterart spielt auch der Radius des Filters eine Rolle. Je höher die Anzahl der einbezogenen Pixel gewählt wird, desto stärker wird das Bild weichgezeichnet. Gleichzeitig steigt jedoch auch der Aufwand für die Berechnung erheblich an. Mit steigendem Filterradius nimmt die Anzahl der zu betrachtenden Pixel quadratisch zu.

Da Pixelzugriffe den größten Teil der Rechenzeit ausmachen und gerade im mobilen Bereich die Ressourcen sehr begrenzt sind, ist es empfehlenswert die Anzahl der Zugriffe so gering wie möglich zu halten. Durch die Separierbarkeit des Gauß-Filters ist es möglich, die Filterung auf ein 2D-Bild in zwei 1-dimensionale Filterungen aufzuteilen. Somit wird das Bild einmal vertikal und einmal horizontal gefiltert. Dies verringert die Anzahl der Zugriffe im Falle eines 9×9 Filters von 81 auf 18. Das folgende Bild verdeutlicht die Anwendung dieses Konzepts:

Blur horizontal

Abbildung 3: Blur horizontal

Blur vertikal

Abbildung 4: Blur vertikal

Blur Resultat

Abbildung 5: Ergebnis

Die Realisierung des beschriebenen Konzepts in OpenGL ES erfolgt über Pixel Berechnungen im Fragment Shader. Dazu wird der gewünschte Bildbereich zunächst mit Hilfe eines Framebuffer Objects in eine Textur gerendert. Auf diese Textur wird anschließend die Filteroperation im Shader angewandt.

Um das Konzept des separierten Filters anzuwenden ist es notwendig 2 Framebuffer zu verwenden. Aus dem einem Buffer wird das ungeblurte Bild gelesen und in den zweiten wird das resultierende Bild gespeichert. Nach dem Durchlauf des horizontalen Blurs werden die Buffer vertauscht und der vertikale Blur durchlaufen.

Eine mögliche Realisierung eines solchen Shaders nach Vorlage von [5] ist in dem nachfolgenden Code Snippet zu sehen.

uniform sampler2D image;
                uniform highp float blurSize;

                void main(void) {
                   highp float offset[3];
                   offset[0] = 0.0;
                   offset[1] = 1.3846153846;
                   offset[2] = 3.2307692308;
                   highp float weight[3];
                   weight[0] = 0.2270270270;
                   weight[1] = 0.3162162162;
                   weight[2] = 0.0702702703;

                   gl_FragColor = texture2D( image, vec2(gl_FragCoord) / blurSize) * weight[0];

                   for (int i=1; i<3; i++) {
                      gl_FragColor += texture2D( image, ( vec2(gl_FragCoord)+vec2(offset[i], 0.0) ) / blurSize) * weight[i];
                      gl_FragColor += texture2D( image, ( vec2(gl_FragCoord)-vec2(offset[i], 0.0) ) / blurSize) * weight[i];
                   }
                }
}       

Entspricht das resultierende Bild nicht der gewünschten Blur-Intensität, kann dieser Vorgang beliebig oft wiederholt werden. Anschließend steht das fertig Bild mit Blur-Effekt als Textur zur Verfügung und kann zur Zeichnung der GUI-Elemente verwendet werden. Erfahrungsgemäß sind je nach Größe des geblurrten Bildbereichs unter OpenGL ES 2.0 auf dem iPad 3 schon bis zu fünf Wiederholungen möglich.

Treten trotz der separierten Filter Performance-Probleme auf ist es möglich die Framebuffer in einer niedrigeren Auflösung zu speichern, da die Bilder nach Anwendung des Filters nur noch niederfrequente Bildanteile besitzen.

In einfachen Fällen ist es möglich die benötigten Texturen bereits geblurrt zu hinterlegen und zur Darstellung der GUI-Elemente zu verwenden. Um eine vorgeblurrte Textur zu erstellen, genügt es mit Hilfe aktueller Bildbearbeitungssoftware einen entsprechenden Filter über das Bild zu legen, und das Bild in gefiltertem Zustand abzuspeichern. Steht genügend Speicher zur Verfügung ist die Vorberechnung zu empfehlen.

Im konkreten Einzelfall muss die Wahl der Methode in Abhängigkeit bestimmter Faktoren – der Komplexität des Szenarios und der Verfügbarkeit der Rechenleistung und des Speichers – erfolgen. Eine abschließende allgemein gültige Empfehlung kann also nicht gegeben werden.

Bildnachweis Abbildung 3-5:

  • ATI Technologies Inc.

Weitere Artikel aus unserem Blog