Windows Presentation Foundationの特徴の一つには3Dグラフィックスがあります。以前紹介したように3Dの描画自身はそれほど難しくはありません。3Dを使ったメニューのようなものを作りたいとき必要なことは、マウスによるクリックがどの3Dオブジェクトを選択したのかを確認することです。残念ながら、3Dオブジェクトにマウスクリックのコールバックを設定することはできません。
まず、Viewport3Dにマウスクリックのコールバックを設定します。WPFには、マウスがどのオブジェクトをクリックしたかを確認するためのVisualTreeHelper.HitTestメソッドがありますので、このコールバックの中でHitTestを呼び出します。
<Viewport3D MouseLeftButtonDown="OnClick" Name="myViewport3D" >
...
// Viewport3Dクリック時のヒットテスト public void OnClick(object sender, System.Windows.Input.MouseButtonEventArgs args) { Point mouseposition = args.GetPosition(myViewport3D); PointHitTestParameters pointparams = new PointHitTestParameters(mouseposition); VisualTreeHelper.HitTest(myViewport3D, null, HTResult, pointparams); }
ここで注意してほしいのは、第4引数にHitTestParameters3DではなくPointHitTestParametersを渡している点です。これは第1引数にViewport3Dを渡しているからです。Viewport3Dは3Dを2Dに投影したスクリーンですから実は2Dのオブジェクトなのです。ここに3Dオブジェクトを渡そうとすると、自前でマウスのクリック点からレイを導出し、逆座標変換でスクリーン空間からワールド空間に変換し戻す必要があるので面倒です。
HitResult関数では、次のようにHitTestResultで渡されたオブジェクトと、判定したいオブジェクトの比較を行い、必要な作業を行います。ここではVisualHitを使いましたが、RayMeshGeometry3DHitTestResultのメンバには、MeshHit、ModelHit、PointHit、VisualHitなどがあり、目的に応じて利用できます。
public HitTestResultBehavior HTResult(System.Windows.Media.HitTestResult rawresult) { if (rawresult != null) { RayMeshGeometry3DHitTestResult rayMeshResult = rawresult as RayMeshGeometry3DHitTestResult; if (rayMeshResult != null) { Visual3D v3d = rayMeshResult.VisualHit as Visual3D;
if (v3d.Equals(myModel1)) { myPanelStoryboardForward.Begin(myViewport3D); } else { MyVideoDrawing4.Player = null; } } } return HitTestResultBehavior.Stop; }
また、ここでは一番手前のオブジェクトだけを使いたかったので、HitTestResultBehavior.Stopにしていますが、HitTestResultBehavior.Continueにすれば下にあるオブジェクトのヒットテストも行います。
これまでVisual3D の派生クラスは ModelVisual3D だけでしたが、3.5では次の図のように新しくUIElement3D と Viewport3DVisula2D が加わりました。今回は