あれこれ計算してフリップしたUVを見つける!! part2

前回投稿した「あれこれ計算してフリップしたUVを見つける!! part1」の続編です!!今回は、Pythonに落とし込むところをやっていきたいと思います!!

OpenMayaでの選択の取得

 

from maya import OpenMaya

def main():
	selection = OpenMaya.MSelectionList()#(1)
	OpenMaya.MGlobal.getActiveSelectionList(selection)#(2)
	if selection.length() == 0:#(3)
		return False

OpenMayaで選択を取得するには、まず「OpenMaya.MSelectionList」のインスタンスを作成し(1)、「OpenMaya.MGlobal.getActiveSelectionList」に渡してあげると、インスタンスに選択した情報をぶちこんでくれます!(2)

選択したノードがあるかどうかは、「length」の数からわかります(3)(`・ω・´)ゞ

ループ処理の準備

from maya import OpenMaya

def main():
	selection = OpenMaya.MSelectionList()
	OpenMaya.MGlobal.getActiveSelectionList(selection)
	if selection.length() == 0:
		return False
		
	iter   = OpenMaya.MItSelectionList(selection)#(1)
	result = OpenMaya.MSelectionList()#(2)

OpenMayaでループ処理をする場合は、イテレータと言われるものを使います。イテレータとは、配列系のデータ構造を繰り返し処理を抽象化したものです(1)。OpenMayaのオブジェクトを繰り返し処理する場合は、OpenMayaの作法にのっとって行います。

次に、フリップしたUVのフェイスを格納するためのリストを用意します(2)。

繰り返し処理

from maya import OpenMaya

def main():
	# 中略
	while not iter.isDone():#(1)

		dagPath = OpenMaya.MDagPath()
		component = OpenMaya.MObject()
		iter.getDagPath(dagPath, component)#(2)
		
		iter.next()#(3)

ここでの繰り返し処理は「while」を使い、イテレータが完了した状態になるまで繰り返します(1)。

繰り返し処理で最初に行うのは、選択情報からDagPathとコンポーネントを指すオブジェクトの取得です。DagPathはMDagPath、コンポーネントを指すオブジェクトはMObjectのインスタンスを作成し、イテレータのgetDagPathにぶち込み設定してもらいます(2)。

イテレータを使う場合、必ず「next()」を実行しないと無限ループに陥るので注意してください!(3)ついつい忘れて、やっちまったー!ってこともしばし、、、(;´∀`)

Mesh情報を取得する準備と、フェイス単位の処理をする準備

from maya import OpenMaya

def main():
	# 中略
	while not iter.isDone():

		dagPath = OpenMaya.MDagPath()
		component = OpenMaya.MObject()
		iter.getDagPath(dagPath, component)
		
		fnMesh   = OpenMaya.MFnMesh(dagPath)#(1)
		polyIter = OpenMaya.MItMeshPolygon(dagPath, component)#(2)
		
		iter.next()

OpenMayaでは、Meshの情報にアクセスしたり変更したりするにはクラスを通して行う必要があります。今回はNormal、Tangent、Binormalを取得する必要があるので「MFnMesh」のインスタンスが必要になります。先程取得したdagPathを引数にMFnMeshのインスタンスを作成し、選択したポリゴンにアクセスできるようにしておきます(1)。

次に必要になるのは、フェイス単位で処理をするための準備です。先程登場したイテレータが今回も必要になります。フェイス単位で繰り返し処理したい場合は、「MItMeshPolygon」にdagPathとコンポーネントオブジェクトを引数にインスタンを作成します(2)。

フェイス単位の繰り返し処理の骨格

from maya import OpenMaya

def main():
	# 中略
	while not iter.isDone():
		# 中略
		
		fnMesh   = OpenMaya.MFnMesh(dagPath)
		polyIter = OpenMaya.MItMeshPolygon(dagPath, component)
		
		while not polyIter.isDone():#(1)
			polyIter.next()#(2)
			
		iter.next()

フェイス単位の繰り返し処理も、先程の繰り返し処理と同様です。whileを使って、完了するまで繰り返すようにします(1)。

こちらも忘れずに、「next()」を実行するようにし、無限ループにならないようにしましょう(2)。

Normal・Tangent・Binormalの取得

from maya import OpenMaya

def main():
	# 中略
	while not iter.isDone():
		# 中略
		while not polyIter.isDone():
			#(1)
			normal = OpenMaya.MVector()
			fnMesh.getPolygonNormal(polyIter.index(), normal)
			
			#(2)
			tangents = OpenMaya.MFloatVectorArray()
			fnMesh.getFaceVertexTangents(polyIter.index(), tangents)
			tangent = tangents[0]
			
			#(3)
			binormals = OpenMaya.MFloatVectorArray()
			fnMesh.getFaceVertexBinormals(polyIter.index(), binormals)
			binormal = binormals[0]
			
			polyIter.next()
			
		iter.next()

最初は、法線を取得します。MVectorのインスタンスを用意して、MFnMeshの「getPolygonNormal」に欲しいフェイスのIndexと一緒にぶち込みます(1)。

次にTangentの取得です。Tangentを頂点の数だけ情報があるので「MFloatVectorArray」のインスタンスを用意します。必要なのは1つだけなので、最初の要素だけを取り出します(2)。

最後はBinormalの取得です。こちらもTangentと同様に頂点の数だけ情報があるので、同様の流れで取得します(3)。

外積、内積を求める

from maya import OpenMaya

def main():
	# 中略
	while not iter.isDone():
		# 中略
		while not polyIter.isDone():
			# 中略
			
			cross = tangent ^ binormal#(1)
			dot   = OpenMaya.MFloatVector(normal) * cross#(2)
			if dot < 0:#(3)
				result.add(dagPath, polyIter.currentItem())#(4)
			
			polyIter.next()
			
		iter.next()

外積、内積を求めるには、自力で計算してもOKですが、どうせOpenMayaを使うならMFloatVectorを使うとお手軽かもしれません。

まずは、TangentとBinormalの外積を求めます。MFloatVectorを使った場合は、演算子「^」を使うだけで外積を求めることができます(1)。

次に、法線と内積を求めて表裏を判断していきます。取得した法線の情報は「MVector」で計算しにくいので「MFloatVector」に変換して、演算子「*」を使って計算すれば内積を求められます(2)。

内積で得た値は、多少の誤差が考えられますので、「0以上なら表、それ以外は裏」っとすると良いかもしれません(3)(*´ω`*)b

裏の場合は、フェイスの情報をリストに追加します(4)。

UVが裏のフェイスを選択する

from maya import OpenMaya

def main():
	# 中略
	while not iter.isDone():
		# 中略
		while not polyIter.isDone():
			# 中略
			polyIter.next()
		iter.next()
		
	OpenMaya.MGlobal.setActiveSelectionList(result)#(1)

OpenMayaで選択を変更する場合は、「MGlobal」の「setActiveSelectionList」にリストを渡せば選択が切り替わります!(1)


せっかくだし、、、あまり情報がないし、、、っということで、OpenMayaオンリーでやってみました。フリップしたUVを選択する以外にも、何かご参考になる箇所があれば幸いです。(*´ω`*)

この記事がイイネ!っと思ったら、ぜひSNSで拡散お願い致します!