Übersicht über 3D-Grafiken

Mit der 3D-Funktion in Windows Presentation Foundation (WPF) können Entwickler 3D-Grafiken sowohl in Markupcode als auch in prozeduralem Code zeichnen, transformieren und animieren. Entwickler können 2D- und 3D-Grafiken miteinander kombinieren, um ansprechende Steuerelemente zu erstellen, komplexe Illustrationen von Daten bereitzustellen oder die Benutzererfahrung einer Anwendungsschnittstelle zu verbessern. 3D-Unterstützung in WPF ist nicht dazu gedacht, eine vollständige Plattform zur Spieleentwicklung bereitzustellen. Dieses Thema bietet eine Übersicht über 3D-Funktionen im WPF-Grafiksystem.

3D in einem 2D-Container

Die Inhalte von 3D-Grafiken sind in WPF in einem Element gekapselt, Viewport3D, das Teil einer zweidimensionalen Elementstruktur sein kann. Das Grafiksystem behandelt Viewport3D als ein zweidimensionales visuelles Element, wie viele andere auch in WPF. Viewport3D fungiert als Fenster – ein Anzeigebereich – in eine dreidimensionale Szene. Genauer gesagt handelt es sich um eine Oberfläche, auf die eine 3D-Szene projiziert wird.

In einer konventionellen 2D-Anwendung verwenden Sie Viewport3D wie jedes andere Containerelement wie Raster oder Canvas. Obwohl Sie Viewport3D mit anderen 2D-Zeichenobjekten im selben Szenegraphen verwenden können, können Sie keine 2D- und 3D-Objekte in Viewport3D durchdringen. Dieses Thema behandelt das Zeichnen von 3D-Grafiken in Viewport3D.

3D-Koordinatenbereich

Im WPF-Koordinatensystem für 2D-Grafiken befindet sich der Ursprung in der linken oberen Ecke des Renderingbereichs (in der Regel der Bildschirm). Im 2D-System verlaufen die positiven Werte der x-Achse nach rechts und die positiven Werte der y-Achse nach unten. Im 3D-Koordinatensystem befindet sich der Ursprung hingegen in der Mitte des Renderingbereichs. Die positiven Werte der x-Achse verlaufen auch nach rechts, die positiven Werte der y-Achse verlaufen aber nach oben und die positiven Werte der z-Achse laufen vom Ursprung ausgehend auf den Betrachter zu.

Coordinate systems
Darstellungen konventioneller 2D- und 3D-Koordinatensysteme

Der von diesen Achsen definierte Raum ist der feststehende Verweisrahmen für 3D-Objekte in WPF. Wenn Sie innerhalb dieses Raumes Modelle erstellen und Lichter und Kameras, um sie anzuzeigen, ist es hilfreich, diesen feststehenden Verweisrahmen oder „Weltenraum“ vom lokalen zu unterscheiden, den Sie beim Anwenden von Transformationen für jedes Modell erstellen. Beachten Sie außerdem, dass Objekte im Weltenraum je nach der Kamera und den Einstellungen völlig anders oder überhaupt nicht angezeigt werden können. Die Position der Kamera ändert aber nicht die Position von Objekten im Weltenraum.

Kameras und Projektionen

Entwickler, die in 2D arbeiten, sind es gewöhnt, zeichnende primitive Typen auf einem zweidimensionalen Bildschirm zu positionieren. Beim Erstellen einer 3D-Szene ist es wichtig, dass Sie daran denken, dass Sie wirklich eine 2D-Darstellung von 3D-Objekten erstellen. Da eine 3D-Szene je nach Perspektive des Betrachters anders aussieht, müssen Sie diese Perspektive angeben. Mit der Camera-Klasse können Sie diese Perspektive für eine 3D-Szene angeben.

Eine andere Möglichkeit, zu verstehen, wie eine 3D-Szene auf einer 2D-Oberfläche dargestellt wird, ist durch Beschreibung der Szene als eine Projektion auf die Ansichtsoberfläche. Mit der ProjectionCamera-Klasse können Sie verschiedene Projektionen und deren Eigenschaften angeben, um die Art und Weise zu ändern, in der der Betrachter 3D-Modelle sieht. Ein PerspectiveCamera gibt eine Projektion an, die die Szene verkürzt. Das heißt, die PerspectiveCamera bietet eine Fluchtpunkt-Perspektive. Sie können die Position der Kamera im Koordinatenbereich der Szene, die Richtung und das Sichtfeld der Kamera und ein Vektor angeben, der die Richtung „nach oben“ in der Szene definiert. Das folgende Diagramm veranschaulicht die PerspectiveCamera-Projektion.

Die NearPlaneDistance- und FarPlaneDistance-Eigenschaften von ProjectionCamera begrenzen den Bereich der Kameraprojektion. Da sich Kameras überall in der Szene befinden können, kann die Kamera auch innerhalb eines Modells oder sehr nah an einem Modell positioniert werden. Dies erschwert ordnungsgemäße die Unterscheidung von Objekten. Mit NearPlaneDistance können Sie einen Mindestabstand von der Kamera angeben, über den hinaus Objekte nicht gezeichnet werden. Im Gegensatz dazu können Sie mit FarPlaneDistance einen Abstand von der Kamera angeben, über den hinaus keine Objekte gezeichnet werden. Dies stellt sicher, dass Objekte, die zu weit entfernt sind, um erkannt zu werden, nicht in der Szene enthalten sind.

Camera setup
Kameraposition

OrthographicCamera gibt eine orthogonale Projektion eines 3D-Modells auf einer visuellen 2D-Oberfläche an. Wie andere Kameras gibt es eine Position, Blickrichtung und die Richtung „nach oben“ an. Im Gegensatz zu PerspectiveCamera beschreibt OrthographicCamera jedoch eine Projektion, die keine perspektivische Verkürzung umfasst. Das heißt, dass OrthographicCamera ein Sichtfeld beschreibt, dessen Seiten parallel sind, statt in einem Punkt der Kamera zusammenzulaufen. Das folgende Bild zeigt das gleiche Modell, wie mit PerspectiveCamera und OrthographicCamera dargestellt.

Orthographic and perspective projection
Perspektivische und orthografische Projektionen

Der folgende Code zeigt einige typische Kameraeinstellungen.

// Defines the camera used to view the 3D object. In order to view the 3D object,
// the camera must be positioned and pointed such that the object is within view
// of the camera.
PerspectiveCamera myPCamera = new PerspectiveCamera();

// Specify where in the 3D scene the camera is.
myPCamera.Position = new Point3D(0, 0, 2);

// Specify the direction that the camera is pointing.
myPCamera.LookDirection = new Vector3D(0, 0, -1);

// Define camera's horizontal field of view in degrees.
myPCamera.FieldOfView = 60;

// Asign the camera to the viewport
myViewport3D.Camera = myPCamera;
' Defines the camera used to view the 3D object. In order to view the 3D object,
' the camera must be positioned and pointed such that the object is within view 
' of the camera.
Dim myPCamera As New PerspectiveCamera()

' Specify where in the 3D scene the camera is.
myPCamera.Position = New Point3D(0, 0, 2)

' Specify the direction that the camera is pointing.
myPCamera.LookDirection = New Vector3D(0, 0, -1)

' Define camera's horizontal field of view in degrees.
myPCamera.FieldOfView = 60

' Asign the camera to the viewport
myViewport3D.Camera = myPCamera

Modell- und primitive Gittertypen

Model3D ist die abstrakte Basisklasse, die ein generisches 3D-Objekt darstellt. Um eine 3D-Szene zu erstellen, benötigen Sie einige anzuzeigende Objekte und die Objekte, aus denen der Szenengraph besteht, werden von Model3D abgeleitet. Derzeit unterstützt WPF Modellierungsgeometrien mit GeometryModel3D. Die Geometry-Eigenschaft dieses Modells akzeptiert einen primitiven Gittertypen.

Um ein Modell zu erstellen, erstellen Sie zuerst einen primitiven Typen oder ein Gitter. Ein primitiver 3D-Typ besteht aus einer Auflistung der Vertices, die eine einzelne 3D-Entität bilden. Die meisten 3D-Systeme bieten primitive Typen, die ausgehend von der einfachsten geschlossenen Figur modelliert wurden: drei durch drei Vertices definiertes Dreieck. Da die drei Punkte eines Dreiecks auf derselben Ebene liegen, können Sie weiterhin Dreiecke hinzufügen, um komplexere Formen, die Gitter genannt werden, zu modellieren.

Das 3D-System von WPF stellt derzeit dieMeshGeometry3D-Klasse bereit, mit dem Sie jede beliebige Geometrie angeben können. Es werden derzeit aber keine vordefinierten primitiven 3D-Typen wie Kreise und kubische Formen unterstützt. Erstellen Sie MeshGeometry3D, indem Sie eine Liste der Dreieck-Vertices als Positions-Eigenschaft angeben. Jeder Vertex wird als Point3D angegeben. (Geben Sie diese Eigenschaft in XAML als eine Liste von Zahlen in Dreiergruppen an, die die Koordinaten der einzelnen Vertices darstellen.) Je nach Geometrie kann das Gitter aus mehreren Dreiecken bestehen, von denen einige dieselben Eckpunkte (Vertices) teilen. Um das Gitter korrekt zeichnen zu können, benötigt WPF Informationen dazu, welche Dreiecke sich welche Vertices teilen. Sie stellen diese Informationen zur Verfügung, indem Sie eine Liste der Dreieck-Indizes mit der TriangleIndices-Eigenschaft angeben. In dieser Liste ist die Reihenfolge angegeben, in der die in der Positions-Liste aufgeführten Punkte ein Dreieck festlegen.

<GeometryModel3D>
  <GeometryModel3D.Geometry>
          <MeshGeometry3D 
              Positions="-1 -1 0  1 -1 0  -1 1 0  1 1 0"
              Normals="0 0 1  0 0 1  0 0 1  0 0 1"
              TextureCoordinates="0 1  1 1  0 0  1 0   "
              TriangleIndices="0 1 2  1 3 2" />
      </GeometryModel3D.Geometry>
      <GeometryModel3D.Material>
          <DiffuseMaterial>
              <DiffuseMaterial.Brush>
                  <SolidColorBrush Color="Cyan" Opacity="0.3"/>
              </DiffuseMaterial.Brush>
          </DiffuseMaterial>
      </GeometryModel3D.Material>
  <!-- Translate the plane. -->
      <GeometryModel3D.Transform>
          <TranslateTransform3D
            OffsetX="2" OffsetY="0" OffsetZ="-1"   >
          </TranslateTransform3D>
      </GeometryModel3D.Transform>
  </GeometryModel3D>

Im vorherigen Beispiel sind in der Positions-Liste vier Vertices angegeben, um ein rechteckiges Gitter zu definieren. Die TriangleIndices-Eigenschaft gibt eine Liste mit zwei Gruppen von jeweils drei Indizes an. Jede Zahl in der Liste bezieht sich auf einen Versatz in die Positions-Liste. Die ersten drei Vertices in der Positions-Liste sind beispielsweise (-1,-1,0), (1,-1,0) und (-1,1,0). Die ersten drei Indizes in der TriangleIndices-Liste sind 0, 1 und 2, was dem ersten, zweiten und dritten Punkt in der Positions-Liste entspricht. Daher setzt sich das erste Dreieck, aus dem das Rechteckmodell besteht, aus (-1,-1,0), (1,-1,0) und (-1,1,0) zusammen. Das zweite Dreieck wird ähnlich bestimmt.

Sie können das Modell weiter definieren, indem Sie Werte für die Normals- und TextureCoordinates-Eigenschaften angeben. Um die Oberfläche des Modells zu rendern, benötigt das Grafiksystem Informationen darüber, in welche Richtung die Oberfläche bei jedem gegebenen Dreieck zeigt. Diese Informationen werden dazu verwendet, die Beleuchtung für das Modell zu berechnen: Flächen, die einer Lichtquelle direkt zugewendet sind, erscheinen heller als solche, die von Licht abgewandt sind. Obwohl WPF die Standardnormalvektoren mithilfe der Positionskoordinaten ermitteln kann, können Sie auch verschiedene Normalvektoren angeben, um sich der Darstellung von gekrümmten Oberflächen zu nähern.

Die TextureCoordinates-Eigenschaft gibt eine Auflistung von Point an, damit das Grafiksystem die Koordinaten zuordnen kann, die bestimmen, wie eine Textur zu den Vertices des Gittermodells gezeichnet wird. TextureCoordinates sind als ein Wert zwischen Null und 1 inklusive angegeben. Wie bei der Normals-Eigenschaft kann das Grafiksystem Standardtexturkoordinaten berechnen. Sie können aber ggf. andere Texturkoordinaten festlegen, um die Zuordnung einer Textur zu steuern, die z. B. einen Teil eines Wiederholungsmusters enthält. Weitere Informationen zu Texturkoordinaten finden Sie in den nachfolgenden Themen oder im Managed Direct3D SDK.

Im folgenden Beispiel wird veranschaulicht, wie eine Seite des Würfelmodells in prozeduralem Code erstellt wird. Sie können den gesamten Würfel als einzelnes Element vom Typ GeometryModel3D zeichnen. In diesem Beispiel wird die Würfelseite als eigenes Modell gezeichnet, um später separate Texturen auf die einzelnen Seiten anzuwenden.

MeshGeometry3D side1Plane = new MeshGeometry3D();
Private side1Plane As New MeshGeometry3D()
side1Plane.Positions.Add(new Point3D(-0.5, -0.5, -0.5));
side1Plane.Positions.Add(new Point3D(-0.5, 0.5, -0.5));
side1Plane.Positions.Add(new Point3D(0.5, 0.5, -0.5));
side1Plane.Positions.Add(new Point3D(0.5, 0.5, -0.5));
side1Plane.Positions.Add(new Point3D(0.5, -0.5, -0.5));
side1Plane.Positions.Add(new Point3D(-0.5, -0.5, -0.5));

side1Plane.TriangleIndices.Add(0);
side1Plane.TriangleIndices.Add(1);
side1Plane.TriangleIndices.Add(2);
side1Plane.TriangleIndices.Add(3);
side1Plane.TriangleIndices.Add(4);
side1Plane.TriangleIndices.Add(5);

side1Plane.Normals.Add(new Vector3D(0, 0, -1));
side1Plane.Normals.Add(new Vector3D(0, 0, -1));
side1Plane.Normals.Add(new Vector3D(0, 0, -1));
side1Plane.Normals.Add(new Vector3D(0, 0, -1));
side1Plane.Normals.Add(new Vector3D(0, 0, -1));
side1Plane.Normals.Add(new Vector3D(0, 0, -1));

side1Plane.TextureCoordinates.Add(new Point(1, 0));
side1Plane.TextureCoordinates.Add(new Point(1, 1));
side1Plane.TextureCoordinates.Add(new Point(0, 1));
side1Plane.TextureCoordinates.Add(new Point(0, 1));
side1Plane.TextureCoordinates.Add(new Point(0, 0));
side1Plane.TextureCoordinates.Add(new Point(1, 0));
side1Plane.Positions.Add(New Point3D(-0.5, -0.5, -0.5))
side1Plane.Positions.Add(New Point3D(-0.5, 0.5, -0.5))
side1Plane.Positions.Add(New Point3D(0.5, 0.5, -0.5))
side1Plane.Positions.Add(New Point3D(0.5, 0.5, -0.5))
side1Plane.Positions.Add(New Point3D(0.5, -0.5, -0.5))
side1Plane.Positions.Add(New Point3D(-0.5, -0.5, -0.5))

side1Plane.TriangleIndices.Add(0)
side1Plane.TriangleIndices.Add(1)
side1Plane.TriangleIndices.Add(2)
side1Plane.TriangleIndices.Add(3)
side1Plane.TriangleIndices.Add(4)
side1Plane.TriangleIndices.Add(5)

side1Plane.Normals.Add(New Vector3D(0, 0, -1))
side1Plane.Normals.Add(New Vector3D(0, 0, -1))
side1Plane.Normals.Add(New Vector3D(0, 0, -1))
side1Plane.Normals.Add(New Vector3D(0, 0, -1))
side1Plane.Normals.Add(New Vector3D(0, 0, -1))
side1Plane.Normals.Add(New Vector3D(0, 0, -1))

side1Plane.TextureCoordinates.Add(New Point(1, 0))
side1Plane.TextureCoordinates.Add(New Point(1, 1))
side1Plane.TextureCoordinates.Add(New Point(0, 1))
side1Plane.TextureCoordinates.Add(New Point(0, 1))
side1Plane.TextureCoordinates.Add(New Point(0, 0))
side1Plane.TextureCoordinates.Add(New Point(1, 0))

Anwenden von Materialien auf das Modell

Damit ein Gitter wie ein dreidimensionales Objekt aussieht, muss eine Textur darauf angewendet werden, die die von den Vertices und Dreiecken definierte Fläche abdeckt, sodass es beleuchtet und von der Kamera projiziert werden kann. In 2D verwenden Sie die Brush-Klasse, um Bildschirmbereichen Farben, Muster, Farbverläufe oder andere visuelle Inhalte zuzuweisen. Die Darstellung von 3D-Objekten ist eine Funktion des Beleuchtungsmodells und nicht nur des der Farbe oder des Musters, die darauf angewendet werden. Reale Objekte reflektieren Licht unterschiedlich, je nach der Qualität ihrer Oberflächen: glänzende und leuchtende Oberflächen sehen anders aus als raue oder matte Oberflächen, und einige Objekte scheinen Licht zu absorbieren, während andere leuchten. Sie können dieselben Pinsel auf 3D-Objekte anwenden, die Sie auch auf 2D-Objekte anwenden können, allerdings nicht direkt.

Um die Eigenschaften einer Modelloberfläche zu definieren verwendet WPF die abstrakte Material-Klasse. Die konkreten Unterklassen von „Material“ bestimmen einige der Darstellungseigenschaften der Modelloberfläche und stellen jeweils eine Pinseleigenschaft bereit, der Sie ein SolidColorBrush, TileBrush oder VisualBrush übergeben können.

  • DiffuseMaterial gibt an, dass der Pinsel auf das Modell angewendet wird, als wäre das Modell diffus beleuchtet. Die Verwendung von DiffuseMaterial ähnelt am meisten der direkten Verwendung auf 2D-Modelle. Modelloberflächen reflektieren das Licht nicht, als ob sie glänzen würden.

  • SpecularMaterial gibt an, dass der Pinsel auf das Modell angewendet wird, als ob die Modelloberfläche fest oder glänzend und in der Lage wäre, ein Glänzen zu reflektieren. Sie können den Grad festlegen, bis zu dem die Textur diese reflektierende Qualität (ein „Scheinen“) aufweist, indem Sie der SpecularPower-Eigenschaft einen Wert zuweisen.

  • Mit EmissiveMaterial können Sie angeben, dass die Textur angewendet wird, als ob das Modell Licht ausstrahlt, das der Farbe des Pinsels gleicht. Dies macht das Modell nicht zu Licht. Schatteneffekte werden jedoch anders dargestellt, als mit DiffuseMaterial oder SpecularMaterial.

Für eine bessere Leistung werden die Rückseiten von GeometryModel3D aus der Szene herausgefiltert (diese Seiten liegen außerhalb des Sichtfelds, da sie sich auf der der Kamera entgegengesetzten Seite des Modells befinden). Um Material zu bestimmen, was auf die Rückseite eines Modells wie eine Ebene angewendet werden soll, legen Sie die BackMaterial-Eigenschaft des Modells fest.

Um einige Oberflächenqualitäten zu erzielen, z.B. ein Leuchten oder reflektierende Effekte, können Sie nacheinander mehrere unterschiedliche Pinsel auf ein Modell anwenden. Mithilfe der MaterialGroup-Klasse können Sie mehrere Materialien anwenden und erneut verwenden. Die untergeordneten Elemente von MaterialGroup werden nacheinander in mehreren Renderingdurchläufen angewendet.

In den folgenden Codebeispielen wird gezeigt, wie eine Volltonfarbe und eine Zeichnung als Pinsel auf 3D-Modelle angewendet wird.

<GeometryModel3D.Material>
    <DiffuseMaterial>
        <DiffuseMaterial.Brush>
            <SolidColorBrush Color="Cyan" Opacity="0.3"/>
        </DiffuseMaterial.Brush>
    </DiffuseMaterial>
</GeometryModel3D.Material>
<DrawingBrush x:Key="patternBrush" Viewport="0,0,0.1,0.1" TileMode="Tile">
  <DrawingBrush.Drawing>
    <DrawingGroup>
      <DrawingGroup.Children>
        <GeometryDrawing Geometry="M0,0.1 L0.1,0 1,0.9, 0.9,1z"
          Brush="Gray" />
        <GeometryDrawing Geometry="M0.9,0 L1,0.1 0.1,1 0,0.9z"
          Brush="Gray" />
        <GeometryDrawing Geometry="M0.25,0.25 L0.5,0.125 0.75,0.25 0.5,0.5z"
          Brush="#FFFF00" />
        <GeometryDrawing Geometry="M0.25,0.75 L0.5,0.875 0.75,0.75 0.5,0.5z"
          Brush="Black" />
        <GeometryDrawing Geometry="M0.25,0.75 L0.125,0.5 0.25,0.25 0.5,0.5z"
          Brush="#FF0000" />
        <GeometryDrawing Geometry="M0.75,0.25 L0.875,0.5 0.75,0.75 0.5,0.5z"
          Brush="MediumBlue" />
      </DrawingGroup.Children>
    </DrawingGroup>
  </DrawingBrush.Drawing>
</DrawingBrush>
DiffuseMaterial side5Material = new DiffuseMaterial((Brush)Application.Current.Resources["patternBrush"]);
Dim side5Material As New DiffuseMaterial(CType(Application.Current.Resources("patternBrush"), Brush))

Beleuchten der Szene

Lichter in 3D-Grafiken verhalten sich genauso wie Lichter in der realen Welt: Sie beleuchten Oberflächen. Genauer gesagt bestimmen Lichter, welcher Teil einer Szene auch Teil der Projektion ist. Helle Objekte in WPF erzeugen eine Vielzahl von Licht- und Schatteneffekten und werden nach dem Verhalten verschiedener realer Lichter modelliert. Nehmen Sie mindestens ein Licht in Ihre Szene auf, andernfalls sind keine Modelle sichtbar.

Die folgenden Lichter leiten sich von der Basisklasse Light her:

  • AmbientLight: Bietet Umgebungslicht, das alle Objekte gleichmäßig beleuchtet, unabhängig von ihrer Position oder Ausrichtung.

  • DirectionalLight: Leuchtet wie eine entfernte Lichtquelle. Diffuse Lichter haben Direction, als Vector3D spezifiziert, aber keine bestimmte Position.

  • PointLight: Leuchtet wie eine Lichtquelle in der Nähe. PointLights verfügen über eine Position und senden Licht von dieser Position aus. Objekte in der Szene werden je nach deren Position und Abstand von der Lichtquelle beleuchtet. PointLightBase zeigt eine Range-Eigenschaft an, die eine Entfernung festlegt, über die hinaus Modelle nicht von der Lichtquelle beleuchtet werden. PointLight macht außerdem Lichtabnahmeeigenschaften verfügbar, die bestimmen, wie die Lichtintensität mit der Entfernung abnimmt. Sie können die konstante, lineare oder quadratische Interpolationen für die Lichtabnahme angeben.

  • SpotLight: Erbt von PointLight. Scheinwerfer beleuchten wie PointLight und weisen sowohl eine Position als auch eine Richtung auf. Sie projizieren Licht in einen kegelförmigen Bereich, festgelegt durch InnerConeAngle- und OuterConeAngle-Eigenschaften, angegeben in Grad.

Lichter sind Model3D-Objekte. Sie können Lichteigenschaften daher transformieren und animieren, einschließlich der Position, der Farbe, der Richtung und des Bereichs.

<ModelVisual3D.Content>
    <AmbientLight Color="#333333" />
</ModelVisual3D.Content>
DirectionalLight myDirLight = new DirectionalLight();
Private myDirLight As New DirectionalLight()
myDirLight.Color = Colors.White;
myDirLight.Direction = new Vector3D(-3, -4, -5);
myDirLight.Color = Colors.White
myDirLight.Direction = New Vector3D(-3, -4, -5)
modelGroup.Children.Add(myDirLight);
modelGroup.Children.Add(myDirLight)

Transformieren von Modellen

Wenn Sie Modelle erstellen, verfügen diese über eine bestimmte Position in der Szene. Um die Position dieser Modelle in der Szene zu verändern, sie zu drehen oder ihre Größe zu ändern, sollten Sie nicht die Vertices ändern, die die Modelle selbst definieren. Wenden Sie stattdessen wie in 2D-Modellen Transformationen auf Modelle an.

Jedes Modellobjekt hat eine Transform-Eigenschaft, mit der Sie das Modell verschieben, neu ausrichten oder in der Größe verändern können. Wenn Sie eine Transformation anwenden, versetzen Sie alle Punkte des Modells durch den in der Transformation angegebenen Vektor oder Wert. Sie haben also den Koordinatenbereich transformiert, in dem das Modell definiert ist (Modellraum), aber Sie haben noch nicht die Werte geändert, die die Geometrie des Modells im Koordinatensystem der gesamten Szene („Weltenraum“) ausmachen.

Weitere Informationen zum Transformieren von Modellen finden Sie unter Übersicht über 3D-Transformationen.

Animieren von Modellen

Die 3D-Implementierung von WPF gehört dem gleichen Zeitsteuerungs- und Animationssystem an wie die 2D-Grafiken. Das heißt, dass Sie die Eigenschaften von dessen Modellen animieren müssen, um eine 3D-Szene zu animieren. Es ist möglich, die Eigenschaften von primitiven Typen direkt zu animieren. In der Regel ist es aber einfacher, Transformationen zu animieren, die die Position oder die Darstellung von Modellen ändern. Da Transformationen auf Model3DGroup-Objekte und auf einzelne Modelle angewendet werden können, ist es möglich, einen Satz von Animationen auf untergeordneten Elemente einer Model3DGroup und einen weiteren Satz von Animationen auf eine Gruppe von untergeordneten Objekten anzuwenden. Sie können eine Vielzahl von visuellen Effekten erzielen, indem Sie die Eigenschaften der Beleuchtung Ihrer Szene animieren. Schließlich können Sie ggf. die Projektion selbst animieren, indem Sie die Kameraposition oder das Sichtfeld animieren. Hintergrundinformationen zum Zeitsteuerungs- und Animationssystem von WPF finden Sie in den Themen Übersicht über Animationen, Übersicht über Storyboards und Übersicht über Freezable-Objekte.

Um ein Objekt in WPF zu animieren, erstellen Sie eine Zeitachse, definieren Sie eine Animation (die im Zeitablauf eine tatsächliche Änderung einiger Eigenschaftswerte darstellt) und geben Sie die Eigenschaft an, auf die die Animation angewendet werden soll. Da alle Objekte in einer 3D-Szene untergeordnete Elemente von Viewport3D sind, handelt es sich bei den Eigenschaften, an die sich alle Animationen richten, die Sie auf die Szene anwenden möchten, um Eigenschaften von Viewport3D.

Angenommen, ein Modell soll an seiner Position als wackelnd angezeigt werden. Sie können dazu RotateTransform3D auf das Modell anwenden und dessen Rotationsachse von einem Vektor zu einem anderen animieren. Das folgende Codebeispiel veranschaulicht die Anwendung einer Vector3DAnimation auf die Achseneigenschaft der Rotation3D-Klasse der Transformation unter der Annahme, dass RotateTransform3D eine der vielen Transformationen darstellt, die auf das Modell mit TransformGroup angewendet werden.

//Define a rotation
RotateTransform3D myRotateTransform = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 1));
'Define a rotation
Dim myRotateTransform As New RotateTransform3D(New AxisAngleRotation3D(New Vector3D(0, 1, 0), 1))
Vector3DAnimation myVectorAnimation = new Vector3DAnimation(new Vector3D(-1, -1, -1), new Duration(TimeSpan.FromMilliseconds(5000)));
myVectorAnimation.RepeatBehavior = RepeatBehavior.Forever;
Dim myVectorAnimation As New Vector3DAnimation(New Vector3D(-1, -1, -1), New Duration(TimeSpan.FromMilliseconds(5000)))
myVectorAnimation.RepeatBehavior = RepeatBehavior.Forever
myRotateTransform.Rotation.BeginAnimation(AxisAngleRotation3D.AxisProperty, myVectorAnimation);
myRotateTransform.Rotation.BeginAnimation(AxisAngleRotation3D.AxisProperty, myVectorAnimation)
//Add transformation to the model
cube1TransformGroup.Children.Add(myRotateTransform);
'Add transformation to the model
cube1TransformGroup.Children.Add(myRotateTransform)

Hinzufügen von 3D-Inhalt zum Fenster

Um die Szene zu rendern, fügen Sie Modelle und Lichter zu Model3DGroup hinzu und legen Sie dann Model3DGroup als Content von ModelVisual3D fest. Fügen Sie ModelVisual3D zur Children-Auflistung von Viewport3D hinzu. Fügen Sie Kameras zu Viewport3D hinzu, indem Sie die entsprechende Camera-Eigenschaft festlegen.

Fügen Sie schließlich Viewport3D zum Fenster hinzu. Wenn Viewport3D als Inhalt eines Layoutelements wie Canvas enthalten ist, geben Sie die Größe von Viewport3D an, indem Sie entsprechende Height- und Width-Eigenschaften festlegen (geerbt von FrameworkElement).

<UserControl x:Class="HostingWpfUserControlInWf.UserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    >
  
    <Grid>

      <!-- Place a Label control at the top of the view. -->
      <Label 
                HorizontalAlignment="Center" 
                TextBlock.TextAlignment="Center" 
                FontSize="20" 
                Foreground="Red" 
                Content="Model: Cone"/>

      <!-- Viewport3D is the rendering surface. -->
      <Viewport3D Name="myViewport" >

        <!-- Add a camera. -->
        <Viewport3D.Camera>
          <PerspectiveCamera 
                        FarPlaneDistance="20" 
                        LookDirection="0,0,1" 
                        UpDirection="0,1,0" 
                        NearPlaneDistance="1" 
                        Position="0,0,-3" 
                        FieldOfView="45" />
        </Viewport3D.Camera>

        <!-- Add models. -->
        <Viewport3D.Children>

          <ModelVisual3D>
            <ModelVisual3D.Content>

              <Model3DGroup >
                <Model3DGroup.Children>

                  <!-- Lights, MeshGeometry3D and DiffuseMaterial objects are added to the ModelVisual3D. -->
                  <DirectionalLight Color="#FFFFFFFF" Direction="3,-4,5" />

                  <!-- Define a red cone. -->
                  <GeometryModel3D>

                    <GeometryModel3D.Geometry>
                      <MeshGeometry3D 
    Positions="0.293893 -0.5 0.404509  0.475528 -0.5 0.154509  0 0.5 0  0.475528 -0.5 0.154509  0 0.5 0  0 0.5 0  0.475528 -0.5 0.154509  0.475528 -0.5 -0.154509  0 0.5 0  0.475528 -0.5 -0.154509  0 0.5 0  0 0.5 0  0.475528 -0.5 -0.154509  0.293893 -0.5 -0.404509  0 0.5 0  0.293893 -0.5 -0.404509  0 0.5 0  0 0.5 0  0.293893 -0.5 -0.404509  0 -0.5 -0.5  0 0.5 0  0 -0.5 -0.5  0 0.5 0  0 0.5 0  0 -0.5 -0.5  -0.293893 -0.5 -0.404509  0 0.5 0  -0.293893 -0.5 -0.404509  0 0.5 0  0 0.5 0  -0.293893 -0.5 -0.404509  -0.475528 -0.5 -0.154509  0 0.5 0  -0.475528 -0.5 -0.154509  0 0.5 0  0 0.5 0  -0.475528 -0.5 -0.154509  -0.475528 -0.5 0.154509  0 0.5 0  -0.475528 -0.5 0.154509  0 0.5 0  0 0.5 0  -0.475528 -0.5 0.154509  -0.293892 -0.5 0.404509  0 0.5 0  -0.293892 -0.5 0.404509  0 0.5 0  0 0.5 0  -0.293892 -0.5 0.404509  0 -0.5 0.5  0 0.5 0  0 -0.5 0.5  0 0.5 0  0 0.5 0  0 -0.5 0.5  0.293893 -0.5 0.404509  0 0.5 0  0.293893 -0.5 0.404509  0 0.5 0  0 0.5 0  " 
    Normals="0.7236065,0.4472139,0.5257313  0.2763934,0.4472138,0.8506507  0.5308242,0.4294462,0.7306172  0.2763934,0.4472138,0.8506507  0,0.4294458,0.9030925  0.5308242,0.4294462,0.7306172  0.2763934,0.4472138,0.8506507  -0.2763934,0.4472138,0.8506507  0,0.4294458,0.9030925  -0.2763934,0.4472138,0.8506507  -0.5308242,0.4294462,0.7306172  0,0.4294458,0.9030925  -0.2763934,0.4472138,0.8506507  -0.7236065,0.4472139,0.5257313  -0.5308242,0.4294462,0.7306172  -0.7236065,0.4472139,0.5257313  -0.858892,0.429446,0.279071  -0.5308242,0.4294462,0.7306172  -0.7236065,0.4472139,0.5257313  -0.8944269,0.4472139,0  -0.858892,0.429446,0.279071  -0.8944269,0.4472139,0  -0.858892,0.429446,-0.279071  -0.858892,0.429446,0.279071  -0.8944269,0.4472139,0  -0.7236065,0.4472139,-0.5257313  -0.858892,0.429446,-0.279071  -0.7236065,0.4472139,-0.5257313  -0.5308242,0.4294462,-0.7306172  -0.858892,0.429446,-0.279071  -0.7236065,0.4472139,-0.5257313  -0.2763934,0.4472138,-0.8506507  -0.5308242,0.4294462,-0.7306172  -0.2763934,0.4472138,-0.8506507  0,0.4294458,-0.9030925  -0.5308242,0.4294462,-0.7306172  -0.2763934,0.4472138,-0.8506507  0.2763934,0.4472138,-0.8506507  0,0.4294458,-0.9030925  0.2763934,0.4472138,-0.8506507  0.5308249,0.4294459,-0.7306169  0,0.4294458,-0.9030925  0.2763934,0.4472138,-0.8506507  0.7236068,0.4472141,-0.5257306  0.5308249,0.4294459,-0.7306169  0.7236068,0.4472141,-0.5257306  0.8588922,0.4294461,-0.27907  0.5308249,0.4294459,-0.7306169  0.7236068,0.4472141,-0.5257306  0.8944269,0.4472139,0  0.8588922,0.4294461,-0.27907  0.8944269,0.4472139,0  0.858892,0.429446,0.279071  0.8588922,0.4294461,-0.27907  0.8944269,0.4472139,0  0.7236065,0.4472139,0.5257313  0.858892,0.429446,0.279071  0.7236065,0.4472139,0.5257313  0.5308242,0.4294462,0.7306172  0.858892,0.429446,0.279071  "                   TriangleIndices="0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 " />
                    </GeometryModel3D.Geometry>

                    <GeometryModel3D.Material>
                      <DiffuseMaterial>
                        <DiffuseMaterial.Brush>
                          <SolidColorBrush 
                            Color="Red" 
                            Opacity="1.0"/>
                        </DiffuseMaterial.Brush>
                      </DiffuseMaterial>
                    </GeometryModel3D.Material>

                  </GeometryModel3D>

                </Model3DGroup.Children>
              </Model3DGroup>

            </ModelVisual3D.Content>

          </ModelVisual3D>

        </Viewport3D.Children>

      </Viewport3D>
    </Grid>
  
</UserControl>

Siehe auch