non-manifold ですって
発端はこれ
// Warning: The OpenSubdiv Catmull-Clark subdivision method cannot be applied to non-manifold geometry
smoothPreviewをonにするとこんなワーニングが出てくるデータに遭遇。
スクリプトエディタにはopen/import時にこのワーニング出てるんですけど、
思った以上にスクリプトエディタってのは見られてないらしい。
ワーニングの根源
今回ジオメトリはこんな感じになってました。
smoothPreviewをoffにすると一見問題ないのですが、
実は赤丸の部分にはエッジが2本重なっておりマージされてません。
目視でこれを見つけるのはかなーり大変な気がしますね。
そもそも non-manifold
ところで non-manifoldって?
のん まにふぉーるど?
なるほど?
雑に言えば、無茶なつながり方をしてるポリゴンか。
今回の場合は 2つ以上のフェースが1つの頂点を共有する場合(エッジは非共有) かなぁ
どうやって見つける?
- とりあえずmaya標準の機能でやってみる。
cleanupでできるらしい。
ビックリするぐらい引っかからない!
設定が悪い気もするけれども、一回忘れよう。
えーじゃぁどうしよう、力技でvtx数とかポリゴン数とかでなんとかするー?
ってtwitterでモゴモゴ言ってたら
polyInfo ってコマンドがあるそうですわ!
なるほど、non-manifoldの為のオプションが幾つかありますね。
※invalidVertices これ使えば前の記事の様に面倒なことしなくても孤立したvtx見つけられそうですね
polyInfoを試す
こんなメッシュの場合
これで
print(cmds.polyInfo("pPlane6",nonManifoldEdges =True))
print(cmds.polyInfo("pPlane6",nonManifoldVertices =True))
こう
['pPlane6.e[1]', 'pPlane6.e[12]', 'pPlane6.e[23]', 'pPlane6.e[34]', 'pPlane6.e[45]', 'pPlane6.e[56]', 'pPlane6.e[67]', 'pPlane6.e[78]', 'pPlane6.e[89]', 'pPlane6.e[100]']
['pPlane6.vtx[0]', 'pPlane6.vtx[6]', 'pPlane6.vtx[12]', 'pPlane6.vtx[18]', 'pPlane6.vtx[24]', 'pPlane6.vtx[30]', 'pPlane6.vtx[36]', 'pPlane6.vtx[42]', 'pPlane6.vtx[48]', 'pPlane6.vtx[54]', 'pPlane6.vtx[60]']
お、見つけられそうですね。
ではこいつの場合
※わかりづらいのでsmoothPreview = On
さぁ
print(cmds.polyInfo("pPlane3",nonManifoldEdges =True))
print(cmds.polyInfo("pPlane3",nonManifoldVertices =True))
えー・・・・・・・
None
None
力に頼ろう
要は、・・・・・どうすればいいんだ?
- vtxを完全に共有しているedgeを探す
かな?
とりあえずAPI2のドキュメントを眺めてみて
OpenMaya.MItMeshPolygon.getConnectedEdges()
OpenMaya.MItMeshPolygon.getConnectedFaces()
OpenMaya.MItMeshPolygon.getConnectedVertices()
ポリゴンだけどもこの辺が使えそう。
getConnectedEdgesを試してみる
import maya.api.OpenMaya as om
target = "pPlane3"
mesh_dagPath = om.MGlobal.getSelectionListByName(target).getDagPath(0)
shape_Fn = om.MFnMesh(mesh_dagPath)
face_ids = range(0,shape_Fn.numPolygons)
it = om.MItMeshPolygon(mesh_dagPath)
it.setIndex(130)
edges = it.getConnectedEdges()
for edge in edges:
cmds.select(target + ".e["+str(edge)+"]",add =True)
getConnectedVerticesを試してみる
import maya.api.OpenMaya as om
target = "pPlane3"
mesh_dagPath = om.MGlobal.getSelectionListByName(target).getDagPath(0)
shape_Fn = om.MFnMesh(mesh_dagPath)
face_ids = range(0,shape_Fn.numPolygons)
it = om.MItMeshPolygon(mesh_dagPath)
it.setIndex(130)
vtxes = it.getConnectedVertices()
for vtx in vtxes:
cmds.select(target + ".vtx["+str(vtx)+"]",add =True)
重なってるエッジが接続されてるvtxが取れましたね。
てことは
getConnectedVerticesで取得した接続されているvtx
と
faceを構成しているvtx
を比較して、被ってる場合は non-manifold ってことでいいのかしら?
実装
じゃぁまぁそういう事で一回まとめると
def listSlitVtx(target):
vtxIds = []
mesh_dagPath = om.MGlobal.getSelectionListByName(target).getDagPath(0)
shape_Fn = om.MFnMesh(mesh_dagPath)
face_ids = range(0,shape_Fn.numPolygons)
it = om.MItMeshPolygon(mesh_dagPath)
for index in face_ids:
it.setIndex(index)
#faceを構成するvtxIDを取得
vtxs = it.getVertices()
#faceに接続されているvtxIDを取得
connectedVtx = it.getConnectedVertices()
#2種類のvtxIDの積集合を取る
product = list(set(vtxs) & set(connectedVtx))
if len(product):
vtxIds = list(set(vtxIds) | set(product))
result = [target + '.vtx[' + str(vid) + ']'for vid in vtxIds]
return result
cmds.select(listSlitVtx("pPlane3"),add=True)
なんか listSlitVtxは違う気がするけどもまぁ仮という事で。
お 取れました。
こっちのタイプだと無反応なので、こっちはpolyInfoでひっかけた方が良さそうですね
ひとまずこれで。
まぁ完全ではないけども、目視で探すよりは100倍くらい楽ですかね。