Jedną z ciekawszych funkcjonalności WPF jest wsparcie dla grafiki trójwymiarowej. Funkcjonalności 3D są dostępne zarówno z poziomu XAML jak i kodu proceduralnego. Poniższy kod przedstawia prosty sposób opisu sceny 3D w sposób deklaratywny:
<Window x:Class="_3dGraphics.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Viewport3D>
<Viewport3D.Camera>
<OrthographicCamera Position="5,5,5" LookDirection="-1,-1,-1" Width="5"/>
</Viewport3D.Camera>
<Viewport3D.Children>
<ModelVisual3D x:Name="Light">
<ModelVisual3D.Content>
<AmbientLight/>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup x:Name="House">
<GeometryModel3D x:Name="Roof">
<GeometryModel3D.Material>
<DiffuseMaterial Brush="Blue"/>
</GeometryModel3D.Material>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="-1,1,1 0,2,1 0,2,-1 -1,1,-1 0,2,1 1,1,1
1,1,-1 0,2,-1"
TriangleIndices="0 1 2 0 2 3 4 5 6 4 6 7"/>
</GeometryModel3D.Geometry>
</GeometryModel3D>
<GeometryModel3D x:Name="Sides">
<GeometryModel3D.Material>
<DiffuseMaterial Brush="Green"/>
</GeometryModel3D.Material>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="-1,1,1 -1,1,-1 -1,-1,-1 -1,-1,1 1,1,-1
1,1,1 1,-1,1 1,-1,-1"
TriangleIndices="0 1 2 0 2 3 4 5 6 4 6 7"/>
</GeometryModel3D.Geometry>
</GeometryModel3D>
<GeometryModel3D x:Name="Ends">
<GeometryModel3D.Material>
<DiffuseMaterial Brush="Red"/>
</GeometryModel3D.Material>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions="-0.25,0,1 -1,1,1 -1,-1,1 -0.25,-1,1 -0.25,0,1
-1,-1,1 0.25,0,1 1,-1,1 1,1,1 0.25,0,1 0.25,-1,1 1,-1,1
1,1,1 0,2,1 -1,1,1 -1,1,1 -0.25,0,1 0.25,0,1 1,1,1 1,1,-1
1,-1,-1 -1,-1,-1 -1,1,-1 1,1,-1 -1,1,-1 0,2,-1"
TriangleIndices="0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 15
17 18 19 20 21 19 21 22 23 24 25"/>
</GeometryModel3D.Geometry>
</GeometryModel3D>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D.Children>
</Viewport3D>
</Grid>
</Window>
Zastosowane powyżej elementy XAML służą do:
- GeometryModel3D - reprezentuje kształt i materiał obiektu 3D, kształt w powyższym przypadku jest siatką, w której podaje się współrzędne trójkątów oraz ich indeksy.
- ModelVisual3D - odpowiada za renderowanie contentu 3D
Położenie kamery oraz obiektów na scenie podaje się, pamiętając o układzie osi w kartezjańskim układzie współrzędnych.
Układ współrzędnych jest prawoskrętny, a pozycję podaje się ustawiając wartości na atrybucie Position.
Pozostałe ważne atrybuty to LookDirection (kierunek, w którym ma być obrócona kamera), oraz UpDirection decydujący o obrocie kamery wokół osi z.
Rodzaje kamer:
- PerspectiveCamera - odpowiada postrzeganiu przestrzeni przez ludzkie oko, obiekty znajdujące się daleko od kamery wydają się mniejsze, niż te bliższe
- OrthographicCamera - obiekty pozostają tej samej wielkości niezależnie od odległości
Szerokość pola widzenia kontrolowana jest przez atrybut Width (dla drugiej kamery) i przez atrybut FieldOfView (dla pierwszej kamery).
Transformacje 3D:
Poniżej przedstawiono, jak wykonać trzy podstawowe transformacje z poziomu kodu proceduralnego
private void KeyDownHandler(object sender, KeyEventArgs e)
{
Transform3DGroup group = new Transform3DGroup();
switch (e.Key)
{
case Key.T:
TranslateTransform3D transform3D = new TranslateTransform3D(0.1,0,0);
group.Children.Add(transform3D);
House.Transform = group;
break;
case Key.R:
//45 - stopnie, nie radiany, new Vector3D(0, 1, 0) - wokol jakiej osi obrot
RotateTransform3D rotate3d = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 45));
group.Children.Add(rotate3d);
House.Transform = group;
break;
case Key.S:
ScaleTransform3D scale3d = new ScaleTransform3D(0.5,0.5,1);
group.Children.Add(scale3d);
House.Transform = group;
break;
default:
break;
}
}
Rodzaje świateł:
- DirectionalLight - wysyła równoległe wiązki światła ze źródła umieszczonego nieskończenie daleko, odpowiada słońcu
- PointLight - odpowiada żarówce, wysyła światło we wszystkich kierunkach, intensywność spada wraz ze wzrostem odległości od źródła
- FlashLight - odpowiada działaniu latarki, emituje stożek światła, którego intensywność spada wraz ze wzrostem odległości od źródła
- AmbientLight - światło rozproszone