Transparenz-Simulation in Silverlight

by St. Lange 25. May 2010 17:55

Anhand von zwei Projekt-Beispielen wird die Anwendung von nicht ganz alltäglichen Transparenz-Effekten vorgestellt.

1. Transparentes Video

Die Vorgabe der Grafikerin klang eigentlich ganz einfach: Das zu bewerbende Produkt sollte aus sich bewegendem Nebel herausragen und dabei aber noch teilweise mehr oder weniger vom Nebel verdeckt werden. Da Nebel an sich ja durchsichtig ist, sollte dies eigentlich kein Problem sein.

Der Nebel lag in Form eines HD Videos von real gefilmtem Nebel vor, das Bild vom Produkt war ein freigestelltes PNG. Nun ist aber ein Video von Nebel etwas anderes als realer Nebel. Natürlich kann man der Property Opacity des Media-Elements, welches den Nebel abspielt, einen Wert kleiner eins geben. Damit erhält man zwar ein durchsichtiges Video, aber nicht den gewünschten Effekt. So einfach geht es leider nicht.

Das folgende Bild zeigt einen Screenshot der fertigen Seite. Durch Anklicken kommt man auf die echte Seite.

Die Lösung besteht darin, das Produktbild vor das Video zu legen und es mit Hilfe einer OpacityMask nach unten hin immer durchsichtiger werden zu lassen. Hier ein Auszug des dazugehörigen XAML-Codes:

<MediaElement x:Name="fog1" Source="http://localhost/newblonde/assets/NewBlondeFog.wmv" AutoPlay="True" Stretch="UniformToFill"/>
<SSME:SmoothStreamingMediaElement x:Name="fog2" SmoothStreamingSource="http://localhost/newblonde/assets/NewBlondeFog.ism/Manifest" AutoPlay="True" Stretch="UniformToFill"/>
...
<Image x:Name="imgPackShot" Height="501" Width="356" Canvas.Left="321" Canvas.Top="94" Source="Assets/packshot.png" Stretch="Fill" RenderTransformOrigin="0.5,0.5">
  <Image.OpacityMask>
    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
      <GradientStop Color="White" Offset="0"/>
      <GradientStop Color="#7FFFFFFF" Offset="0.33"/>
      <GradientStop Color="Transparent" Offset="1"/>
    </LinearGradientBrush>
  </Image.OpacityMask>
</Image>

Die ersten beiden Elemente sind zwei verschiedene Videoplayer. Der erste ist der Standardplayer für WMV-Dateien, während der zweite aus dem Smooth Streaming SDK stammt. Durch Silverlight Smooth Streaming kann wahlweise eine höhere Qualität des Nebel-Videos erreicht werden. Welcher der beiden Player verwendet wird, kann per Konfiguration festgelegt werden.

Das dritte Element ist das Foto des Produktes. Die OpacityMask sorgt dafür, das im unteren Bereich des Bildes mehr und mehr vom dahinterliegenden Nebel zu sehen ist. Beim Betrachter entsteht so die Illusion, das Produkt schwebe mitten im Nebel. Durch eine leichte, mittels PowerEase gedämpfte Bewegung des Bildes wird dieser Effekt noch unterstrichen. Es ist schon erstaunlich: Obwohl ich es gemacht habe, kann ich nicht "sehen", dass sich der Nebel in Wirklichkeit hinter dem Bild befindet.

Der Nebel

Das Nebel-Video ist übrigens wie folgt gemacht: Das von der Agentur gelieferte ca. 25 Sekunden lange HD Video habe ich mit Sony Vegas so bearbeitet, dass die letzten 5 Sekunden mit dem Anfang per Kreuzblende überlagert wurden. Damit sehen der letzte Frame und der Frame aus Sekunde 5 des Originalvideos identisch aus. Das so entstandene neue und um 5 Sekunden kürzere Video kann nun in einer Endlosschleife abgespielt werden und der Sprung an den Anfang ist dabei fast nicht zu bemerken.

 

2. Transparente Silverlight Anwendung

Hier bestand die Aufgabe darin, ein mit Silverlight animiertes Firmenlogo auf einer normalen HTML-Seite anzuzeigen. Eine Silverlight-Anwendung von beispielsweise 150 x 150 Pixeln Größe zu erstellen, in der ein Logo animiert wird, ist trivial. Das Problem bestand darin, durch die Anwendung hindurch das Hintergrundbild der darunterliegenden HTML-Seite sehen zu können.

Die einfachste Lösung ist, die Silveright-Anwendung auf windowless zu schalten. Dies sollte jedoch gerade nicht gemacht werden, da dieser Modus möglicherweise nicht bei allen Browsern einwandfrei funktioniert.

Eine alternative Lösung besteht darin, dass die Silverlight-Anwendung das gleiche Hintergrundbild wie die HTML-Seite lädt und dann exakt den Ausschnitt davon anzeigt, den sie selbst gerade verdeckt. Die folgende Test-Anwendung zeigt, wie man das im Prinzip machen kann:

Das Bild mit dem Baum soll den Hintergrund einer HTML-Seite darstellen. Die eigentliche Silverlight-Anwendung ist zur Verdeutlichung mit gelben Punkten umrandet. Durch Anklicken kann die Umrandung ab und auch wieder angeschaltet werden.

Als Logo Beispiel dient hier ein Dodekaeder, dessen Seiten mit einem teiltransparenten ImageBrush gefüllt sind. 5 Sekunden nach dem Laden der Seite beginnt der Dodekaeder sich zu drehen. Nach weiteren 15 Sekunden fängt die Silverlight-Anwendung an, sich zusätzlich noch auf dem Hintergrund herumzubewegen.

Es entsteht dabei die Illusion, die Silverlight-Anwendung sei transparent, obwohl sie in Wirklichkeit nur geschickt ihren Hintergrund zeichnet.

Das div Element, welches das Silverlight object Element enthält, liegt wiederum in einem div mit dem background Bild:

<div style="height:375px; width:600px; background:url(http://.../background.jpg)">
  <div id="silverlightControlHost" style="height:150px; width:150px; left:90px; top:50px;
      position:relative">
    <object data="data:application/x-silverlight-2," type="application/x-silverlight-2"
       width="150" height="150">

Dieses div mit dem Namen "silverlightControlHost" sorgt dafür, dass sich die Anwendung 90 Pixel vom linken und 50 Pixel vom oberen Rand entfernt befindet. Hier nun der XAML-Code der eigentlichen Anwendung:

<UserControl x:Class="PseudoTransparentBackground.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:PseudoTransparentBackground" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" 
    Height="150" Width="150">
  <Grid x:Name="LayoutRoot" Cursor="Hand">
    <Grid.Background>
      <ImageBrush ImageSource="http://.../background.jpg"
          Stretch="None" AlignmentX="Left" AlignmentY="Top">
        <ImageBrush.Transform>
          <CompositeTransform x:Name="Offset" TranslateX="-90" TranslateY="-50"  />
        </ImageBrush.Transform>
      </ImageBrush>
    </Grid.Background>
    <local:DodecahedronLogo RenderTransformOrigin="0.5 0.5" >
      <local:DodecahedronLogo.RenderTransform>
        <ScaleTransform ScaleX="0.25" ScaleY="0.25"/>
      </local:DodecahedronLogo.RenderTransform>
    </local:DodecahedronLogo>
    <Rectangle x:Name="ControlBorder" Stroke="Yellow" StrokeThickness="4" StrokeDashArray="0 2"
        StrokeDashCap="Round" StrokeDashOffset="0.5" />
  </Grid>
</UserControl>

Das selbe Hintergrundbild wie aus der HTML-Seite wird über eine ImageBrush als Background verwendet. Dabei wird das Bild über eine CompositeTransform entsprechend so verschoben, dass es den gleichen Ausschnitt zeigt wie die Stelle, die die Anwendung momentan verdeckt.

Damit habe ich erreicht, eine nicht-windowless Silverlight-Anwendung mit einem scheinbar transparenten Hintergrund zu erstellen.

Noch mehr Bewegung

Nur so zum Ausprobieren habe ich dann auch noch die Position der Silverlight-Anwendung animiert. Dazu wurde eine neue Klasse AppPosition mit zwei Dependency Properties Left und Top angelegt. Mittels zweier DoubleAnimation Objekte werden Left und Top animiert und so die Anwendung immer wieder auf neue Zufallspositionen innerhalb der Grenzen des Hintergrundbildes bewegt.

Damit nun die Silverlight-Anwendung ihre eigene Position im Browserfenster verändern kann, verwendet sie die Funktion SetStyleAttribute der Klasse HtmlElement. Hier der Code, der aufgerufen wird, wenn sich beispielsweise der Wert der Property Left ändert:

private static void LeftChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  int x = Convert.ToInt32((double)e.NewValue);
  MainPage.Offset.TranslateX = -x;
  SilverlightControlHost.SetStyleAttribute("left", String.Format("{0}px", x));
}

Zum einen wird die Property TranslateX aus dem ImageBrush angepasst, zum anderen das Attribut left des Styles des SilverlightControlHost div Elements. Analoges gilt für die Property Top. Diesen Effekt hätte man vielleicht auch mit JavaScript erreichen können, aber mit Silverlight fiel mir das Programmieren deutlich leichter.

Im Internet Explorer 8 funktioniert diese Bewegung übrigens ganz gut, während der Hintergrund im Firefox 3.6 und in Chrome 4.1 relativ stark zittert. Im aktuellen Internet Explorer 9 Platform Preview sieht es am geschmeidigsten aus.

Für alle, die es sich genauer anschauen wollen, hier der Quellcode zum Downloaden:

PseudoTransparentBackground.zip (235 kB)

(Hinweis: Vor dem Build muss möglicherweise die Datei Petzold.Media3D.dll über Eigenschaften/Sicherheit zur Verwendung zugelassen werden.)

 
kick it on dotnet-kicks.de

Tags:

Silverlight

Comments

5/25/2010 7:03:45 PM #

pingback

Pingback from topsy.com

Twitter Trackbacks for
        
        Weblog by Stefan Lange | Transparenz-Simulation in Silverlight
        [st-lange.net]
        on Topsy.com

topsy.com |

5/27/2010 11:58:59 AM #

trackback

Transparenz in Videos und Silverlight

Sie wurden gekickt (eine gute Sache) - Trackback von  dotnet-kicks.de

dotnet-kicks.de |

Comments are closed

Powered by BlogEngine.NET 1.6.1.0 - Impressum