8.3D Grafika II.
Navážeme na předchozí díl, kde jsme implementovali trojrozměrnou krychli, ze které nyní vytvoříme interaktivní objekt.
Co přesně budeme dělat? Vytvoříme video přehrávač, video se bude vykreslovat na přední stranu krychle a na horní stranu krychle vložíme dvě tlačítka pro ovládání videa - play a pause. Zdá se vám to nemožné? Čtěte dál...
Implementace krychle z minulého dílu
Window1.xaml
<Window x:Class="WPF3D.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Tools3D="clr-namespace:_3DTools;assembly=3DTools"
Title="WPF3D" Height="300" Width="300">
<Tools3D:TrackballDecorator>
<Viewport3D Name="myViewport3D">
<Viewport3D.Camera>
<PerspectiveCamera LookDirection="0,0,-1" Position="0,0,5"
NearPlaneDistance="3" FarPlaneDistance="100" />
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<AmbientLight Color="#AA0000" />
<DirectionalLight Color="White" Direction="0.2,0.5,-1" />
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Tools3D:TrackballDecorator>
</Window>
Window1.xaml.cs
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Controls;
namespace WPF3D
{
public partial class Window1 : System.Windows.Window
{
public Window1()
{
InitializeComponent();
Model3DGroup models = new Model3DGroup();
Point3D p0 = new Point3D(-1, -1, -1);
Point3D p1 = new Point3D(1, -1, -1);
Point3D p2 = new Point3D(1, -1, 1);
Point3D p3 = new Point3D(-1, -1, 1);
Point3D p4 = new Point3D(-1, 1, -1);
Point3D p5 = new Point3D(1, 1, -1);
Point3D p6 = new Point3D(1, 1, 1);
Point3D p7 = new Point3D(-1, 1, 1);
models.Children.Add(CreateRectangle(p3, p2, p6, p7, Brushes.Red)); // front
models.Children.Add(CreateRectangle(p2, p1, p5, p6, Brushes.Red)); // right
models.Children.Add(CreateRectangle(p1, p0, p4, p5, Brushes.Red)); // back
models.Children.Add(CreateRectangle(p0, p3, p7, p4, Brushes.Red)); // left
models.Children.Add(CreateRectangle(p7, p6, p5, p4, Brushes.Red)); // top
models.Children.Add(CreateRectangle(p2, p3, p0, p1, Brushes.Red)); // bottom
ModelVisual3D visual = new ModelVisual3D();
visual.Content = models;
myViewport3D.Children.Add(visual);
}
public GeometryModel3D CreateRectangle(
Point3D point1, Point3D point2,
Point3D point3, Point3D point4, Brush brush)
{
MeshGeometry3D mesh = new MeshGeometry3D();
mesh.Positions.Add(point1);
mesh.Positions.Add(point2);
mesh.Positions.Add(point3);
mesh.Positions.Add(point4);
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(1);
mesh.TriangleIndices.Add(2);
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(2);
mesh.TriangleIndices.Add(3);
return new GeometryModel3D(mesh,
new DiffuseMaterial(brush));
}
}
}
V projektu jsme použili knihovnu 3D Tools for WPF [ ^].
Video
Vložení videa do projektu
pravým tlačítkem myši klikněte v Solution Exploreru na "WPF3D" projekt > Add > Existing Item > .. a vyberte jakýkoliv video soubor, který chcete přehrávat
... dále musíme nastavit kopírování souboru:
levým kliknout na video soubor v Solution Exploreru > ve vlastnostech (properties) nastavit "Copy To Output Directory" na hodnotu "Copy always"
Přehrávání videa
Pro práci s videem máme ve WPF k dispozici třídu MediaPlayer
MediaPlayer player = new MediaPlayer();
player.Open(new Uri(@"myVideo.wmv", UriKind.Relative));
Vytvoření textury z videa
Jak vykreslit video na mesh? Nejdříve musíme z videa udělat Brush, ze kterého již můžeme vytvořit texturu.
Co je Brush? Jedná se o výplň typu ...
- barva (SolidColorBrush)
- lineární gradient (LinearGradientBrush)
- radiální gradient (RadialGradientBrush)
- obrázek (ImageBrush)
- kontroly (VisualBrush) - vykreslí se vzhled kontrol
- prvky typu Drawing jako jsou text, video ,obrázky a další... (DrawingBrush)
Pomocí třídy VideoDrawing uděláme z videa Brush
VideoDrawing vd = new VideoDrawing();
vd.Player = player;
vd.Rect = new Rect(0, 0, 100, 100);
vd.Player.Play();
DrawingBrush db = new DrawingBrush(vd);
Brush videoBrush = (Brush)db;
A nyní to vše spojíme dohromady
Window1.xaml.cs
public partial class Window1 : System.Windows.Window
{
MediaPlayer mp;
public Window1()
{
InitializeComponent();
// Video
mp = new MediaPlayer();
mp.Open(new Uri(@"myVideo.wmv", UriKind.Relative));
VideoDrawing vd = new VideoDrawing();
vd.Player = mp;
vd.Rect = new Rect(0, 0, 100, 100);
vd.Player.Play();
DrawingBrush db = new DrawingBrush(vd);
Brush videoBrush = (Brush)db;
// Model
Model3DGroup models = new Model3DGroup();
Point3D p0 = new Point3D(-1, -1, -1);
Point3D p1 = new Point3D(1, -1, -1);
Point3D p2 = new Point3D(1, -1, 1);
Point3D p3 = new Point3D(-1, -1, 1);
Point3D p4 = new Point3D(-1, 1, -1);
Point3D p5 = new Point3D(1, 1, -1);
Point3D p6 = new Point3D(1, 1, 1);
Point3D p7 = new Point3D(-1, 1, 1);
models.Children.Add(CreateRectangle(p3, p2, p6, p7, videoBrush)); // front
models.Children.Add(CreateRectangle(p2, p1, p5, p6, Brushes.Red)); // right
models.Children.Add(CreateRectangle(p1, p0, p4, p5, Brushes.Red)); // back
models.Children.Add(CreateRectangle(p0, p3, p7, p4, Brushes.Red)); // left
models.Children.Add(CreateRectangle(p7, p6, p5, p4, Brushes.Red)); // top
models.Children.Add(CreateRectangle(p2, p3, p0, p1, Brushes.Red)); // bottom
ModelVisual3D visual = new ModelVisual3D();
visual.Content = models;
myViewport3D.Children.Add(visual);
}
public GeometryModel3D CreateRectangle(Point3D point1, Point3D point2,
Point3D point3, Point3D point4, Brush brush)
{
MeshGeometry3D mesh = new MeshGeometry3D();
mesh.Positions.Add(point1);
mesh.Positions.Add(point2);
mesh.Positions.Add(point3);
mesh.Positions.Add(point4);
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(1);
mesh.TriangleIndices.Add(2);
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(2);
mesh.TriangleIndices.Add(3);
mesh.TextureCoordinates.Add(new Point(0, 1));
mesh.TextureCoordinates.Add(new Point(1, 1));
mesh.TextureCoordinates.Add(new Point(1, 0));
mesh.TextureCoordinates.Add(new Point(0, 0));
return new GeometryModel3D(mesh, new DiffuseMaterial(brush));
}
}
- Abychom mohli pracovat s videem, vytvořili jsme MediaPlayer
- Video jsme zkonvertovali přes MediaPlayer > VideoDrawing > DrawingBrush > Brush, abychom ho mohli použít jako texturu
- Protože nyní jako texturu používáme video, musíme při vytváření mesh určit TextureCoordinates (pole bodů, podle kterých je textura mapována na mesh)
A takto vypadá naše aplikace nyní ...
2D kontroly ve 3D?
Většinou když vytváříme aplikaci, používáme různé 2D kontroly jako jsou tlačítka, textová pole, labely a další prvky. Co kdybychom ale chtěli zobrazit tyto kontroly v prostoru, jde to? Ano, lze je použít jako texturu, ale bude se jednat pouze o ne-interaktivní zobrazení! ... na tlačítka nepůjde kliknout, do textboxů nepůjde zadávat text, bude se v podstatě jednat pouze o obrázky těchto kontrol.
Od verze WPF 3.5 máme ale možnost zobrazit 2D kontroly v 3D prostoru a přitom zachovat jejich funkčnost, slouží k tomu nová třída Viewport2DVisual3D.
Interaktivní zobrazení 2D prvků ve 3D prostoru je podporováno až od verze WPF 3.5. V předchozí verzi WPF 3.0 zde nativní podpora chybí, ale můžeme použít knihovnu 3D Tools for WPF, která podporuje interaktivní zobrazení 2D prvků v prostoru.
Příklad: Vytvoříme dvě tlačítka ( play a pause), kterými budeme ovládat video. Tyto tlačítka budou zobrazeny na vrchní straně krychle.
Implementace
Pokud chceme použít 2D kontroly na 3D mesh, musíme ...
- Vytvořit 2D kontrolu, kterou budeme chtít zobrazit na vrchní stranu krychle
- Vytvořit objekt material typu DiffuseMaterial a povolit Viewport2DVisual3D.SetIsVisualHostMaterial()
- Inicializovat objekt typu Viewport2DVisual3D, což je náš interaktivní 3D visual
- do interactiveVisual.Material přiřadit material
- do interactiveVisual.Visual vložit 2D kontrolu, která se na mesh má vyrenderovat
- do interactiveVisual.Geometry přiřadit mesh, na který se 2D kontrola vykreslí
Window1.xaml
<Window x:Class="WPF3D.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Tools3D="clr-namespace:_3DTools;assembly=3DTools"
Title="WPF3D" Height="300" Width="300">
<Window.Resources>
<Grid x:Key="VideoControl" Background="Red">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Button Grid.Column="0" Grid.Row="1" Click="Play">Play</Button>
<Button Grid.Column="1" Grid.Row="1" Click="Pause">Pause</Button>
</Grid>
</Window.Resources>
<Tools3D:TrackballDecorator>
<Viewport3D Name="myViewport3D">
<Viewport3D.Camera>
<PerspectiveCamera LookDirection="0,0,-1" Position="0,0,5"
NearPlaneDistance="3" FarPlaneDistance="100" />
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<AmbientLight Color="#AA0000" />
<DirectionalLight Color="White" Direction="0.2,0.5,-1" />
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Tools3D:TrackballDecorator>
</Window>
Window1.xaml.cs
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Controls;
using _3DTools;
namespace WPF3D
{
public partial class Window1 : System.Windows.Window
{
MediaPlayer mp;
bool paused = false;
public Window1()
{
InitializeComponent();
// Video
mp = new MediaPlayer();
mp.Open(new Uri(@"myVideo.wmv", UriKind.Relative));
VideoDrawing vd = new VideoDrawing();
vd.Player = mp;
vd.Rect = new Rect(0, 0, 100, 100);
vd.Player.Play();
DrawingBrush db = new DrawingBrush(vd);
Brush videoBrush = (Brush)db;
// Model
Model3DGroup models = new Model3DGroup();
Point3D p0 = new Point3D(-1, -1, -1);
Point3D p1 = new Point3D(1, -1, -1);
Point3D p2 = new Point3D(1, -1, 1);
Point3D p3 = new Point3D(-1, -1, 1);
Point3D p4 = new Point3D(-1, 1, -1);
Point3D p5 = new Point3D(1, 1, -1);
Point3D p6 = new Point3D(1, 1, 1);
Point3D p7 = new Point3D(-1, 1, 1);
models.Children.Add(CreateRectangle(p3, p2, p6, p7, videoBrush)); // front
models.Children.Add(CreateRectangle(p2, p1, p5, p6, Brushes.Red)); // right
models.Children.Add(CreateRectangle(p1, p0, p4, p5, Brushes.Red)); // back
models.Children.Add(CreateRectangle(p0, p3, p7, p4, Brushes.Red)); // left
models.Children.Add(CreateRectangle(p2, p3, p0, p1, Brushes.Red)); // bottom
ModelVisual3D visual = new ModelVisual3D();
visual.Content = models;
myViewport3D.Children.Add(visual);
// top
MeshGeometry3D interactiveMesh;
CreateRectangle(p7, p6, p5, p4, Brushes.Red, out interactiveMesh);
DiffuseMaterial material = new DiffuseMaterial();
Viewport2DVisual3D.SetIsVisualHostMaterial(material, true);
Viewport2DVisual3D interactiveVisual = new Viewport2DVisual3D();
interactiveVisual.Material = material;
interactiveVisual.Geometry = interactiveMesh;
interactiveVisual.Visual = (Visual)FindResource("VideoControl");
myViewport3D.Children.Add(interactiveVisual);
}
void Play(object sender, RoutedEventArgs e)
{
mp.Stop();
mp.Play();
paused = false;
}
void Pause(object sender, RoutedEventArgs e)
{
if (paused) { mp.Play(); paused = false; }
else { mp.Pause(); paused = true; }
}
public GeometryModel3D CreateRectangle(
Point3D point1, Point3D point2,
Point3D point3, Point3D point4,
Brush brush)
{
MeshGeometry3D mesh;
return CreateRectangle(point1,point2,point3,point4,brush,out mesh);
}
public GeometryModel3D CreateRectangle(
Point3D point1, Point3D point2,
Point3D point3, Point3D point4,
Brush brush, out MeshGeometry3D mesh)
{
mesh = new MeshGeometry3D();
mesh.Positions.Add(point1);
mesh.Positions.Add(point2);
mesh.Positions.Add(point3);
mesh.Positions.Add(point4);
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(1);
mesh.TriangleIndices.Add(2);
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(2);
mesh.TriangleIndices.Add(3);
mesh.TextureCoordinates.Add(new Point(0, 1));
mesh.TextureCoordinates.Add(new Point(1, 1));
mesh.TextureCoordinates.Add(new Point(1, 0));
mesh.TextureCoordinates.Add(new Point(0, 0));
return new GeometryModel3D(mesh,
new DiffuseMaterial(brush));
}
}
}

Ukázka 3D přehrávače
Závěr
3D ve WPF není určeno pro vývoj složitých 3D scén nebo her, slouží spíše pro vytváření trojrozměrných efektů nebo jednoduchých aplikací. Pro pokročilejší práci s trojrozměrnou grafikou máme k dispozici Direct3D, které pokud potřebujeme můžeme ve WPF také použít.
Komentáře
Martin Pham
6/26/2010 1:29:17 PM
Ales Sturala
8/3/2010 10:58:10 AM
| Vaše jméno |
|
| Vaše webová stránka |
|
|
|
| Povolené tagy jsou [code=C#]...[/code] pro zvýraznění C# kódu a [code=XML]...[/code] pro XML a XAML |
|
|