Filter in SVG/Licht und Schatten

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Du kannst HTML-Elementen sowohl mit der box-shadow-Eigenschaft als auch der drop-shadow()-Funktion des CSS-Filters einen Schatten geben, wobei diese zweite Möglichkeit auch für SVG-Elemente möglich ist.

In diesem Kapitel lernst du, wie du solche Filter aus mehreren primitiven Filtern selbst erzeugen. So werden feinere Abstimmungen möglich.

Erzeugen eines weiteren Objekts

Ein (Schlag)-Schatten ist ja ein mittels einer Lichtquelle erzeugtes Projektionsbild des im „Weg des Lichts stehenden“ Gegenstands. Deshalb wird in einem ersten Schritt unsere Grafik verdoppelt.

feOffset

Der primitive Filter feOffset verschiebt eine Grafik. Er verhält sich also ähnlich wie transform:translate(), nur eben innerhalb eines Filters. In der Praxis wird feOffset häufig in Zusammenhang mit anderen Filtern verwendet, um einen Schatten zu erzeugen.

feOffset nutzt dazu folgende Attribute:

  • dx: waagerechte Verschiebung
  • dy: senkrechte Verschiebung

Für dx und dy sind auch negative Werte zulässig, um die Grafik nach links bzw. oben zu verschieben.


feMerge

Der primitive Filter feMerge fügt Ergebnisse verschiedener Urfilter oder Eingabekanäle zusammen. Die zusammenzufügenden Eingaben oder Ergebnisse werden jeweils im Kindelement feMergeNode notiert. Die Eingaben werden in der Reihenfolge übereinandergelegt, wie sie notiert sind. Anders als bei feBlend sind beliebig viele Ebenen möglich.

Verdopplung mit feOffset und feMerge ansehen …
<defs>
  <filter id="f1" x="0" y="0" width="200%" height="200%">
    <feOffset in="SourceGraphic" result="translatedObject" dx="20" dy="20" />
    <feMerge>
      <feMergeNode in="f1"/>
      <feMergeNode in="SourceGraphic"/>
    </feMerge>
  </filter>
</defs>

<g transform="translate(250,0)">
 <use href="#doppeldecker" filter="url(#f1)"/>
 <text x="20" y="190">Verdoppelung mit feOffset</text>
</g>

Der Filter besteht aus einem feOffset-Filter, der aus der Ursprungsgrafik ein weiteres Bild mit einer Verschiebung von 20px in die x- und y-Richtung erzeugt.

Dieses wird mittels des feMerge-Filters wieder mit der Ursprungsgrafik zusammengeführt.


Unschärfe

feGaussianBlur

Durch die Streuung des Sonnenlichts in der Luft und die Reflexion von hellen Flächen ist ein Schatten aber nie so abgegrenzt wie im obigen Beispiel, sondern hat nur verschwommene Konturen.

Mit dem feGaussianBlur-Filter, dem sogenannten „Gausschen Weichzeichner“ kannst du die Ursprungsgrafik nun verwischen.[1]

Beispiel ansehen …
<defs>
  <filter id="f1" x="0" y="0" width="200%" height="200%">
    <feOffset in="SourceGraphic" result="translatedObject"  dx="20" dy="20" />
    <feGaussianBlur in="translatedObject" result="blurredObject"  stdDeviation="10" />
    <feBlend in="SourceGraphic" in2="blurredObject" mode="normal" />
  </filter>
</defs>

<g transform="translate(250,0)">
 <use xlink:href="#doppeldecker" filter="url(#f1)"/>
 <text x="20" y="190">Verwischen mit feGaussianBlur</text>
</g>

Das Ergebnis des feOffset-Filters wird mit dem feGaussianBlur-Filter verwischt, sodass es nur noch verschwommen ist.

Das weichgezeichnete Zwischenergebnis blurredObject wird mittels des feBlend-Filters wieder mit der Ursprungsgrafik zusammengeführt.

Schattenfarbe

Farbige Schatten sind eher ein Sonderfall unter speziellen Lichtverhältnissen. Um unseren Schatten grau einzufärben gibt es zwei alternative Vorgehensweisen:

Beispiel ansehen …
<defs>
  <filter id="f1" x="0" y="0" width="200%" height="200%">
    <feOffset in="SourceAlpha" result="translatedObject"  dx="20" dy="20" />
	<feGaussianBlur in="translatedObject" result="blurredObject"  stdDeviation="10" />
    <feBlend in="SourceGraphic" in2="blurredObject" mode="normal" />
  </filter>
  
  <filter id="f2" x="0" y="0" width="200%" height="200%">
    <feOffset in="SourceGraphic" result="translatedObject"  dx="20" dy="20" />
    <feColorMatrix in="translatedObject" result="matrixOut" type="matrix"
               values="0.2 0 0 0 0 0 0.2 0 0 0 0 0 0.2 0 0 0 0 0 1 0" />
    <feGaussianBlur in="matrixOut" result="blurOut" stdDeviation="10" />
    <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />	
  </filter>  
</defs>

Im linken Beispiel wird anstelle der Ausgangsgrafik selbst nur der Alphakanal der Ausgangsgrafik verwendet. <feOffset in="SourceAlpha" .../>

Im rechten Beispiel wird das Ergebnis der Verschiebung mit feOffset durch den feColorMatrix-Filter gefärbt. Durch die Multiplikation der Farbwerte für rot, grün und blau werden sie dunkler und schwärzer. Alternativ könnte man hier den feFlood-Filter verwenden.

feDropShadow

Da bei den meisten Schlagschatten diese Schritte nötig sind, wurde im Filter Effects Module ein zusammenfassender Urfilter feDropShadow eingeführt, der alle obigen Schritte beinhaltet:


Neben den schon oben eingeführten

  • dx und dy für die Verschiebung
  • stdDeviation für den Weichzeichner-Effekt

gibt es die aus feFlood bekannten Präsentationsattribute

feDropShadow ansehen …
    <filter id="DropShadow">
      <feDropShadow dx="-0.8" dy="-0.8" stdDeviation="1"
          flood-color="pink" flood-opacity="0.5"/>
    </filter>

Schlaglicht und Innenschatten

Beleuchtete Objekte werfen aber nicht nur einen Schlagschatten auf den Hintergrund, sondern erscheinen im Schlaglicht heller und auf der abgewandten, aber sichtbaren Seite dunkler.


Beispiel ansehen …
	<radialGradient id="gold" cx="0.3" cy=".3" r=".5" >
		<stop offset="0%" stop-color="#fff" />
		<stop offset="100%" stop-color="gold" />
	</radialGradient>
	
	<filter id="InnerShadow">
		<feOffset dx="-20" dy="-20" />
		<feGaussianBlur stdDeviation="10" result="blurOut"/>
		<feComposite in="SourceGraphic" in2="blurOut" operator="out" result="inverseOut"/>
		<feFlood flood-color="black" flood-opacity="0.75" result="color" />
		<feComposite in="color" in2="inverseOut" operator="in" result="shadow"/>
		<feComposite in="shadow" in2="SourceGraphic" operator="over" />
	</filter>

Der Apfel und die Birne erhalten als Füllung einen radialGradient, der die beleuchtete Fläche weiß darstellt. Der Verlauf geht in die jeweilige Grundfarbe über.

Zusätzlich kannst du mit dem InnerShadow-Filter Teile der Urspungsgrafik schattieren.

Wenn du die Ursprungsgrafik sowohl innen als auch außen schattieren willst, musst du beide Filter innerhalb eines Filterelements notieren und zum Schluss mit feBlend wieder zusammenführen. Ein Aufrufen mehrerer Filter ist in SVG leider nicht möglich.


Beleuchtungseffekte

Mit feGaussianBlur erzeugte Schlagschatten können aber auch als Ausgangspunkt für einen Beleuchtungseffekt mit dem feSpecularLighting-Filter verwendet werden. Der Wischeffekt des Schattens sorgt für eine abgerundete Oberfläche der Alphawerte, die durch den Beleuchtungseffekt hervorgehoben werden.

feDiffuseLighting

Der primitive Filter feDiffuseLighting dient der indirekten Beleuchtung durch diffuses Licht nach dem Phong-Modell. Als Lichtquellen dienen die Kindelemente feDistantLight (entfernte Lichtquelle), fePointLight (Punktlichtquelle) und feSpotLight (Scheinwerfer).

Folgende Attribute sind möglich:

  • in: Eingangsgrafik
  • surfaceScale: legt die Höhe der Oberfläche fest, auf die ein Beleuchtungs-Filter angewendet wird
  • diffuseConstant: repräsentiert den kd-Wert im Phong-Beleuchtungsmodell


indirekte Beleuchtung ansehen …
  <filter id="beleuchtung1">
    <feDiffuseLighting in="SourceGraphic" result="light" lighting-color="white">
      <feDistantLight azimuth="50" elevation="50"/>
    </feDiffuseLighting>

    <feComposite in="SourceGraphic" in2="light"
                 operator="arithmetic" k1="1" k2="0" k3="0" k4="0"/>
  </filter>
  
  <filter id="beleuchtung2">
    <feDiffuseLighting in="SourceGraphic" result="light" lighting-color="white">
      <fePointLight x="30" y="30" z="20" />
    </feDiffuseLighting>
    <feComposite in="SourceGraphic" in2="light"
                 operator="arithmetic" k1="1" k2="0" k3="0" k4="0"/>
  </filter>
  
 <filter id="beleuchtung3">
    <feDiffuseLighting in="SourceGraphic" result="light" lighting-color="white">
      <feSpotLight x="-20" y="5" z="30" limitingConeAngle="20"
                   pointsAtX="50" pointsAtY="50" pointsAtZ="0"/>
    </feDiffuseLighting>

    <feComposite in="SourceGraphic" in2="light"
                 operator="arithmetic" k1="1" k2="0" k3="0" k4="0"/>
  </filter>

Im Beispiel werden verschiedene Beleuchtungsfilter angewandt. Zuerst wird die Grafik mit einem feDiffuseLighting-Filter beleuchtet. Danach wird die Grafik mittels feComposite mit der Ursprungsgrafik kombiniert.

Um die Werte für die Lichtquellen nicht immer anpassen zu müssen, werden die Filter und Objekte auf den Ursprung (0,0) ausgerichtet und mit transform="translate() verschoben.

Die Beispiele in der 2. Spalte werden mit feDistantLight indirekt beleuchtet. Dabei fällt auf, dass sie dunkler als die unbeleuchteten Elemente in der linken Spalte wirken. Durch eine Erhöhung des elevation-Werts auf 100 kannst du die Helligkeit verstärken.

Die Beispiele in der 3. Spalte werden mit fePointLight mit einer Punktlichtquelle beleuchtet.

Die Beispiele in der rechten Spalte werden mit feSpotLight mit einem Scheinwerfer beleuchtet.

Beachte: Der Beleuchtungseffekt wird umso deutlicher, je heller das zu beleuchtende Objekt ist. Bei der Füllfarbe schwarz ist gar kein Beleuchtungseffekt zu erkennen.


Kindelemente

feDistantLight

Der Filter feDistantLight beleuchtet mit einer entfernten Lichtquelle.

Folgende Attribute sind nötig:

  • azimuth: Richtungswinkel der Lichtquelle
  • elevation: legt den Richtungswinkel (in Grad) der Lichtquelle aus der X/Y- Ebene zur Z-Achse fest

fePointLight

Der Filter fePointLight beleuchtet mit einer Punktlichtquelle.

Folgende Attribute sind möglich:

  • x: Koordinate der X-Achse
  • y: Koordinate der Y-Achse
  • z: Koordinate der Z-Achse (Höhe der Lichtquelle)

Falls die Attribute nicht definiert werden, wird ein Wert von 0 angenommen.

feSpotLight

Der Filter feSpotLight beleuchtet mit einem Scheinwerfer.

Folgende Attribute sind möglich:

  • x: Koordinate der X-Achse
  • y: Koordinate der Y-Achse
  • z: Koordinate der Z-Achse
  • limitingConeAngle: (Standardwert: kein Winkel) legt den Winkel (in Grad) der Beleuchtungsachse (zwischen der Lichtquelle und dem beleuchteten Punkt) fest
  • pointsAtX: X-Position im Koordinatensystem
  • pointsAtY: Y-Position im Koordinatensystem
  • pointsAtZ: Z-Position im Koordinatensystem
  • specularExponent: legt den Fokus (Brennpunkt) der Lichtquelle fest (Standardwert: 1)

Falls die Attribute nicht definiert werden, wird ein Wert von 0 angenommen.

Siehe auch


feSpecularLighting

Der primitive Filter feSpecularLighting dient der Beleuchtung einer Eingangsgrafik mit reflektierendem Licht. Dabei wird der Alpha-Kanal der Eingangsgrafik als Relief verwendet. Als Lichtquellen dienen die Kindelemente feDistantLight (entfernte Lichtquelle), fePointLight (Punktlichtquelle) und feSpotLight (Scheinwerfer). Der Filter benutzt das Blinn-Phong-Beleuchtungsmodell als theoretische Grundlage.[2]

Du kannst die Relieftiefe, die Intensität und den Glanz des Lichts durch Attribute beeinflussen.

Folgende Attribute sind möglich:

in
Eingangsgrafik
surfaceScale
legt die Höhe der Oberfläche fest, auf die ein Beleuchtungs-Filter angewendet wird
specularConstant
legt fest, wie viel Licht reflektiert wird (der kspecular-Wert im Beleuchtungsmodell)
specularExponent
legt den Fokus (Brennpunkt) der Lichtquelle fest (kleinerer Wert wirkt diffuser, größerer Wert wirkt glänzender)


Beleuchtungseffekte ansehen …
<filter id="specular1">
  <feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>
  <feSpecularLighting in="blur" surfaceScale="5" specularConstant="1" 
                      specularExponent="10" lighting-color="white"
                      result="specOut">
    <fePointLight x="-50" y="-100" z="200"/>
  </feSpecularLighting>
  <feComposite in="specOut" in2="SourceAlpha" operator="in" result="specOut"/>
  <feComposite in="SourceGraphic" in2="specOut" operator="lighter"/>
</filter>
  
<filter id="specular2">
  <feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>
  <feSpecularLighting in="blur" surfaceScale="5" specularConstant="1"
                      specularExponent="10" lighting-color="white"
                      result="specOut">
    <feDistantLight azimuth="45" elevation="45"/>
  </feSpecularLighting>
  <feComposite in="specOut" in2="SourceAlpha" operator="in" result="specOut"/>
  <feComposite in="SourceGraphic" in2="specOut" operator="lighter" />
</filter>

<filter id="specular3">
  <feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>
  <feSpecularLighting in="blur" surfaceScale="5" specularConstant="1" 
                      specularExponent="10" lighting-color="white"
                      result="specOut">
    <feSpotLight x="-20" y="5" z="30" limitingConeAngle="45"
           pointsAtX="10" pointsAtY="10" pointsAtZ="0"/>
  </feSpecularLighting>
  <feComposite in="specOut" in2="SourceAlpha" operator="in" result="specOut"/>
  <feComposite in="SourceGraphic" in2="specOut" operator="lighter" />
</filter>

Das Beispiel zeigt, wie du eine feSpecularLighting-Beleuchtung auf ein Bild anwendest und wie sich die unterschiedlichen Lichtquellen auf das Ergebnis auswirken.

Grundsätzlich benötigt feSpecularLighting eine weichgezeichnete Version des SourceAlpha-Bildes. Scharfe Übergänge des Transparenzwertes zerstören den Effekt. Deswegen wird zunächst eine solche Weichzeichnung erstellt und mit dem Namen "blur" versehen.

Die verwendeten Attribute für den Beleuchtungsfilter sind immer gleich und empirisch ermittelt. Von den verwendeten Werten für specularConstant und specularExponent sollte man sich in der Praxis nicht zu weit entfernen, weil der Beleuchtungseffekt sonst zu schwach oder diffus wird oder zu sehr überstrahlt.

Es ist wichtig, dass das Ergebnis von feSpecularLighting mit dem in-Operator auf die SourceGraphic reduziert wird. Andernfalls führt der Übergang von Alphabild zum Umfeld zu einem weiteren Beleuchtungsrand. Das Ergebnis der Maskierung kann dann mit der SourceGraphic zusammengeführt werden. Dazu verwendet man den Composite-Operator "lighter", der die Werte beider Teilbilder unter Berücksichtigung ihrer Transparenz addiert und für diesen Zweck vorgesehen ist. Natürlich kann man auch den arithmetic-Operator mit k1=0, k2=1, k3=1 und k4=0 verwenden. Das führt zum gleichen Ergebnis.

Die linke Spalte wird mit feDistantLight indirekt beleuchtet.

Die Objekte in der mittleren Spalte werden mit fePointLight mit einer Punktlichtquelle beleuchtet. Die Lichtquelle ist schräg über den Objekten platziert. (Verändere die Werte für x, y und z!)

Die Beispiele in der rechten Spalte werden mit feSpotLight mit einem Scheinwerfer beleuchtet. Wie bei feDiffuseLighting ist hier kein ausgeprägter Lichtkegel sichtbar.

Siehe auch

Weblinks

  1. MDN: Drop Shadow example (sehr einfach)
  2. Wikipedia: Blinn-Phong-Beleuchtungsmodell