Shader 101: Umgebungslicht / Ambient Light

Am Anfang war das Licht… So steht es zwar nicht im erfolgreichsten Buch aller Zeiten, aber zumindest in der Welt der 3D-Programmierung und der Shader ist dieser Satz sehr treffend.

Ohne Licht sehen wir nichts. Dies ist nicht nur im richtigen Leben so, sondern auch in der Spieleentwicklung. Aus diesem Grund möchte ich in diesem Artikel das einfachste Licht vorstellen, dass es gibt: Das Umgebungslicht oder auch Ambient Light. Dieses wird zwar auch vom BasicEffect des XNA-Frameworks bereitgestellt, ich möchte hier aber erklären, wie dies in einem eigenen Shader erzeugt wird.

Zuerst ein wenig graue Theorie, da es ja schon interessant sein dürfte, was überhaupt das Umgebungslicht ist. Das Umgebungslicht ist überall, gleichmäßig und hat keine Richtung. Es benötigt auch keine direkte Lichtquelle um zu entstehen. Im Grunde genommen sind es einfach nahezu unendlich viele Reflektionen von Lichtphotonen. Ich möchte euch hier jetzt nicht mit physikalischen Grundlagen langweilen, was ich auch nicht wirklich könnte, aber eine ausreichende und grundlegende Erklärung möchte ich geben, wie dieses Umgebungslicht entsteht. Alles, auch die kleinsten Teilchen in der Luft, können die Photonen aus denen das Licht besteht reflektieren. Einige Flächen mehr, andere weniger. Ein Spiegel oder eine Wasseroberfläche reflektiert besonders stark, ein flauschiger Stoff weniger stark. Flächen, die kein Licht reflektieren, sind unsichtbar, da wir nicht die Fläche selbst sehen, sondern nur das reflektierte Licht.

Diese Reflektion hört aber nicht nach der ersten Reflektion vollständig auf, sondern die Photonen ändern lediglich ihre Richtung und gehen unter bestimmten Umständen auch verloren. Wenn wir jetzt mal den Raum anschauen, den wir uns anschauen, können wir uns ja mal überlegen, wo und wie oft das Licht, dass von der Lampe kommt reflektiert wird (Einfallswinkel = Ausfallswinkel), bevor es unser Auge trifft. Dies kann ein direkter Strahl sein, aber auch der Strahl, der von der Wand reflektiert wird. Oder der Strahl, der erst auf die Wand trifft, dann auf den Tisch und dann erst unser Auge. Es gibt unzählige Kombinationen. Und genau dies ist das Umgebungslicht. Eine verdammt große Anzahl von Reflektionen aus allen möglichen Richtungen. Damit sind auch unsere Grundaussagen mehr oder weniger bestätigt:

- Umgebungslicht hat keine Richtung, da es aus vielen/allen Richtungen kommt
– Umgebungslicht braucht keine direkte Lichtquelle, da es “nur” Reflektionen sind
– Umgebungslicht ist gleichmäßig, da sich aus dem “Chaos der Reflektionen” eine gleichmäßige Verteilung ergibt

Diese Punkte machen es uns jedenfalls sehr, sehr einfach einen Shader zu entwickeln, der Umgebungslicht simuliert. Leider hat dies auch einen Haken: Es sieht nicht besonders schön aus, weil es einfach gleichmäßig die Szene in eine Farbe taucht.

Aus diesem Grund besteht es auch ganz einfach nur aus einer Lichtstärke und einer Lichtfarbe, die wir im folgenden durch die Shader-Parameter AmbientColor und AmbientIntensity definieren. Hier nun der Shader:

float4x4 World;
float4x4 View;
float4x4 Projection;

float4 AmbientColor		= float4(1, 1, 1, 1);
float  AmbientIntensity = 0.75;

struct VertexShaderInput
{
    float4 Position : POSITION0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);

    return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
    return ( AmbientColor * AmbientIntensity );
}

technique AmbientLight
{
    pass Pass1
    {
        // TODO: set renderstates here.

        VertexShader = compile vs_1_1 VertexShaderFunction();
        PixelShader = compile ps_1_1 PixelShaderFunction();
    }
}

Der Shader dürfte nicht weiter schwer zu verstehen sein. In Zeile 5 und 6 definieren wir die Parameter für die Lichtfarbe und -stärke, die wir dann im Pixel-Shader in Zeile 31 als Farbe für jeden Pixel verwenden. Da wir noch keine Texturen oder anderes Licht haben, ist dies das einzige Licht, das unsere Szene beleuchtet.

Der Aufruf aus XNA ist nicht sonderlich schwierig. Wir laden einfach den Effect über die ContentPipeline in eine Member-Variable und setzen die entsprechenden Parameter:

ambientEffect.Parameters["AmbientColor"].SetValue(Color.White.ToVector4());
ambienteEffect.Parameters["AmbientIntensity"].SetValue(0.3f);

ambientEffect.Begin();
ambientEffect.CurrentTechnique.Passes[0].Begin();

GraphicsDevice.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList, vertices, 0, vertices.Length / 3);

ambientEffect.CurrentTechnique.Passes[0].End();
ambientEffect.End();

In Zeile 1 und 2 werden die Parameter für das Ambient Light gesetzt und der Rest ist XNA-Standard zur Verwendung eines Effekts und zeichnen eines Vertex-Arrays. Das fertige Programm sieht dann wie folgt aus:

Dies ist nicht sonderlich spektakulär, aber trotzdem bietet diese Grundbeleuchtung bereits interessante Möglichkeiten. Wenn man die Intensität z.B. für Bruchteile von Sekunden auf einen größeren Wert ansteigen lässt, dann sieht es so aus, als würden Blitze eines Gewitters zucken. Lässt man diesen Wert von hoch nach niedrig laufen und interpoliert man die Lichtfarbe langsam zu einem rot, so sieht dies aus wie ein Sonnenuntergang. Die Möglichkeiten sind groß…

Eine Übersicht über alle Artikel der Reihe Shader 101 findet ihr im Einstiegsartikel: Shader 101: Grundlagen.

About these ads

Veröffentlicht am 25.04.2011 in Shader, XNA, XNA 3.1, XNA 4.0 und mit , , , , , getaggt. Setze ein Lesezeichen auf den Permalink. 4 Kommentare.

  1. sorry das ich wieder nerve, und danke dass du immer antwortest :D

    Wenn ich mit dem Shader jetzt die Farbe festlege, muss mein Vertex Format in XNA, dann
    schon eine Farbe haben?

  1. Pingback: Shader 101: Grundlagen « "Mit ohne Haare"

  2. Pingback: Shader 101: Diffuse / Directional Light « "Mit ohne Haare"

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ photo

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

Folgen

Erhalte jeden neuen Beitrag in deinen Posteingang.

Schließe dich 139 Followern an

%d Bloggern gefällt das: