MathematicaでMikuMikuDance 3

  ステージの読み込み。

# 1 MMDの背景(ステージ)を入手する。
 MMDの背景ステージは色々と公開されています。
今回は[恋スルVOC@LOIDステージ](http://mmdyuyu.blog43.fc2.com/category2-1.html)　遊々さん作を利用します。リンク先からKoiVoca-Stage.zipをダウンロードして解凍します。

# 2 .xファイルをMathematicaで読み込めるように変換する。
 MicroSoftの.xファイルをMathematicaの形式に合わせて変換します。
.xファイルには様々な内部形式がありますが、KoiVoca-Stage用に合わせて作成しましたので汎用性はありません。

```awk:x_conv.awk
BEGIN {
  material_no=0;
}
// {
  if(header==1) {
    if(sl==0) printf("    {\"Major\",%d},\n",$0);
    if(sl==1) printf("    {\"Minor\",%d},\n",$0);
    if(sl==2) printf("    {\"Flag\",%d}\n",$0);
    sl=sl+1;
  }
  if(meshvertexcolors==1) {
    if(sl==0) {
      str=$0+0;
      nvertexcolor=str;
      printf("  {\"VertexColors\",{ (* %d *)\n",str);
    }
    if(sl>=1&&sl<nvertexcolor) {
      split($0,vc,";");
      printf("    RGBColor[%f,%f,%f,%f], (* %d *)\n",vc[2],vc[3],vc[4],vc[5],vc[1]);
    }
    if(sl==nvertexcolor) {
      split($0,vc,";");
      printf("    RGBColor[%f,%f,%f,%f]  (* %d *)\n",vc[2],vc[3],vc[4],vc[5],vc[1]);
      print "  }}";
    }
    sl=sl+1;
  }

  if(meshtexturecoords==1) {
    if(sl==0) {
      str=$0+0;
      nuvvectors=str;
      printf("  {\"UVVectors\",{ (* %d *)\n",str);
    }
    if(sl>=1&&sl<nuvvectors) {
      split($0,uvv,";");
      printf("    {%f,%f}, (* %d *)\n",uvv[1],uvv[2],sl);
    }
    if(sl==nuvvectors) {
      split($0,uvv,";");
      printf("    {%f,%f}  (* %d *)\n",uvv[1],uvv[2],sl);
      print "  }},";
    }
    sl=sl+1;
  }

  if(material==1) {
    if(sl==0) {
      split($0,rgba,";");
      printf("    { (* %d *)\n",material_no);
      printf("     RGBColor[%f,%f,%f,%f],\n",rgba[1],rgba[2],rgba[3],rgba[4]);
    }
    if(sl==1) {
      pow=$0+0;
    }
    if(sl==2) {
      split($0,rgba,";");
      printf("     Specularity[RGBColor[%f,%f,%f],%f],\n",rgba[1],rgba[2],rgba[3],pow);
    } 
    if(sl==3) {
      split($0,rgba,";");
      printf("     Glow[RGBColor[%f,%f,%f]]",rgba[1],rgba[2],rgba[3],rgba[4]);
    }
    if(sl==4) {
      if($0 ~ /^   TextureFilename {/) {
        texture=1;
        printf(",\n");
      } else {
        texture=0;
        printf("\n");
      }
    }
    if(sl==5 && texture==1) {
      texture=0;
      str=substr($0,index($0,"\"")+1);
      str=substr(str,1,index(str,"\"")-1);
      printf("     Texture[Import[\"%s\"]]\n",str);
    }
    if(sl==5) {
      if(material_no==nMaterialList) {
        print "    }";
        print "  }},";
      } else {
        print "    },";
      }
    }
    sl=sl+1;
  }
  if(mesh_material==1) {
    if(sl==0) {
      printf("   (* %d *)\n",$0+0);
      nMaterialList=$0+0;
    }
    if(sl==1) {
      printf("   (* %d *)\n",$0+0);
    }
    if(sl>=2&&sl<nFaces+1) {
      printf("   %d, (* %d *)\n",$0+0,sl-1);
    }
    if(sl==nFaces+1) {
      printf("   %d  (* %d *)\n",$0+0,sl-1);
      print "  }},";
      mesh_material=0;
      mesh=0;
    }
    sl=sl+1;
  }
  if(mesh==1&&mesh_material==0&&material==0) {
    str=$0;
    if(sl==0) {
      printf("    (* %d *)\n",str);
      nVertices=str+0;
    }
    
    if(sl>=1&&sl<=nVertices) {
      split($0,cordinate,";");
      printf("    {%f,%f,%f},(* %d *)\n",cordinate[1],cordinate[2],cordinate[3],sl);
    }
    if(sl==nVertices) {
      split($0,cordinate,";");
      printf("    {%f,%f,%f} (* %d *)\n",cordinate[1],cordinate[2],cordinate[3],sl);
    }

    if(sl==nVertices+2) {
      nFaces=$0+0;
      print "  }},";
      print "  {\"FaceIndices\",{";
      printf("    (* %d *)\n",nFaces);
    }
    if(sl>=nVertices+3&&sl<nVertices+2+nFaces) {
      split($0,element,";");
      split(element[2],faces,",");
      if(element[1]==4) {
        printf("    {%d,%d,%d,%d},(* %d *)\n",faces[1],faces[2],faces[3],faces[4],sl-nVertices-2);
      }
      if(element[1]==3) {
        printf("    {%d,%d,%d},(* %d *)\n",faces[1],faces[2],faces[3],sl-nVertices-2);
      }
    }
    if(sl==nVertices+2+nFaces) {
      split($0,element,";");
      split(element[2],faces,",");
      if(element[1]==4) {
        printf("    {%d,%d,%d,%d} (* %d *)\n",faces[1],faces[2],faces[3],faces[4],sl-nVertices-2);
      }
      if(element[1]==3) {
        printf("    {%d,%d,%d} (* %d *)\n",faces[1],faces[2],faces[3],sl-nVertices-2);
      }
      print "  }},";
      mesh=0;
    }
    sl=sl+1;
  }
}
/\}/ {
  if(header==1) {
    header=0;
    print "  }},";
  }
}
/^Header{/ {
  print "{";
  print "  {\"Header\",{";
  header=1;
  sl=0;
}
/^Mesh {/ {
  print "  {\"VertexVectors\",{";
  mesh=1;
  sl=0;
}  
/^ MeshMaterialList {/ {
  print "  {\"MaterialIndices\",{";
  mesh_material=1;
  sl=0;
}
/^ MeshVertexColors {/ {
  meshvertexcolors=1;
  meshtexturecoords=0;
  sl=0;
}
/^ MeshTextureCoords {/ {
  meshtexturecoords=1;
  mesh_material=0;
  material=0;
  sl=0;
}
/^  Material {/ {
  material_no=material_no+1;
  if(material==0) {
    printf("  {\"TextureList\",{\n");
    material=1;
  }
  material=1;
  sl=0;
}
END {
  print "}";
}
```

下記コマンドで変換します。

```bash:BASH
>gawk -f x_conv.awk KoiVoca-Stage.x >KoiVoca-Stage.m
```

# 3 Mathematicaで読み込む。
 Mathematicaを起動して、KoiVoca-Stage.mを読み込みます。

```Mathematica:Mathematica
Directory[]
Stage = Import["KoiVoca-Stage.m"];
f[s_] := Stage[[Position[Stage[[All, 1]], s ][[1]][[1]], 2]];
```
 次に頂点リストを3Dプロットしてみます。

```Mathematica:Mathematica
vertex = {1, 1, 1} # & /@ f["VertexVectors"];
ListPointPlot3D[vertex, ViewPoint -> Above]
```
![Koivoca2.png](https://qiita-image-store.s3.amazonaws.com/0/119510/866a7289-327a-8fe0-8c2b-05536f0d44bb.png)

 つぎに、ポリゴンを構成してグラフィック表示してみます。

```Mathematica:Mathematica
poly = vertex[[# + 1]] & /@ 
     Piecewise[{
       {{#[[1]], #[[2]], #[[3]]}, Length[#] == 3},
       {{#[[1]], #[[2]], #[[3]], #[[4]]}, Length[#] == 4}
       }] & /@ f["FaceIndices"];
Graphics3D[{Prepend[Polygon /@ poly, EdgeForm[]]}, ViewPoint ->Above]
```
![Koivoca3.png](https://qiita-image-store.s3.amazonaws.com/0/119510/8401844e-df0d-fca3-a7dd-a4335eadc790.png)

  ナニカヘン・・・。ト音記号が逆ですね。実はMathematicaの3Dグラフィックは右手座標系なのですが、DirectXは左手座標系なのです。なので座標系の変換をしなければなりません。
  下記コードで頂点座標のZ座標を-1倍します。

```Mathematica:Mathematica
vertex = {1, 1, -1} # & /@ f["VertexVectors"];
ListPointPlot3D[vertex, ViewPoint -> Above]
```
![Koivoca1.png](https://qiita-image-store.s3.amazonaws.com/0/119510/2d9d9d4b-c793-f6b6-9756-3eef740f4110.png)

  次に下記コードでポリゴンの頂点の並びを1->2->3から1->3->2と並べ替えます。

```Mathematica:Mathematica
poly = vertex[[# + 1]] & /@ 
     Piecewise[{
       {{#[[1]], #[[3]], #[[2]]}, Length[#] == 3},
       {{#[[1]], #[[4]], #[[3]], #[[2]]}, Length[#] == 4}
       }] & /@ f["FaceIndices"];
Graphics3D[{Opacity[1.0], Prepend[Polygon /@ poly, EdgeForm[]]}, 
 ViewPoint -> Above]
```
![Koivoca4.png](https://qiita-image-store.s3.amazonaws.com/0/119510/c40ed3e0-5de6-edcf-e047-f5d34b216a93.png)

  最後にテクスチャとマテリアルカラーを指定して色を塗ります。

```Mathematica:Mathematica
vv[s_, i_] := f[s][[i + 1]];
poly =
  vertex[[# + 1]] & /@
     Piecewise[{
       {{#[[1]], #[[3]], #[[2]]}, Length[#] == 3},
       {{#[[1]], #[[4]], #[[3]], #[[2]]}, Length[#] == 4}
       }] & /@ f["FaceIndices"];
uvv =
  vv["UVVectors", #] & /@
     Piecewise[{
       {{#[[1]], #[[3]], #[[2]]}, Length[#] == 3},
       {{#[[1]], #[[4]], #[[3]], #[[2]]}, Length[#] == 4}
       }] & /@ f["FaceIndices"];
p = Partition[Riffle[poly, uvv], 2];
pl[i_] := Polygon[i[[1]], VertexTextureCoordinates -> i[[2]], 
  VertexNormals -> Automatic]

dl = Prepend[
   Flatten[#, 1] & /@ 
    Partition[Riffle[vv["TextureList", #] & /@ f["MaterialIndices"],
      pl /@ p], 2], EdgeForm[]];
Graphics3D[dl, ViewPoint -> Above]
```

![Koivoca5.png](https://qiita-image-store.s3.amazonaws.com/0/119510/1114d408-17aa-c249-03ad-e4034db6a1bd.png)

  かわいらしいステージが表示されました。

# 4 他関連記事へのリンク
* [MathematicaでMikuMikuDance 1](http://qiita.com/I_HaL/items/caa83662baaca28b5315) PMDファイルの読み込み
* [MathematicaでMikuMikuDance 4](http://qiita.com/I_HaL/items/6991775eb9c8f9a18c0f) ダンスの計算