Motion-Blur

Aus DGL Wiki
Wechseln zu: Navigation, Suche

Motion Blur ist üblicherweise kein Effekt, den man macht weil er schön ist, sondern ein Effekt, der bei der Übertragung von digitalen Bildern zum menschlichen Auge eine Art Vermittlungsrolle spielt.

Biologische Grundlagen

Info DGL.png Mehr zu den biologischen Grundlagen und warum Motion-Blur trotzdem nicht die endgültige Lösung ist (und sogar zum Problem werden kann), erfahrt ihr im Artikel Framerate.

Das menschliche Auge nimmt etwa 25 Bilder je Sekunde wahr. Im Unterschied zur Computergrafik sind dies jedoch keine Momentaufnahmen sondern eine Art Aufsummierung aller Lichtreize, die während dieser 1/25 Sekunde entstanden sind.

Ein leuchtender Punkt

Eine verwischte kreisförmige Lichquelle auf schwarzem Hintergrund.

Nehmen wir als Beispiel einen schwarzen Hintergrund. Über diesen schwarzen Hintergrund wandert (verhältnismäßig schnell) ein Licht. In der Computergrafik, wenn wir beispielsweise 60 Frames pro Sekunde darstellen können, würden wir 60 Momentaufnahmen darstellen, wobei in diesen Momentaufnahmen die Bewegung des Lichtpunktes keine Rolle spielen würde. Das menschliche Auge hingegen erhält nicht 25 Momentaufnahmen, sondern eine analoge Darstellung des Lichtsignales. Dieses analoge Lichtsignal wird nun (wie bereits erwähnt) während der gesamten 1/25 Sekunde aufsummiert und als solches an das Gehirn übertragen. Somit sehen wir nicht einzelne Momentaufnahmen des Lichtes sondern den gesamten Weg, den das Licht zurückgelegt hat.

Wenn wir die Tatsache annehmen, dass wir nur 25 Bilder je Sekunde sehen, so können wir dies durch ein sehr einfaches Experiment nachvollziehen:

Begebt euch in einen möglichst dunklen Raum und vollführt mit einem Licht (z.B. Feuerzeug) verhältnismäßig schnelle Bewegungen. Ihr könnt nun den gesamten Weg sehen, den die Lichtquelle zurückgelegt hat.

Technische Umsetzung

Filme

Wenn ihr euch einen Film anseht, so scheinen die Bewegungen üblicherweise realer als in einem Computerspiel. Wenn ihr euch ein Standbild eines Filmes anseht, so wird klar, weshalb dies der Fall ist. Der Film besitzt üblicherweise zwar nur 25 Bilder je Sekunde, jedoch besitzen diese Bilder (gleich zum menschlichen Auge) die aufsummierte Helligkeit der 1/25 Sekunde, was in einem Standbild durch Streifen sichtbar wird. Diese Streifen kann man nun als Idealfall von Motion Blur ansehen.

Computergrafik

In der Computergrafik stellt man üblicherweise Standbilder dar. Es wäre enorm aufwändig, die Berechnungen durchzuführen, welche Farbe und welche Helligkeit ein Pixel haben würde, wenn er die letzte 1/25 Sekunde darstellen würde und nicht nur eine Momentaufnahme. Glücklicherweise ist der Mensch nicht ganz so wählerisch und begnügt sich auch mit etwas besseren Darstellungen seiner Wirklichkeit, somit ist es um einiges besser, wenn man beispielsweise 60 Momentaufnahmen je Sekunde besitzt als wenn man nur 25 Momentaufnahmen besitzt.

Motion Blur in der Praxis

Motion Blur ist also ein Effekt, der das menschliche Auge möglichst zufriedenstellen soll. Bei verhältnismäßig langsamen Geschwindigkeiten (oder aber bei sehr hoher Framerate) hat Motion Blur kaum bis keine Auswirkungen. Erst bei höheren Geschwindigkeiten kann Motion Blur sinnvoll eingesetzt werden. Hier geht es jedoch teilweise nicht nur darum, allein das Standbild durch grafische Effekte zu verbessern, sondern im Idealfall geht es darum, für jedes Pixel die vergangene 1/25 Sekunde zu beachten.

In Filmen sehen wir Motion Blur dann, wenn enorm hohe Geschwindigkeiten dargestellt werden sollen (annähernd Lichtgeschwindigkeit in Science Fiction Filmen). Obwohl ich weder ein Physiker noch ein Biologe bin, kann ich guten Gewissens behaupten, dass wir ein Raumschiff welches mit (annähernd) Lichtgeschwindigkeit an uns vorbei fliegt wohl so gut wie gar nicht sehen würden, da es nur einen sehr sehr kleinen Bruchteil einer 1/25 Sekunde sichtbar wäre ... einzige Ausnahme wäre natürlich, wenn es enorm hell wäre, wodurch dieser sehr kleine Bruchteil viel bei der Aufsummierung der 1/25 Sekunde ausmachen könnte.

In der Computergrafik bezieht sich Motion Blur üblicherweise ausschließlich auf Momentaufnahmen, wo die aktuelle Geschwindigkeit beachtet wird, oder aber die vorangegangenen Frames ebenfalls einen Einfluss besitzen.

Realisierung in OpenGL

Standardmässig wurde Motion Blur in OpenGL mit dem Akkumulationspuffer realisiert, der jedoch nicht sehr schnell ist. Eine schnellere Methode arbeitet mit einer Bildschirmtextur und funktioniert folgendermassen :

  1. (Bildschirm-)Textur erzeugen [winwidth x winheight] und initialisieren.
  2. Bildschirm und Tiefenpuffer löschen
  3. Szene rendern
  4. Textur ( im Orthomodus ) geblendet auf die Szene zeichnen ( mit Alphawert von z.B. 0.98, abhängig von Framerate, nicht in Depth-Buffer schreiben )
  5. glCopyTexSubImage2D und weiter bei Schritt 2.

Beispielcode ( C )

void initMotionBlur()
{
    //Textur in Bildschirmgrösse
    int texSize = WINWIDTH * WINHEIGHT * 3;
    float* motionTex = new float[texSize];

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 
    glGenTextures( 1, &theMotionTex );
    glBindTexture( GL_TEXTURE_2D, theMotionTex );
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WINWIDTH, WINHEIGHT, 0, GL_RGB, GL_FLOAT, motionTex);
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );   
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );  
    
    //Modulate-Modus, um Textur mit glColor zu mischen
    glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );

    delete [] motionTex;
}

...

void display()
{
   ...
   //Szene rendern

   beginMotionBlur();
   endMotionBlur();
   ...
}

void beginMotionBlur()
{
    glEnable( GL_TEXTURE_2D );
    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
	 
    glDepthMask( false );
	 
    //Motion-Faktor als Alpha-Faktor übergeben, Wert abhängig von Framerate ( z.B. 0.98 )
    glColor4d( 1.0f, 1.0f, 1.0f, decay );
	    
    //Motion-Textur über Szene blenden
    glBindTexture( GL_TEXTURE_2D, theMotionTex );
    screenQuad( winwidth, winheight );	
	 
    glDepthMask( true );
	    
    glDisable( GL_BLEND );
    glDisable( GL_TEXTURE_2D );
}

void endMotionBlur()
{
    //Bildschirm zurück in Textur kopieren
    glEnable( GL_TEXTURE_2D );
    glBindTexture( GL_TEXTURE_2D, theMotionTex );
    glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, WINWIDTH, WINHEIGHT);
    glDisable( GL_TEXTURE_2D );
}

void screenQuad()
{
    beginInfoScreen( WINWIDTH, WINHEIGHT );
        glBegin(GL_QUADS);
            glTexCoord2i( 0, 0 );
            glVertex2i( 0, 0 );
            glTexCoord2i( 1, 0 );
            glVertex2i( WINWIDTH, 0 );
            glTexCoord2i( 1, 1 );
            glVertex2i( WINWIDTH, WINHEIGHT );
            glTexCoord2i( 0, 1 );
            glVertex2i( 0, WINHEIGHT );
        glEnd();
    endInfoScreen();
}

void beginInfoScreen( int winwidth, int winheight )
{
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    gluOrtho2D(0, winwidth, 0, winheight);
                
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();
}

void endInfoScreen()
{
    glPopMatrix();
   
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
   
    glMatrixMode(GL_MODELVIEW); 
}
...
Szene mit aktiviertem Motion-Blur.

Demo

Demo (mit Quellen)