WPF UIコンポーネントを3D内で使う

WPFの特徴の一つは3Dと2Dの融合で、ボタンなどの2DのUIコンポーネントを3Dジオメトリに貼り付けることができます。しかし、これをUIとして使うことはできません、ビジュアルとして貼り付けられているだけです。

WPF 3Dチームのブログにこれを解決するためのツールが紹介されています。つまり、3Dに貼り付けた2DのWPF UIコンポーネントをそのまま使えるようにするためのライブラリです。codeprexのサイトからダウンロードでき、ソースコードも公開されています。

これを使って、以前紹介した入力を3Dに表示させるサンプルを修正し、3Dに入力した結果を3Dに表示させるサンプルを作ってみました。このツールを使うには、ダウンロードした3DTools.dllを参照設定に追加し、XAMLでViewport3DをInteractive3DDecoratorで囲みます。すると、モデルの指定に InteractiveVisual3Dが使え、この例のように座標変換、ジオメトリ、Visualやマテリアルをプロパティとして指定できます。ここでは明確にするためにリソースを使っていますが、特にリソースでなければいけないわけではありません。

<Window x:Class="myInteractive3D.Window1"

    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:local="clr-namespace:_3DTools;assembly=3DTools"

    Title="myInteractive3D" Width="400" Height="300"

    >

  <Window.Resources>

    <!-- Transform -->

    <RotateTransform3D x:Key="myTransform">

      <RotateTransform3D.Rotation>

        <AxisAngleRotation3D Angle="30" Axis="0 1 0" />

      </RotateTransform3D.Rotation>

    </RotateTransform3D>

    <!-- Geometry -->

    <MeshGeometry3D x:Key="myPlaneMesh"

        Positions="-1,1,0 -1,-1,0 1,-1,0 1,1,0"

        TextureCoordinates="0,0 0,1 1,1 1,0"

        TriangleIndices="0 1 2 0 2 3"/>

    <!-- Visual -->

    <Border x:Key="myVisual" BorderBrush="Green"

        BorderThickness="2" Background="White">

      <StackPanel Orientation="Vertical" Width="Auto" Height="Auto"

        HorizontalAlignment="Stretch" VerticalAlignment="Stretch">

        <TextBox x:Name="myInput" Text="キー入力" Background="Yellow" />

        <TextBlock Text="{Binding ElementName=myInput, Path=Text}"

            Background="Red"/>

        <Button Content="ボタン" Margin="10"/>

      </StackPanel>

    </Border>

  </Window.Resources>

 

  <Canvas>

    <local:Interactive3DDecorator>

      <Viewport3D Width="400" Height="300">

        <!-- Camera -->

        <Viewport3D.Camera>

          <PerspectiveCamera Position="0, 0, 6" FieldOfView="45" />

        </Viewport3D.Camera>

        <!-- Light -->

        <ModelVisual3D>

          <ModelVisual3D.Content>

            <DirectionalLight Color="White" Direction="0,0,-1" />

          </ModelVisual3D.Content>

        </ModelVisual3D>

        <!-- Model -->

        <local:InteractiveVisual3D

            Transform="{StaticResource myTransform}"

         Geometry="{StaticResource myPlaneMesh}"

            Visual="{StaticResource myVisual}" />

      </Viewport3D>

    </local:Interactive3DDecorator>

   

  </Canvas>

</Window>

内部的にはちょっと変わったことをやっていて、ユーザーは3Dのボタンを押しているように見えますが、非表示の2D Visualがあり、そのUIを実は操作しています。3Dにはその結果を張り付けているだけです。マウスの位置が2Dと3Dで同じになるように非表示2Dを平行移動させたり、裏側がクリックされないようにしたりなど、けっこう苦労しています。詳細はWPF 3D チームのブログchannel9を参照してください。