Übersicht über 3D-Grafiken
Mit der 3-D-Funktion in Windows Presentation Foundation (WPF) können Entwickler 3D-Grafiken in Markup und in prozeduralem Code zeichnen, transformieren und animieren. 2-D- und 3-D-Grafiken können dabei kombiniert werden, um umfangreiche Steuerelemente zu erstellen, komplexe Datenabbildungen bereitzustellen oder die Benutzerfreundlichkeit einer Anwendungsbenutzeroberfläche zu verbessern. Die 3-D-Funktionalität in WPF unterstützt nicht den vollen Funktionsumfang einer Entwicklungsplattform für Spiele. Dieses Thema enthält eine Übersicht über die 3-D-Funktionalität im WPF-Grafiksystem.
Dieses Thema enthält folgende Abschnitte.
- 3D in einem 2D-Container
- 3D-Koordinatenraum
- Kameras und Projektionen
- Modell und Gitterprimitive
- Anwenden von Materialien auf ein Modell
- Beleuchten der Szene
- Transformieren von Modellen
- Animieren von Modellen
- Hinzufügen von 3D-Inhalt zum Fenster
- Verwandte Abschnitte
3D in einem 2D-Container
3-D-Grafikinhalte in WPF sind gekapselt in ein Element, Viewport3D, das in die zweidimensionale Elementstruktur eingebunden werden kann. Das Grafiksystem behandelt Viewport3D in WPF wie viele andere Elemente als zweidimensionales visuelles Element. Viewport3D funktioniert als Fenster (Viewport) in eine dreidimensionale Szene. Genauer gesagt, handelt es sich hierbei um die Oberfläche, auf der eine 3-D-Szene projiziert wird.
In einer konventionellen 2-D-Anwendung verwenden Sie Viewport3D so wie jedes andere Containerelement, z. B. wie Raster oder Canvas. Auch wenn Sie Viewport3D mit anderen 2-D-Zeichnungsobjekten in demselben Szenendiagramm verwenden können, dürfen sich 2-D-Objekte und 3-D-Objekte in einem Viewport3D nicht überschneiden. Dieses Thema beschreibt schwerpunktmäßig, wie 3-D-Grafiken im Viewport3D gezeichnet werden.
3D-Koordinatenraum
Das WPF-Koordinatensystem für 2-D-Grafiken ordnet den Ursprung in der oberen linken Ecke des Renderingbereichs (in der Regel der Bildschirm) an. Im 2-D-System verlaufen die positiven Werte der x-Achse nach rechts und die positiven Werte der y-Achse nach unten. Im 3-D-Koordinatensystem befindet sich der Ursprung jedoch in der Mitte des Renderingbereichs. In diesem Fall verlaufen die positiven Werte der x-Achse nach rechts, die positiven Werte der y-Achse aber nach oben und die positiven Werte der z-Achse vom Ursprung nach außen in Richtung des Betrachters.
Herkömmliche Darstellungen von 2D- und 3D-Koordinatensystemen
Der von diesen Achsen definierte Bereich ist der feststehende Verweisrahmen für 3-D-Objekte in WPF. Wenn Sie in diesem Bereich Modelle aufbauen und Lichter und Kameras zur Anzeige der Modelle erstellen, ist es hilfreich, diesen feststehenden Verweisrahmen (auch "Weltkoordinaten" genannt) vom lokalen Verweisrahmen zu unterscheiden, den Sie beim Anwenden von Transformationen für jedes Modell erstellen. Beachten Sie außerdem, dass je nach Licht- und Kameraeinstellung die Objekte innerhalb der Weltkoordinaten eventuell völlig anders oder überhaupt nicht angezeigt werden. Die Position der Kamera verändert hingegen die Position der Objekte innerhalb der Weltkoordinaten nicht.
Kameras und Projektionen
Entwickler, die in 2-D arbeiten, sind mit der Positionierung von Zeichnungsprimitiven in einem zweidimensionalen Bildschirm vertraut. Beim Erstellen einer 3-D-Szene sollten Sie beachten, dass Sie tatsächlich eine 2-D-Darstellung von 3-D-Objekten erstellen. Da sich die Perspektive der 3-D-Szene je nach der Sicht des Betrachters verändert, müssen Sie diese Perspektive angeben. Die Camera-Klasse ermöglicht es Ihnen, diese Perspektive für eine 3-D-Szene festzulegen.
Ein Verständnis dafür, wie eine 3-D-Szene auf einer 2-D-Oberfläche dargestellt wird, lässt sich auch dadurch gewinnen, dass die Szene als Projektion auf der Anzeigeoberfläche beschrieben wird. Mithilfe von ProjectionCamera können Sie unterschiedliche Projektionen und deren Eigenschaften angeben, um das Erscheinungsbild von 3-D-Modellen für Betrachter zu ändern. Ein PerspectiveCamera-Objekt gibt eine Projektion an, die die Szene verkürzt. In anderen Worten: PerspectiveCamera enthält eine Fluchtpunktperspektive. Sie können neben der Kameraposition im Koordinatensystem der Szene auch die Richtung und das Sichtfeld für die Kamera sowie einen Vektor, der die Richtung "nach oben" in der Szene definiert, angeben. Das folgende Diagramm veranschaulicht die PerspectiveCamera-Projektion.
Die Eigenschaften NearPlaneDistance und FarPlaneDistance von ProjectionCamera schränken den Projektionsbereich der Kamera ein. Da Kameras in der Szene beliebig positioniert werden können, ist es möglich, dass sich die Kamera tatsächlich innerhalb eines Modells oder sehr nah an einem Modell befindet, wodurch Objekte nur schwer voneinander unterschieden werden können. Mithilfe von NearPlaneDistance können Sie einen Mindestabstand zur Kamera angeben, jenseits dessen keine Objekte gezeichnet werden. Umgekehrt können Sie mithilfe von FarPlaneDistance einen maximalen Abstand zur Kamera angeben, über den hinaus keine Objekte gezeichnet werden. Dadurch wird sichergestellt, dass Objekte, die aufgrund ihrer Entfernung nicht mehr erkannt werden, nicht Teil der Szene sind.
Kameraposition
OrthographicCamera gibt eine orthogonale Projektion eines 3-D-Modells auf eine visuelle 2-D-Oberfläche an. Wie andere Kameras gibt sie eine Position, Anzeigerichtung und Aufwärtsrichtung an. Im Gegensatz zu PerspectiveCamera beschreibt OrthographicCamera jedoch eine Projektion, die keine Perspektivenverkürzung umfasst. Anders gesagt, beschreibt OrthographicCamera ein Sichtfeld mit parallelen Seiten und kein Sichtfeld, dessen Seiten sich in einem Punkt der Kamera treffen. Das folgende Bild zeigt, wie das gleiche Modell unter Verwendung von PerspectiveCamera und OrthographicCamera angezeigt wird.
Perspektivische und orthographische Projektionen
Im folgenden Code werden einige typische Kameraeinstellungen veranschaulicht.
' 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
// 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;
Modell und Gitterprimitive
Model3D ist die abstrakte Basisklasse, die ein generisches 3-D-Objekt darstellt. Zum Aufbau einer 3-D-Szene benötigen Sie Objekte, die in der Szenengrafik angezeigt werden. Diese Objekte werden aus Model3D abgeleitet. WPF unterstützt derzeit das Modellieren von Geometrien mit GeometryModel3D. Die Geometry-Eigenschaft dieses Modells verwendet eine Gitterprimitive.
Um ein Modell zu erstellen, erstellen Sie zunächst eine Primitive oder ein Netz. Eine 3-D-Primitive ist eine Ansammlung von Eckpunkten, die eine einzelne 3-D-Entität bilden. Die meisten 3-D-Systeme stellen Primitive bereit, deren Modell auf der einfachsten geschlossenen Figur beruht: einem aus drei Eckpunkten definierten Dreieck. Da sich die drei Punkte des Dreiecks auf derselben Ebene befinden, d. h., sie sind koplanar angeordnet, können Sie zum Aufbau komplexerer Formen (Netze genannt) weitere Dreiecke hinzufügen.
Das WPF 3-D-System stellt derzeit die MeshGeometry3D-Klasse zur Verfügung, anhand derer Sie jegliche Geometrie angeben können. Vordefinierte 3-D-Primitive, z. B. Kreise und kubische Formen, werden derzeit nicht unterstützt. Sie erstellen ein MeshGeometry3D-Objekt, indem Sie zunächst eine Liste von Dreieckseckpunkten als Positions-Eigenschaft angeben. Jeder Eckpunkt wird als Point3D angegeben. (In Extensible Application Markup Language (XAML) definieren Sie diese Eigenschaft anhand einer Liste von Nummern, die in Dreiergruppen eingeteilt sind und die Koordinaten der einzelnen Eckpunkte darstellen.) Das Netz kann je nach Geometrie aus mehreren Dreiecken bestehen, von denen einige dieselben Ecken (Eckpunkte) verwenden können. Um das Netz ordnungsgemäß zu zeichnen, benötigt WPF Informationen darüber, welche Eckpunkte von welchen Dreiecken gemeinsam verwendet werden. Sie stellen diese Informationen bereit, indem Sie mit der TriangleIndices-Eigenschaft eine Liste mit Dreieckindizes angeben. Diese Liste definiert die Reihenfolge, in der die in der Positions-Liste angegebenen Punkte ein Dreieck formen.
<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 werden in der Positions-Liste acht Eckpunkte angegeben, um ein Netz in der Form eines Würfels zu definieren. Die TriangleIndices-Eigenschaft enthält eine Liste von zwölf Gruppen mit jeweils drei Indizes. Jede Zahl in der Liste verweist auf einen Offset in der Positions-Liste. Beispiel: Die von der Positions-Liste angegebenen ersten drei Eckpunkte sind (1,1,0), (0,1,0) und (0,0,0). Die ersten drei Indizes in der TriangleIndices-Liste lauten 0, 2 und 1. Sie entsprechen dem ersten, dritten und zweiten Punkt in der Positions-Liste. Aus diesem Grund wird das erste Dreieck des Cube-Modells aus den Eckpunkten (1,1,0) bis (0,1,0) bis (0,0,0) gebildet. Die restlichen elf Dreiecke werden ähnlich bestimmt.
Sie können mit der Modelldefinition fortfahren, indem Sie die Werte für die Eigenschaften Normals und TextureCoordinates angeben. Um die Modelloberfläche rendern zu können, benötigt das Grafiksystem Informationen dazu, in welche Richtung die Oberfläche in jedem gegebenen Dreieck zeigt. Das System verwendet diese Informationen, um die Beleuchtung für das Modell zu berechnen: Oberflächen, die sich direkt einer Lichtquelle zuwenden, werden heller angezeigt als die Oberflächen, die nicht auf das Licht ausgerichtet sind. Obwohl WPF Standard-Normalenvektoren mithilfe der Positionskoordinaten bestimmen kann, können Sie zusätzlich verschiedene Normalenvektoren angeben, um die Darstellung von gekrümmten Oberflächen anzugleichen.
Die TextureCoordinates-Eigenschaft gibt eine Auflistung von Point-Elementen an, anhand derer das Grafiksystem erkennt, wie die Koordinaten zuzuordnen sind. Die Koordinaten bestimmen, wie eine Textur innerhalb der Eckpunkte im Netz gezeichnet wird. Die TextureCoordinates-Eigenschaft wird als Wert zwischen 0 und 1 (einschließlich) angegeben. Das Grafiksystem kann wie bei der Normals-Eigenschaft Standard-Texturkoordinaten berechnen. Sie können jedoch unterschiedliche Texturkoordinaten festlegen, um die Zuordnung einer Textur zu steuern, die z. B. einen Teil eines sich wiederholenden Musters enthält. Weitere Informationen über Texturkoordinaten finden Sie in den nachfolgenden Themen oder im verwalteten Direct3D-SDK.
Das folgende Beispiel zeigt, wie eine Fläche des Cube-Modells in prozeduralem Code erstellt wird. Beachten Sie, dass Sie das gesamte Cube-Modell als ein einzelnes GeometryModel3D-Modell zeichnen können. In diesem Beispiel werden die Flächen in unterschiedlichen Modellen gezeichnet, um später separate Texturen auf die einzelnen Flächen anzuwenden.
Private side1Plane As New MeshGeometry3D()
MeshGeometry3D side1Plane = 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 ein Modell
Damit ein Netz als dreidimensionales Objekt angezeigt wird, muss es über eine Textur verfügen, die die von den Eckpunkten und Dreiecken definierte Oberfläche abdeckt. Auf diese Weise kann es durch die Kamera beleuchtet und projiziert werden. In 2-D verwenden Sie die Brush-Klasse, um auf Bildschirmbereiche Farben, Muster, Farbverläufe oder andere visuelle Inhalte anzuwenden. Die Darstellung von 3-D-Objekten ist jedoch eine Funktion des Beleuchtungsmodells und hängt nicht nur von verwendeten Farben oder Mustern ab. Reale Objekte reflektieren das Licht je nach Oberflächenqualität unterschiedlich: Das Erscheinungsbild glatter und glänzender Oberflächen unterscheidet sich vom Erscheinungsbild der rauen oder matten Oberflächen; und einige Objekte absorbieren das Licht scheinbar, während andere leuchten. Sie können für 3-D-Objekte alle Pinsel anwenden, die Ihnen auch für 2-D-Objekte zur Verfügung stehen. Ein direktes Anwenden ist jedoch nicht möglich.
Um die Eigenschaften einer Modelloberfläche zu definieren, verwendet WPF die abstrakte Material-Klasse. Die konkreten Materialunterklassen bestimmen einige der Darstellungseigenschaften der Modelloberfläche und enthalten jeweils eine Pinseleigenschaft, an die Sie ein SolidColorBrush, TileBrush oder VisualBrush übergeben können.
DiffuseMaterial gibt an, dass der Pinsel auf das Modell so angewendet wird, als wäre das Modell diffus beleuchtet. Die Verwendung von DiffuseMaterial ist meistens gleichzusetzen mit der direkten Verwendung von Pinseln für 2-D-Modelle; Modelloberflächen lassen reflektiertes Licht nicht glänzend erscheinen.
SpecularMaterial gibt an, dass der Pinsel auf das Modell so angewendet wird, als wäre die Modelloberfläche fest oder glänzend und in der Lage, Glanzlichter zu reflektieren. Sie können den Umfang festlegen, in dem die Textur diese Reflexionsqualität (den "Glanz") suggeriert, indem Sie einen Wert für die SpecularPower-Eigenschaft angeben.
Mithilfe von EmissiveMaterial können Sie festlegen, dass die Textur so angewendet wird, als würde das Modell Licht in der Pinselfarbe abgeben. Das Modell wird dadurch nicht zum Licht. Es wird sich jedoch im Shadowing anders verhalten als wenn es mit einer DiffuseMaterial- oder SpecularMaterial-Textur versehen wäre.
Zur Leistungsverbesserung werden die rückwärtigen Seiten von einem GeometryModel3D (die Flächen, die außerhalb des Sichtfensters sind, weil sie sich aus der Perspektive der Kamera auf der gegenüberliegenden Seite des Modells befinden) aus der Szene herausgefiltert. Wenn Sie angeben möchten, dass ein Material auf die rückwärtige Seite eines Modells wie eine Ebene anzuwenden ist, müssen Sie die BackMaterial-Eigenschaft für das Modell festlegen.
Um gewisse Oberflächeneigenschaften zu erzielen, z. B. Leuchten oder reflektierende Effekte, könnten Sie nacheinander unterschiedliche Pinsel auf ein Modell anwenden. Sie können mehrere Materialien anwenden und erneut verwenden, indem Sie die MaterialGroup-Klasse verwenden. Die untergeordneten Elemente von MaterialGroup werden in mehreren Renderingdurchläufen vom ersten bis zum letzten Element angewendet.
Im folgenden Codebeispiel wird veranschaulicht, wie eine Volltonfarbe und eine Zeichnung auf 3-D-Modelle als Pinsel angewendet werden.
<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>
Dim side5Material As New DiffuseMaterial(CType(Application.Current.Resources("patternBrush"), Brush))
DiffuseMaterial side5Material = new DiffuseMaterial((Brush)Application.Current.Resources["patternBrush"]);
Beleuchten der Szene
Lichter in 3-D-Grafiken machen das, was sie auch in der realen Welt machen: Sie sorgen dafür, dass Oberflächen sichtbar werden. Genauer ausgedrückt: Lichter bestimmen, welcher Teil einer Szene in die Projektion eingeschlossen wird. Lichtobjekte in WPF erzeugen eine Vielzahl von Licht- und Schatteneffekten und werden nach dem Verhalten der verschiedenen realen Lichter modelliert. Die Modelle sind nur sichtbar, wenn Sie in der Szene mindestens ein Licht vorsehen.
Die folgenden Lichter werden aus der Light-Basisklasse abgeleitet:
AmbientLight: stellt eine Umgebungsbeleuchtung bereit, die alle Objekte, unabhängig von ihrer Position oder Ausrichtung, gleichmäßig beleuchtet.
DirectionalLight: beleuchtet wie eine entfernte Lichtquelle. Bei gerichteten Lichtern wird eine Direction als Vector3D ohne Positionsangabe festgelegt.
PointLight: beleuchtet wie eine nahe gelegene Lichtquelle. PointLights verfügen über eine Position und strahlen ihr Licht von dieser Position aus. Die in der Szene enthaltenen Objekte werden je nach deren Position und Abstand vom Licht beleuchtet. PointLightBase stellt eine Range-Eigenschaft zur Verfügung, die die Entfernung bestimmt, jenseits derer die Modelle vom Licht nicht beleuchtet werden. PointLight enthält ebenso Dämpfungseigenschaften, die bestimmen, wie sich die Intensität des Lichts mit der Entfernung verringert. Sie können für die Dämpfung des Lichts konstante, lineare oder quadratische Interpolationen angeben.
SpotLight: erbt von PointLight. Scheinwerfer beleuchten wie PointLight (Punktlichter) und verfügen sowohl über eine Position als auch über eine Richtung. Sie projizieren das Licht in einem kegelförmigen Bereich, der von den Eigenschaften InnerConeAngle und OuterConeAngle festgelegt und in Grad angegeben wird.
Lichter sind Model3D-Objekte. Aus diesem Grund können Sie Lichteigenschaften, einschließlich Position, Farbe, Richtung und Bereich, transformieren und animieren.
<ModelVisual3D.Content>
<AmbientLight Color="#333333" />
</ModelVisual3D.Content>
Private myDirLight As New DirectionalLight()
DirectionalLight myDirLight = 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, haben sie eine bestimmte Position in der Szene. Um diese Modelle in der Szene zu verschieben, zu drehen oder um die Größe der Modelle zu ändern, sollten Sie nicht die Eckpunkte ändern, die das Modell selbst definieren. Stattdessen wenden Sie wie in 2-D Transformationen auf die Modelle an.
Jedes Modellobjekt verfügt über 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 gewissermaßen alle Punkte im Modell um den durch die Transformation angegebenen Vektor oder Wert. Mit anderen Worten: Sie haben den Koordinatenraum transformiert, in dem das Modell ("Modellraum") definiert ist. Dabei haben Sie jedoch nicht die Werte geändert, aus denen sich die Geometrie des Modells im Koordinatensystem der gesamten Szene ("Weltkoordinatensystem") zusammensetzt.
Weitere Informationen zum Transformieren von Modellen finden Sie unter Übersicht über 3D-Transformationen.
Animieren von Modellen
Die WPF 3-D-Implementierung gehört zum gleichen Zeitsteuerungs- und Animationssystem wie 2-D-Grafiken. Mit anderen Worten: Zur Animation einer 3D-Szene animieren Sie die Eigenschaften seiner Modelle. Sie können die Eigenschaften von Primitiven direkt animieren. In der Regel ist es jedoch einfacher, die Transformationen zu animieren, anhand derer die Position oder die Darstellung der Modelle geändert werden. Da sich Transformationen sowohl auf Model3DGroup-Objekte als auch auf einzelne Modelle anwenden lassen, können Sie einen Satz von Animationen auf ein untergeordnetes Model3DGroup-Objekt und einen weiteren Satz von Animationen auf eine Gruppe von untergeordneten Objekten anwenden. Sie können auch eine Vielzahl visueller Effekte erzielen, indem Sie die Eigenschaften der Szenenbeleuchtung animieren. Letztendlich können Sie auch die Projektion selbst animieren, indem Sie die Kameraposition oder das Sichtfeld animieren. Hintergrundinformationen über das WPF-Zeitsteuerungs- und -Animationssystem finden Sie unter Übersicht über Animationen, Übersicht über Storyboards und unter Übersicht über Freezable-Objekte.
Um ein Objekt in WPF zu animieren, erstellen Sie eine Zeitachse, definieren eine Animation (tatsächlich eine Änderung einiger Eigenschaftswerte im Zeitablauf) und geben die Eigenschaft an, auf die die Animation angewendet werden soll. Da alle Objekte einer 3-D-Szene untergeordnete Objekte von Viewport3D sind, handelt es sich bei den Eigenschaften, auf die sich die in der Szene anzuwendenden Animationen beziehen, um Eigenschaften von Viewport3D-Eigenschaften.
Angenommen, Sie möchten ein Modell so anzeigen, dass es an einer Position wackelt. Dazu sollten Sie RotateTransform3D auf das Modell anwenden und dessen Rotationsachse von einem Vektor auf einen anderen animieren. Im folgenden Codebeispiel wird das Anwenden einer Vector3DAnimation auf die Achseneigenschaft von Rotation3D der Transformation veranschaulicht. Es wird angenommen, dass RotateTransform3D als eine von mehreren Transformationen mit TransformGroup auf das Modell angewendet wird.
'Define a rotation
Dim myRotateTransform As New RotateTransform3D(New AxisAngleRotation3D(New Vector3D(0, 1, 0), 1))
//Define a rotation
RotateTransform3D myRotateTransform = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 1));
Dim myVectorAnimation As New Vector3DAnimation(New Vector3D(-1, -1, -1), New Duration(TimeSpan.FromMilliseconds(5000)))
myVectorAnimation.RepeatBehavior = RepeatBehavior.Forever
Vector3DAnimation myVectorAnimation = 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 Model3DGroup Modelle und Lichter hinzu. Danach legen Sie Model3DGroup als Content von ModelVisual3D fest. Daraufhin fügen Sie ModelVisual3D der Children-Auflistung von Viewport3D hinzu. Dann fügen Sie Viewport3D Kameras hinzu, indem Sie dessen Camera-Eigenschaft festlegen.
Abschließend fügen Sie Viewport3D dem Fenster hinzu. Wenn Viewport3D als Inhalt eines Layoutelements, z. B. Canvas, hinzugefügt wird, geben Sie die Viewport3D-Größe an, indem Sie dessen Eigenschaften Height und Width festlegen (geerbt von FrameworkElement).
<UserControl x:Class="HostingWpfUserControlInWf.UserControl1"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://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
Referenz
Konzepte
Übersicht über 3D-Transformationen
Maximieren der 3D-Leistung von WPF
Übersicht über Formen und die grundlegenden Funktionen zum Zeichnen in WPF
Zeichnen mit Bildern, Zeichnungen und visuellen Elementen