WPFで3Dモーフィング

WFPの壁を破ろうシリーズ第5段?

3Dモーフィングは、複数の3Dジオメトリ間で頂点を補間して中間のジオメトリを表示して、3Dジオメトリ間の遷移を表現するテクニックです。リアルタイム シェーダを使えば、GPU内のジオメトリをハードウェアでモーフィングできますが、WPFでは頂点単位の処理はできないので、例の如くCPUで処理します。ただし頂点の数とそのトポロジは同じでなければなりません。

まず同じ頂点数の球(mySpere)と円柱(myCylinder)のGrometryModel3Dを用意して、一方をシーンに配置します。

<ModelVisual3D>

<ModelVisual3D.Content>

    <GeometryModel3D Geometry="{StaticResource mySphere}" >

      <GeometryModel3D.Material>

        <DiffuseMaterial Brush="{StaticResource myEarth}" />

      </GeometryModel3D.Material>

    </GeometryModel3D>

  </ModelVisual3D.Content>

</ModelVisual3D>

補間パラメータはスライダで設定するように、コールバックを定義します。コールバックの中で2つの頂点を補間し、新しいModelVisual3Dを生成してシーンに追加します。

private void SliderMoved(object sender, RoutedEventArgs e)

{

    Slider s = (Slider)sender;

    myScene.Children.Clear();

    MeshGeometry3D myMesh = GetMorphedMesh(s.Value);

    GeometryModel3D myGeom = new GeometryModel3D();

    myGeom.Geometry = myMesh;

    myGeom.Material = new DiffuseMaterial(myEarth);

    ModelVisual3D myModel = new ModelVisual3D();

    myModel.Content = myGeom;

    myScene.Children.Add(myModel);

}

internal MeshGeometry3D GetMorphedMesh(double w)

{

    MeshGeometry3D m = new MeshGeometry3D();

    m.TextureCoordinates = myCylinder.TextureCoordinates;

    m.TriangleIndices = myCylinder.TriangleIndices;

    for (int i = 0; i < myCylinder.Positions.Count; i++)

    {

        Point3D p0 = myCylinder.Positions[i];

        Point3D p1 = mySphere.Positions[i];

        Point3D p = new Point3D( w * p0.X + (1.0 - w) * p1.X,

                                              w * p0.Y + (1.0 - w) * p1.Y,

                                              w * p0.Z + (1.0 - w) * p1.Z) ;

        m.Positions.Add(p);

     Vector3D n0 = myCylinder.Normals[i];

        Vector3D n1 = mySphere.Normals[i];

        Vector3D n = w * n0 + (1.0 - w) * n1;

        m.Normals.Add(n);

    }

    return m;

}