チュートリアル / Maya API入門チュートリアル
第4回:ポリゴンデータの取得
- Maya
- ゲーム
- コラム
- スクリプト・API
- チュートリアル
- 学生・初心者
- 映画・TV・アニメ
今回はコマンドプラグインでポリゴンデータの取得を行ってみたいと思います。
Mayaのポリゴンを構成する基本要素は頂点で、その頂点(Vertex)をエッジ(Edge)で繋いでポリゴンフェース(Face)が構成されます。1つのポリゴンを構成する頂点数は最少で3頂点の3角形ポリゴンです。もちろん4角形以上の多角形も定義できます。頂点やエッジのみを作成することはできず、ポリゴンフェースを構築する必要があります。また頂点には頂点カラーや法線データ等が含まれます。
ポリゴンメッシュを構成するデータはmeshノードに含まれています。前回はtransformノードのアトリビュート値の操作について説明しましたが、meshノードがシーン中に存在するには親ノードとして主にtransformノードが必要となります。meshノードが持つポリゴンの各頂点のローカル座標をtransformノードで変換してシーンでのポリゴンの配置を決定しています。Mayaではオブジェクトの配置座標はtransformノード、ポリゴン頂点の座標はmeshノードに格納されていて明確に分けて管理されています。
Maya APIではmeshノードのポリゴン各要素について容易にアクセスできるクラスがいくつか用意されています。
今回もサンプルとしてコマンドプラグインのソースコードを用意しましたので内容を確認してみてください。
MFnMeshによるポリゴンメッシュデータの取得
MFnMeshはmeshノード全体について操作ができる多機能なクラスセットです。
頂点、エッジ、フェース、UV、法線、頂点カラー、ブラインドデータ等にアクセスすることができます。その他、任意の線分とポリゴンメッシュとの交点を計算したり、ポリゴンメッシュデータそのもの全体を構築して新たに作ることもできます。MFnMeshを利用したデータ取得の例を見て見ましょう。
////////////////////////////////////////////////////////////////////
//MFnMesh ポリゴンデータの取得
MFnMesh meshFn(meshDagPath);
//頂点数の取得
int numVertices = meshFn.numVertices();
cout<< "numVertices: " << numVertices <<endl;
//ポリゴン数の取得
int numPolygons = meshFn.numPolygons();
cout << "numPolygons: " << numPolygons << endl;
MPointArray vertexPosArray;
//全ての頂点座標を取得 ローカル座標
meshFn.getPoints( vertexPosArray, MSpace::kObject );
cout << "vertexPosArray kObject: " << endl << vertexPosArray << endl;
//全ての頂点座標を取得 ワールド座標
meshFn.getPoints(vertexPosArray, MSpace::kWorld );
cout << "vertexPosArray kWorld: " << endl << vertexPosArray << endl;
//各ポリゴンフェースを構成する頂点のIDと頂点座標の出力
for ( int j = 0; j < numPolygons; j++ ) {
MIntArray vertexList;
meshFn.getPolygonVertices( j, vertexList );
for ( unsigned int k = 0; k < vertexList.length(); k++ ) {
cout << "faceId: "<< j << " vertexId: " << vertexList[k]
<< " vertexPosArray kWorld: " << vertexPosArray[vertexList[k]]
<< endl;
}
}
ここではMFnMeshにmeshノードのMDagPathオブジェクトを与えています。MDagPathを使う理由として、ワールド座標での頂点座標も取得したいからです。meshノードのMObjectを与えるとローカル座標の頂点のみの取得となります。これは前回のtransformノードの移動値の座標を取得した例と同じです。
ポリゴン数と頂点数は、MFnMeshのnumVertices()、numPolygons()で取得できます。
全ての頂点座標をgetPoints()で取得し、MPointArrayに格納しています。ここではローカル座標の取得はkObject、ワールド座標の取得にはkWorldの定数を設定しています。
最後の部分ではポリゴンフェース毎に、getPolygonVertices()を使って1つのポリゴンフェースを構築している頂点のIDを取得して出力しています。
例としてプリミティブのCubeを作成して、pCube1のScale X, Y, Zに2を設定して実行を試します。ワールドとローカルの頂点座標の取得で数値の違いが確認できると思います。
サンプルプラグインの実行を試すにはtransformノードではなく、meshノード(pCubeShape1)を選択してから実行してください。
Output Window出力結果 例:
numVertices: 8
numPolygons: 6
vertexPosArray kObject:
[0: [-0.5, -0.5, 0.5, 1],
1: [0.5, -0.5, 0.5, 1],
2: [-0.5, 0.5, 0.5, 1],
3: [0.5, 0.5, 0.5, 1],
4: [-0.5, 0.5, -0.5, 1],
5: [0.5, 0.5, -0.5, 1],
6: [-0.5, -0.5, -0.5, 1],
7: [0.5, -0.5, -0.5, 1]]
vertexPosArray kWorld:
[0: [-1, -1, 1, 1],
1: [1, -1, 1, 1],
2: [-1, 1, 1, 1],
3: [1, 1, 1, 1],
4: [-1, 1, -1, 1],
5: [1, 1, -1, 1],
6: [-1, -1, -1, 1],
7: [1, -1, -1, 1]]
faceId: 0 vertexId: 0 vertexPos kWorld: [-1, -1, 1, 1]
faceId: 0 vertexId: 1 vertexPos kWorld: [1, -1, 1, 1]
faceId: 0 vertexId: 3 vertexPos kWorld: [1, 1, 1, 1]
faceId: 0 vertexId: 2 vertexPos kWorld: [-1, 1, 1, 1]
faceId: 1 vertexId: 2 vertexPos kWorld: [-1, 1, 1, 1]
faceId: 1 vertexId: 3 vertexPos kWorld: [1, 1, 1, 1]
faceId: 1 vertexId: 5 vertexPos kWorld: [1, 1, -1, 1]
faceId: 1 vertexId: 4 vertexPos kWorld: [-1, 1, -1, 1]
faceId: 2 vertexId: 4 vertexPos kWorld: [-1, 1, -1, 1]
faceId: 2 vertexId: 5 vertexPos kWorld: [1, 1, -1, 1]
faceId: 2 vertexId: 7 vertexPos kWorld: [1, -1, -1, 1]
faceId: 2 vertexId: 6 vertexPos kWorld: [-1, -1, -1, 1]
faceId: 3 vertexId: 6 vertexPos kWorld: [-1, -1, -1, 1]
faceId: 3 vertexId: 7 vertexPos kWorld: [1, -1, -1, 1]
faceId: 3 vertexId: 1 vertexPos kWorld: [1, -1, 1, 1]
faceId: 3 vertexId: 0 vertexPos kWorld: [-1, -1, 1, 1]
faceId: 4 vertexId: 1 vertexPos kWorld: [1, -1, 1, 1]
faceId: 4 vertexId: 7 vertexPos kWorld: [1, -1, -1, 1]
faceId: 4 vertexId: 5 vertexPos kWorld: [1, 1, -1, 1]
faceId: 4 vertexId: 3 vertexPos kWorld: [1, 1, 1, 1]
faceId: 5 vertexId: 6 vertexPos kWorld: [-1, -1, -1, 1]
faceId: 5 vertexId: 0 vertexPos kWorld: [-1, -1, 1, 1]
faceId: 5 vertexId: 2 vertexPos kWorld: [-1, 1, 1, 1]
faceId: 5 vertexId: 4 vertexPos kWorld: [-1, 1, -1, 1]
またこのサンプルではポリゴンフェースのID、頂点のIDを出力しています。ビューポートでこれらの各コンポーネントIDを確認するには、Mayaのメニューから Display->Polygons->Component IDs のVerticesとFacesを選択します。
MItMeshVertexによる頂点データの取得
MItMeshVertexは頂点データへアクセスするイテレータで、頂点IDの順序で反復しデータを取得することができます。頂点イテレータは以下のように頂点IDの順序で参照をします。
next()で次の頂点IDを参照し、isDone()で最後の頂点IDまで到達したかを判別することができます。
サンプルコードでは頂点座標をposition()で取得しています。この他にgetConnectedFaces()で頂点に接続しているポリゴンフェースのIDを取得しています。頂点イテレータが現在参照している頂点のIDはindex()で取得することができます。
////////////////////////////////////////////////////////////////////
//MItMeshVertex 頂点イテレータの例
MItMeshVertex vIter( meshDagPath );
for (; !vIter.isDone(); vIter.next() ) {
MPoint vertexPos = vIter.position( MSpace::kObject );
MIntArray fIndexArray;
vIter.getConnectedFaces(fIndexArray);
cout<< "vertexId: " << vIter.index()
<< " vertexPos kObject: " << vertexPos
<<" connectedFaceId: "<< fIndexArray <<endl;
}
プリミティブのCubeメッシュに対してサンプルプラグインを実行すると以下のような出力結果になります。
Output Window出力結果 例:
vertexId: 0 vertexPos kObject: [-0.5, -0.5, 0.5, 1] connectedFaceId: [5, 0, 3]
vertexId: 1 vertexPos kObject: [0.5, -0.5, 0.5, 1] connectedFaceId: [3, 0, 4]
vertexId: 2 vertexPos kObject: [-0.5, 0.5, 0.5, 1] connectedFaceId: [1, 0, 5]
vertexId: 3 vertexPos kObject: [0.5, 0.5, 0.5, 1] connectedFaceId: [4, 0, 1]
vertexId: 4 vertexPos kObject: [-0.5, 0.5, -0.5, 1] connectedFaceId: [2, 1, 5]
vertexId: 5 vertexPos kObject: [0.5, 0.5, -0.5, 1] connectedFaceId: [4, 1, 2]
vertexId: 6 vertexPos kObject: [-0.5, -0.5, -0.5, 1] connectedFaceId: [3, 2, 5]
vertexId: 7 vertexPos kObject: [0.5, -0.5, -0.5, 1] connectedFaceId: [4, 2, 3]
MItMeshPolygonによるポリゴンフェースデータの取得
MItMeshPolygonはポリゴンフェースデータへアクセスするイテレータです。こちらもMItMeshVertexと同じようにフェースIDの順序で反復しフェース毎のデータを取得することができます。イテレータは以下のようにフェースIDの順序で参照をします。
サンプルコードではgetVertices()でフェースを構成する頂点IDの取得、頂点座標の取得はgetPoints()で行っています。
////////////////////////////////////////////////////////////////////
//MItMeshPolygon ポリゴンフェイスイテレータの例
MItMeshPolygon fIter( meshDagPath );
for (; !fIter.isDone(); fIter.next()) {
MIntArray vIndexArray;
fIter.getVertices(vIndexArray);
MPointArray vertexPosArray;
fIter.getPoints(vertexPosArray, MSpace::kObject);
cout << "faceId: " << fIter.index()
<< " vertexId: " << vIndexArray << endl;
cout <<"vertexPos kObject: "<< endl << vertexPosArray << endl;
}
プリミティブのCubeメッシュに対してサンプルプラグイン実行すると以下のような出力結果になります。
Output Window出力結果 例:
faceId: 0 vertexId: [0, 1, 3, 2]
vertexPos kObject:
[0: [-0.5, -0.5, 0.5, 1],
1: [0.5, -0.5, 0.5, 1],
2: [0.5, 0.5, 0.5, 1],
3: [-0.5, 0.5, 0.5, 1]]
faceId: 1 vertexId: [2, 3, 5, 4]
vertexPos kObject:
[0: [-0.5, 0.5, 0.5, 1],
1: [0.5, 0.5, 0.5, 1],
2: [0.5, 0.5, -0.5, 1],
3: [-0.5, 0.5, -0.5, 1]]
faceId: 2 vertexId: [4, 5, 7, 6]
vertexPos kObject:
[0: [-0.5, 0.5, -0.5, 1],
1: [0.5, 0.5, -0.5, 1],
2: [0.5, -0.5, -0.5, 1],
3: [-0.5, -0.5, -0.5, 1]]
faceId: 3 vertexId: [6, 7, 1, 0]
vertexPos kObject:
[0: [-0.5, -0.5, -0.5, 1],
1: [0.5, -0.5, -0.5, 1],
2: [0.5, -0.5, 0.5, 1],
3: [-0.5, -0.5, 0.5, 1]]
faceId: 4 vertexId: [1, 7, 5, 3]
vertexPos kObject:
[0: [0.5, -0.5, 0.5, 1],
1: [0.5, -0.5, -0.5, 1],
2: [0.5, 0.5, -0.5, 1],
3: [0.5, 0.5, 0.5, 1]]
faceId: 5 vertexId: [6, 0, 2, 4]
vertexPos kObject:
[0: [-0.5, -0.5, -0.5, 1],
1: [-0.5, -0.5, 0.5, 1],
2: [-0.5, 0.5, 0.5, 1],
3: [-0.5, 0.5, -0.5, 1]]
MItMeshFaceVertexによるポリゴンフェース頂点データの取得
MItMeshFaceVertexはフェース頂点へアクセスするイテレータです。フェース頂点は少し特殊で1つのポリゴンフェースとそれを構成する頂点を合わせた単位になっています。フェース頂点毎の法線やUV、頂点カラーにアクセスする場合に使いやすいイテレータだと思います。
フェース頂点をビューポートで確認するには、マーキングメニューでVertex Faceを選択します。各フェースが少し小さく表示されます。ここではフェースID:1, 頂点ID:5を選択していますが、スクリプトエディタで確認するとpPlane1.vtxFace[5][1]が選択されたと確認できます。
イテレータは以下のような順序で参照を行います。このメッシュの場合、イテレータの始点はフェースID:0、頂点ID:0です。
サンプルコードではフェース頂点毎の法線データを取得しています。法線はgetNormal()で取得できます。
////////////////////////////////////////////////////////////////////
//MItMeshFaceVertex ポリゴンフェース頂点 イテレータの例
MItMeshFaceVertex fvIter( meshDagPath );
for( ; !fvIter.isDone(); fvIter.next() ){
MVector fvNormal;
fvIter.getNormal( fvNormal, MSpace::kObject );
cout <<"faceId: "<< fvIter.faceId()<<" vertexId: "<<fvIter.vertId()
<< " fvNormal: " << fvNormal << endl;
}
プリミティブのCubeメッシュに対してサンプルプラグインを実行すると以下のような出力結果になります。
Output Window出力結果 例:
faceId: 0 vertexId: 0 fvNormal: [0, 0, 1]
faceId: 0 vertexId: 1 fvNormal: [0, 0, 1]
faceId: 0 vertexId: 3 fvNormal: [0, 0, 1]
faceId: 0 vertexId: 2 fvNormal: [0, 0, 1]
faceId: 1 vertexId: 2 fvNormal: [0, 1, 0]
faceId: 1 vertexId: 3 fvNormal: [0, 1, 0]
faceId: 1 vertexId: 5 fvNormal: [0, 1, 0]
faceId: 1 vertexId: 4 fvNormal: [0, 1, 0]
faceId: 2 vertexId: 4 fvNormal: [0, 0, -1]
faceId: 2 vertexId: 5 fvNormal: [0, 0, -1]
faceId: 2 vertexId: 7 fvNormal: [0, 0, -1]
faceId: 2 vertexId: 6 fvNormal: [0, 0, -1]
faceId: 3 vertexId: 6 fvNormal: [0, -1, 0]
faceId: 3 vertexId: 7 fvNormal: [0, -1, 0]
faceId: 3 vertexId: 1 fvNormal: [0, -1, 0]
faceId: 3 vertexId: 0 fvNormal: [0, -1, 0]
faceId: 4 vertexId: 1 fvNormal: [1, 0, 0]
faceId: 4 vertexId: 7 fvNormal: [1, 0, 0]
faceId: 4 vertexId: 5 fvNormal: [1, 0, 0]
faceId: 4 vertexId: 3 fvNormal: [1, 0, 0]
faceId: 5 vertexId: 6 fvNormal: [-1, 0, 0]
faceId: 5 vertexId: 0 fvNormal: [-1, 0, 0]
faceId: 5 vertexId: 2 fvNormal: [-1, 0, 0]
faceId: 5 vertexId: 4 fvNormal: [-1, 0, 0]
ポリゴンメッシュに対応するイテレータはこの他にもエッジに対応するMItMeshEdgeもありますのでAPIのクラスドキュメントを確認してみてください。
今回はポリゴンメッシュデータの取得についてご紹介しました。ポリゴンメッシュのデータが取得できればメッシュを検査するツールや独自のエキスポータなどを作ることができると思います。
次回はポリゴンメッシュのデータ構築と作成方法についてご紹介したいと思います。