WPFのクラスで3Dプログラミング

WPFで3Dプログラミングをする場合、通常は裏でDirect3Dを用意してレンダリングを行います。

ただ、とても簡単な3D描画を行いたい場合は、WPFが用意する3D描画クラスを利用することができます。

今回は簡単な実装をしてみたいと思います。

アプリケーション

今回はキーボードの上下左右で回転する立方体を表示してみたいと思います。
f:id:any-programming:20170801015918p:plain

コントロールの主体はViewport3Dで、そこにカメラやライト、メッシュを追加していく形となります。

法線は自動生成されるため、今回は作成していません。

回転はModel3DのTransformを更新することで行っています。

下記はC#で実装していますが、Xamlで記述することも可能です。

// Cubeの各三角形(12枚)を作成
var vertices = new []
{
    new Point3D(-1,  1,  1),
    new Point3D(-1, -1,  1),
    new Point3D( 1, -1,  1),
    new Point3D( 1,  1,  1),
    new Point3D(-1,  1, -1),
    new Point3D(-1, -1, -1),
    new Point3D( 1, -1, -1),
    new Point3D( 1,  1, -1)
};
Point3D[] face(int i1, int i2, int i3, int i4) =>
    new[] { i1, i2, i3, i1, i3, i4 }.Select(x => vertices[x]).ToArray();
Point3D[] positions = new[]
{
    face(0, 1, 2, 3),
    face(3, 2, 6, 7),
    face(7, 6, 5, 4),
    face(4, 5, 1, 0),
    face(0, 3, 7, 4),
    face(5, 6, 2, 1),
}.SelectMany(x => x).ToArray();

// 頂点座標と色をセット
var model = new GeometryModel3D()
{
    Geometry = new MeshGeometry3D() { Positions = new Point3DCollection(positions) },
    Material = new DiffuseMaterial(Brushes.LightGreen),
};

// ライト作成
var light = new DirectionalLight(Colors.White, new Vector3D(0, 0, -1));

// カメラ作成
var camera = new PerspectiveCamera(new Point3D(0, 0, 5), new Vector3D(0, 0, -1), new Vector3D(0, 1, 0), 45);

// 表示用コントロールの作成
Viewport3D viewport3D = new Viewport3D();
viewport3D.Camera = camera;
viewport3D.Children.Add(new ModelVisual3D() { Content = model });
viewport3D.Children.Add(new ModelVisual3D() { Content = light });

Content = viewport3D;

// KeyDownでCubeが回転するよう実装
var quaternion = new Quaternion();
KeyDown += (s, e) =>
{
    var q =
        e.Key == Key.Left  ? new Quaternion(new Vector3D(0, 1, 0), -1) :
        e.Key == Key.Right ? new Quaternion(new Vector3D(0, 1, 0),  1) :
        e.Key == Key.Up    ? new Quaternion(new Vector3D(1, 0, 0), -1) :
        e.Key == Key.Down  ? new Quaternion(new Vector3D(1, 0, 0),  1) :
        Quaternion.Identity;

    quaternion = q * quaternion;
    model.Transform = new RotateTransform3D(new QuaternionRotation3D(quaternion));
};


法線やインデックス

MeshGeometry3DにはNormalsとTriangleIndicesが設定可能となっています。

テクスチャ

MeshGeometry3DのTextureCoordinatesを設定し、DiffuseMaterialにImageBrushを設定します。

カリングOFF

GeometryModel3DのBackMaterialを設定するとOFFになります。

ライン描画

残念ながら対応していません。細いポリゴンを描くしかなさそうです。

オブジェクト毎のマウスイベントハンドリング

ModelVisual3Dの代わりにModelUIElement3Dを利用すると、MouseMoveなどが登録できるようになります。

2Dコントロール(Buttonなど)を3D上に配置

Viewport2DVisual3Dを用いると可能となります。