Last Updated 2011/09/21
3D グラフィックスを実現するには結局のところ、3D モデルをどうやって作るかにかかっています。WPF における 3D モデルは下図を見てのとおり、三角形メッシュの集合体として定義します。

3D モデルを定義するクラスは、MeshGeometry3D クラスですが、少なくとも、その Positions プロパティと TriangleIndices とを設定しなければなりません。立方体程度ならデータを手入力してもたいしたことはありませんが、球体となると計算で作るとしても相当に面倒です。
さて、WPF SDK に含まれるサンプルプロジェクトの「3-D ソリッドのサンプル」の中に、3D モデルを作成するクラスが含まれています。これを利用すればテスト用の 3D モデルぐらいなら作成することは簡単です。
ライブラリ名は、Primitive3DSurfaces.dll で、円錐体(Cone3D)、円筒体(Cylinder3D)、球体(Sphere3D)の 3 種類の 3D モデルに対応していて、それぞれに対応する ModelVisual3D オブジェクトを作成してくれます。
このライブラリを使って、球体の 3D モデルを定義する GeometryModel3D オブジェクトがどれぐらいのデータ数になるのかをテストしてみました。詳しい手順は省略しますが、フォーム内に 3D モデルを表示した状態で、フォーム上をクリックするとデータ数をフォームのタイトルとして表示します。
using System.Windows.Media.Media3D;
private void Window_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
Primitive3DSurfaces.Sphere3D sphere = new Primitive3DSurfaces.Sphere3D();
GeometryModel3D model = sphere.Content as GeometryModel3D;
if (model != null)
{
MeshGeometry3D mesh = model.Geometry as MeshGeometry3D;
if (mesh != null)
{
int positions = mesh.Positions.Count;
int normals = mesh.Normals.Count;
int triangleIndices = mesh.TriangleIndices.Count;
int textureCoordinates = mesh.TextureCoordinates.Count;
Title = String.Format("{0} {1} {2} {3}", positions,normals, triangleIndices, textureCoordinates);
}
}
}
実行結果は、1089 1089 6144 1089 となり、データとして取り出すにはデータが多すぎます。つまり、ModelVisual3D オブジェクトを取り出すことは実務的ではなく、ライブラリをそのまま利用するほかないと思います。以下の XAML コードはライブラリの Sphere3D クラスを使う手順です。

<Window x:Class="SphereTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:Primitive3DSurfaces;assembly=Primitive3DSurfaces"
Title="Sphere3D" Height="300" Width="300">
<StackPanel Orientation="Vertical" Background="Black">
<Viewport3D Width="200" Height="200" Margin="20">
<Viewport3D.Camera>
<PerspectiveCamera Position="0,0,3" UpDirection="0,1,0" LookDirection="0,0,-1" />
</Viewport3D.Camera>
<Viewport3D.Children>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight Color="White" Direction="0,0,-1" />
</ModelVisual3D.Content>
</ModelVisual3D>
<my:Sphere3D>
<my:Sphere3D.Material>
<DiffuseMaterial Brush="Gold" />
</my:Sphere3D.Material>
</my:Sphere3D>
</Viewport3D.Children>
</Viewport3D>
</StackPanel>
</Window>
円錐体、円筒体、球体の 3 種類の 3D モデルを作成するライブラリは前のページで説明しました。ここでは、一般的な 3D モデル作成ツールについて説明します。
3D モデル作成ツールのことを「3D モデラー」などと呼ぶことがあるらしい。
Microsoft から 3D モデルを作成するツールはでていませんが、市販のものならたくさんあります。しかし、ほとんどがプロ向きなので相当に高価です。日本製で無料で入手可能なものとの条件の下に、WEB サイトをあたってみると、有力なものが見つかりました。Metasequoia といいます。
Metasequoia(メタセコイアと読む)はシェアウエア版と無料版とがありますので、まず無料版でテストしてからシェアウエア版(5,000 円)にすすむ手があります。私自身は起動してみた程度なので、評価は難しいですが、評判は悪くないようです。プロで使っている人もいるぐらいですから。ただし、これは WPF 対応の 3D モデル作成ツールではありませんので、これだけでは不十分です。
この問題を解決したのが、Identity という 3D アニメーション作成ツールです。これを使うと、Metasequoia で作成したデータを WPF 対応のデータに変換できるようです。
「変換できるようだ」と書きましたが、私自身はテストしていないという意味です。
以下に、Metasequoia(無料版は Metasequoia LE)と Identity の入手先を示しますので、各自テストしてみてください。
| Metasequoia | http://www.metaseq.net/ |
| Identity | http://vixar.jp/identity/ |
Microsoft から 3D モデルを作成するツールはでていないと書きましたが、3DTools なるものを公開しています。入手先は、「開発ツール」のページに書いておきました。ただし、多くを期待してはいけません。その機能はきわめて限定的です。下図はこのライブラリを利用して作ったものですが、こういう機能はあります。

なお、3DTools は WEB 上で公開されている多くのサンプルプロジェクトで使っていますので、ダウンロードしておいて損はありません。
下図のような立方体の 3D モデルを定義してみましょう。立方体の頂点は 8 あって、6 面あるので、頂点の座標値は MeshGeometory3D オブジェクトの Positions プロに 8 つのデータを設定します。また、三角形メッシュを指定する TriangleIndices プロパティには 12 のデータが必要となります。

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<DockPanel Background="beige">
<Viewport3D Width="300" Height="300">
<Viewport3D.Camera>
<PerspectiveCamera Position="-30,30,30" LookDirection="1,-1,-1 " UpDirection="0,1,0" />
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<DirectionalLight Color="White" Direction="-1,-1,-3" />
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions="0,0,0 10,0,0 10,10,0 0,10,0 0,0,10 10,0,10 10,10,10 0,10,10"
TriangleIndices="0 1 3, 1 2 3, 0 4 3, 4 7 3, 4 6 7, 4 5 6
0 4 1, 1 4 5, 1 2 6, 6 5 1, 2 3 7, 7 6 2"/>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial Brush="Gold" />
</GeometryModel3D.Material>
</GeometryModel3D>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</DockPanel>
</Page>
その1 では立方体の形状を定義しただけで、実用性はとぼしいですね。少なくとも、各面の色を変えるとか、画像を表示するなどをしたいところです。こういう場合は、立方体の 6 面に対して個々に 3D モデルを作成し、それぞれのマテリアルを設定します。以下は、立方体の各面に別々の色を設定したものです。

【注意】以下の [使用例の実行] は、IE(インターネットエクスプローラ)でしか正常に動作しません。
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<MeshGeometry3D x:Key="squareMesh"
Positions="-1,1,1 -1,-1,1 1,-1,1 1,1,1"
TriangleIndices="0 1 2 0 2 3"/>
<GeometryModel3D x:Key="redModel" Geometry="{StaticResource squareMesh}">
<GeometryModel3D.Material>
<DiffuseMaterial Brush="OrangeRed"/>
</GeometryModel3D.Material>
</GeometryModel3D>
<GeometryModel3D x:Key="yellowModel" Geometry="{StaticResource squareMesh}">
<GeometryModel3D.Material>
<DiffuseMaterial Brush="Yellow"/>
</GeometryModel3D.Material>
</GeometryModel3D>
<GeometryModel3D x:Key="blueModel" Geometry="{StaticResource squareMesh}">
<GeometryModel3D.Material>
<DiffuseMaterial Brush="DeepSkyBlue"/>
</GeometryModel3D.Material>
</GeometryModel3D>
<GeometryModel3D x:Key="greenModel" Geometry="{StaticResource squareMesh}">
<GeometryModel3D.Material>
<DiffuseMaterial Brush="LawnGreen"/>
</GeometryModel3D.Material>
</GeometryModel3D>
<GeometryModel3D x:Key="magentaModel" Geometry="{StaticResource squareMesh}">
<GeometryModel3D.Material>
<DiffuseMaterial Brush="Magenta"/>
</GeometryModel3D.Material>
</GeometryModel3D>
</Page.Resources>
<StackPanel Background="DarkSlateBlue">
<Viewport3D Width="400" Height="300">
<Viewport3D.Camera>
<PerspectiveCamera Position="0, 3, 10" LookDirection="0,-3,-10" FieldOfView="30"/>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Children>
<ModelVisual3D>
<ModelVisual3D.Content>
<AmbientLight Color="White"/>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D Content="{StaticResource redModel}"/>
<ModelVisual3D Content="{StaticResource blueModel}">
<ModelVisual3D.Transform>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Angle="90" Axis="0 1 0"/>
</RotateTransform3D.Rotation>
</RotateTransform3D>
</ModelVisual3D.Transform>
</ModelVisual3D>
<ModelVisual3D Content="{StaticResource yellowModel}">
<ModelVisual3D.Transform>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Angle="180" Axis="0 1 0"/>
</RotateTransform3D.Rotation>
</RotateTransform3D>
</ModelVisual3D.Transform>
</ModelVisual3D>
<ModelVisual3D Content="{StaticResource greenModel}">
<ModelVisual3D.Transform>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Angle="-90" Axis="0 1 0"/>
</RotateTransform3D.Rotation>
</RotateTransform3D>
</ModelVisual3D.Transform>
</ModelVisual3D>
<ModelVisual3D Content="{StaticResource greenModel}">
<ModelVisual3D.Transform>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Angle="90" Axis="1 0 0"/>
</RotateTransform3D.Rotation>
</RotateTransform3D>
</ModelVisual3D.Transform>
</ModelVisual3D>
<ModelVisual3D Content="{StaticResource magentaModel}">
<ModelVisual3D.Transform>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Angle="-90" Axis="1 0 0"/>
</RotateTransform3D.Rotation>
</RotateTransform3D>
</ModelVisual3D.Transform>
</ModelVisual3D>
</ModelVisual3D.Children>
<ModelVisual3D.Transform>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D x:Name="rotateTransform" Axis="1,1,0"/>
</RotateTransform3D.Rotation>
</RotateTransform3D>
</ModelVisual3D.Transform>
</ModelVisual3D>
<Viewport3D.Triggers>
<EventTrigger RoutedEvent="Viewport3D.Loaded">
<BeginStoryboard>
<Storyboard >
<DoubleAnimation Storyboard.TargetName="rotateTransform"
Storyboard.TargetProperty="Angle"
RepeatBehavior="Forever" From="0" To="360" Duration="0:0:10" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Viewport3D.Triggers>
</Viewport3D>
</StackPanel>
</Page>
−以上−