Table of Contents
Anisotrope Reflexe für realistisches Haar mit GLSLDurch Unebenheiten mit einer bestimmten Vorzugsrichtung (gebürstetes Metall, Haare, Seide usw.) wird das Licht richtungsabhängig reflektiert. Für den theoretischen Hintergrund gibt es z.B. hier Unterlagen. Zuerst mal das Programm: und die Texturen dazu (das Verzeichnis auf “textures” umbenennen): Für jene, die das “mal eben” ausprobieren wollen, einfach auch die folgenden Python-Dateien ins gleiche Verzeichnis kopieren: Die Bibliothek "Pylget" muss natürlich auch installiert sein. Das Ergebnis sieht etwa so aus: (von links nach rechts: Blinn/Phong, Phong, Blinn/Phong auf Bumpmap) AnisotropieFür dieses Programm habe ich die relevanten lokalen Vektoren umbenannt:
Das folgende Bild ist aus der Arbeit Ashikhmin,Shirley: An Anisotropic BRDF Model (2000) entnommen, diese Arbeit sollte man sich jedenfalls angesehen haben. Die Vektoren E,L,H liegen in einer Ebene - im allgemeinen Fall liegt N nicht in dieser. Um meinen Anisotropie-Algorithmus zu erklären (ist der neu (August 2011) ? ich bin mir nicht sicher), führe ich noch einen Vektor ein:
Betrachten wir die grüne Ebene, die durch T und N aufgespannt ist. Wenn E,L (und daher auch H) in dieser Ebene liegen, ist die Reflektion am hellsten. Sie verschwindet, wenn die Vektoren orthogonal dazu liegen. Um das zu erreichen, projiziere ich (rote Linien) die Vektoren auf diese Ebene und führe die Glanzlicht-Berechnungen (Phong oder Blinn-Phong) mit diesen projizierten Vektoren E',L',H' (blau) durch. (Beachte, dass für Phong-Shading nur E' und L' benötigt werden, für Blinn-Phong-Shading nur H', dass also nur eine Projektion berechnet werden muss). Ok ? Also weiter zur Implementierung - um die beiden Shading-Algorithmen vergleichen zu können, habe ich die Taste 'M' (Model) eingeführt, um zwischen beiden umzuschalten. Anisotropie - CodingZur Erklärung des Quellcodes: wir erweitern das Beispiel 5, das sich mit “Parallax Mapping” beschäftigt hat. Zu Beginn wird der Hilfe-Text erweitert: I = Isotropic/Anisotropic Lighting M = Model (Phong/Blinn-Phong) Die Standard-Werte werden ganz unten im Programm gesetzt, wir beginnen mit “anisotropisch” und “Phong”-Shading. toggleaniso = True togglemodel = False # Phong Die “import” Statements habe ich etwas verändert, weil ich in der Zwischenzeit auf Pydev mit Eclipse als Entwicklungsumgebung umgestellt habe und dort werden unqualifizierte (“*”)-Importe ausführlich angemeckert: from math import pi, sin, cos, sqrt from euclid import Vector3 from pyglet import resource from pyglet.window import * #@UnusedWildImport from pyglet.gl import * #@UnusedWildImport from shader import Shader So zeige ich im Vorübergehen, wie man diese Pydev-Warnungen unterdrückt Übrigens - einige Leute haben die Frage gestellt, wo denn die Libraries sind, mit denen ich die ganze Zeit arbeite. Ich habe daher die relevanten py-Files hier nochmal angeführt, damit die Site-Dependencies klein bleiben: “Pyglet.py” sollte ordentlich installiert werden, sonst gibt's später Schwierigkeiten bei Upgrades. Weiter gehts: die beiden neuen Schalter können mit den Tasten 'I' und 'M' verändert werden und ihr aktueller Zustand wird an das Shader-Programm weitergereicht: shader.uniformi('toggleaniso', toggleaniso) shader.uniformi('togglemodel', togglemodel) Ich habe ein paar Zeilen für die Positionierung des Hilfe-Textes verändert, aber die sind nicht so besonders interessant. Das Wichtigste ist natürlich das Shader Programm für Anisotrope GlanzlichterWie beim vorigen Beispiel lese ich die Farbe jedes Pixels (nachdem ich im “Parallax-Shading”-Teil die Position berechnet habe) und die Normale aus den entsprechenden Texturen: vec4 texColor = vec4(texture2D(my_color_texture[0], newCoords).rgb, 1.0); vec3 norm = normalize( texture2D(my_color_texture[1], newCoords).rgb - 0.5); vec3 gloss = texture2D(my_color_texture[3], newCoords).rgb; // Glossmap: r=brightness, g=specular exp, b=strand-dirx Neu ist die “gloss”-Textur, dieses RGB-Bild liefert
Der (B)lue-Kanal ist folgendermassen codiert:
Beachte, dass die Farbwerte bei “jpg”-kodierten Texturen speziell an Kanten kräftig überschiessen können - daher habe ich einen Sicherheitsabstand vom “0”-Wert eingehalten. Zur Berechnung der “Phong”-Formel für das Glanzlicht verwende ich etwas wie specular = pow ( max(0.0, R.E), gloss.g * gloss.g * 128.0) wobei “R.E” das Innere Produkt von “R” (der Reflektierte Licht-Vektor) mit “E” der Augen-Vektor. Der Exponent ist 32 für einen “Grün”-Wert von 128 (das kommt von gloss.g = 0.5, so 0.5*0.5*128.0 = 32.0) und maximal 128. Im isotropen Fall ist die Phong Berechnung nicht allzu überraschend, aber der anisotrope Fall ist erstaunlicherweise genau das Gleiche: R•E for Phong N•H for Blinn-Phong Das liegt daran, dass die “Anisotropie” schon vor der “Phong” oder “Blinn/Phong” Berechnung erledigt wird, indem die Augen- und Licht-Vektoren manipuliert werden. Ich projiziere die beiden Vektoren in eine Ebene, die parallel zum Faserrichtung liegt. Dazu wird der Normalvektor auf diese Ebene berechnet: vec3 tplane = cross( N, vec3( straindir, 0.0 )); // normal vector of T-Plane E = normalize( E - dot(E, tplane) * tplane ); // project eye to texture plane Weil die Faserrichtung “straindir” in der Tangentenebene liegt, liegt auch dieser Orthogonalvektor in der Tangentenebene, wenn die Normale N nicht durch die Bumpmap verändert wird. Dann wird der “E”-Vektor und der “R”-Vektor in diese Ebene projiziert. Auf diese Weise erhält man eine Standard-“Phong”-Reflektion, wenn man entlang der Faserrichtung schaut. Wie man aus Wikipedia lernen kann, ist die Berechnung der “Blinn-Phong” Reflektion in einigen (häufigen) Spezialfällen deutlich einfacher. Insbesondere ist der Fall interessant, bei dem die Lichtquelle(n) und das Auge sehr weit von der Oberfläche entfernt sind - dann werden “L” und “E” konstant. “Blinn-Phong” scheint für viele Materialien die bessere Annäherung an die Wirklichkeit zu liefern als “Phong” (siehe Experimental Validation of Analytical BRDF Functions), daher habe ich mir das auch angesehen: Das nette Ergebnis ist, dass nur ein einziger Vektor (“H”) in die Faser-Ebene projiziert werden muss - also ist auch hier die Blinn-Phong-Berechnung einfacher, schneller und (meist) realistischer. Hier ein direkter Vergleich von Blinn/Phong (links) mit Phong (rechts) im isotropen Fall: Der Unterschied wird bei Streiflicht recht augenscheinlich. Im Quellcode sind einige Berechnungen redundant, damit beide Beleuchtungsmodelle jeweils isotrop und anisotrop demonstriert werden können. Diese Berechnungen können natürlich entfallen, wenn man sich für das eine oder andere Berechnungsmodell entschieden hat. Das war's.. Und jetzt zu etwas völlig anderem: Beispiel 8 - Environmental Bump Mapping mit GLSL Cube Mapping ! Schon das Beispiel 6 - Vertex Offset Shader für deformierbare Objekte gesehen ? Literatur: |