ModelVisual3Dによる3Dモデルの階層構築
3Dモデルに階層構造が必要なことがよくあります。たとえば、ビルを街に配置するとき、ビル自身はローカル座標で作成し、座標変換で街の望みの位置に配置します。あるいは、タイヤはローカルに回転しつつ、上の階層である自動車と共に並行移動します。人の手は腕の動きに追従しつつそのまた上位の身体と共に移動します。
WPFのModelVisual3Dを使えばこういった階層を構築できます。ModelVisual3DにはChildrenプロパティがあり、この下にさらにModelVisual3D自身を入れることができるのです。それぞれのModelVisual3DにTransformプロパティがあるので、それぞれローカルな座標変換やアニメーションを適用できます。最上位のModelVisual3Dをシーンとしてグローバルなアニメーションを適用しつつ、その下のModelVisual3Dを個々のパーツとしてそれぞれローカルな座標変換を適用して配置できます。
正方形に赤・緑・青の色を付けて、それぞれローカルに座標変換して立方体を作り、その立方体をグローバルに回転アニメーションさせてみましょう。まず、GeometryModel3Dで赤・緑・青の正方形をリソースとして作ります。
<Page.Resources>
<MeshGeometry3D x:Key="myMesh"
Positions="-1,1,1 -1,-1,1 1,-1,1 1,1,1"
TriangleIndices="0 1 2 0 2 3" />
<GeometryModel3D x:Key="myRedGeom" Geometry="{StaticResource myMesh}" >
<GeometryModel3D.Material>
<DiffuseMaterial Brush="Red" />
</GeometryModel3D.Material>
</GeometryModel3D>
<GeometryModel3D x:Key="myBlueGeom" Geometry="{StaticResource myMesh}" >
<GeometryModel3D.Material>
<DiffuseMaterial Brush="Blue" />
</GeometryModel3D.Material>
</GeometryModel3D>
<GeometryModel3D x:Key="myGreenGeom" Geometry="{StaticResource myMesh}" >
<GeometryModel3D.Material>
<DiffuseMaterial Brush="Green" />
</GeometryModel3D.Material>
</GeometryModel3D>
</Page.Resources>
カメラとライトを定義した後で、グローバルシーン用のModelVisual3DとローカルModelVisual3Dを定義します。6枚の正方形から立方体を作りたいので、先ほど作ったGeometryModel3Dを使って、左右に+/-90度と180度、上下に+/-90度の回転をローカルな座標変換として適用します。
<!--グローバル シーン-->
<ModelVisual3D>
<ModelVisual3D.Children>
<!-- ローカル モデル 1-->
<ModelVisual3D Content="{StaticResource myRedGeom}" />
<!-- ローカル モデル 2-->
<ModelVisual3D Content="{StaticResource myBlueGeom}" >
<ModelVisual3D.Transform>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Angle="90" Axis="0 1 0" />
</RotateTransform3D.Rotation>
</RotateTransform3D>
</ModelVisual3D.Transform>
</ModelVisual3D>
.....
ここで、<ModelVisual3D.Children>タグを入れいていますが、これは省略可能です。ただ省略してしまうと階層構造が分かりにくくなるので、残しておいたほうが良いかもしれません。そしてアニメーション用にグローバルな座標変換を設定しておきます。
...
</ModelVisual3D.Children>
<!-- グロ-バルな回転アニメーション -->
<ModelVisual3D.Transform>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D x:Name="myGlobalRotation" Axis="0,1,0" />
</RotateTransform3D.Rotation>
</RotateTransform3D>
</ModelVisual3D.Transform>
</ModelVisual3D>
<Viewport3D.Triggers>
<EventTrigger RoutedEvent="Viewport3D.Loaded">
<BeginStoryboard>
<Storyboard >
<DoubleAnimation Storyboard.TargetName="myGlobalRotation"
Storyboard.TargetProperty="Angle" RepeatBehavior="Forever"
From="0" To="360" Duration="0:0:10" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Viewport3D.Triggers>