オブジェクトの位置をリセットして綺麗なデータを作ろう

こんにちは!Rhinoです。
早いもので、もう5月も終わりですね。
1日1日を大切にしたいところですが、今年は特に時間が経つのが早いです。

さて、今日はオブジェクトの位置について書きたいと思います。
モデリングをしているとピボットの位置をtranslateの値がずれたりすることがないでしょうか?

ピットを動かすとずれてしまいますよね。
今日はこれをリセットするスクリプトを書いてみました。

# -*- coding: utf-8 -*-
import maya.cmds as cmds

sel = cmds.ls( sl=True, fl=True, type="transform" )

for s in sel:
	parent = cmds.listRelatives( s, ap=True, f=True )
	if parent != None:
		cmds.parent( s, w=True )
		s = cmds.ls( sl=True )[0]
		
	trs = list(cmds.getAttr( s + ".translate" )[0])
	rot = list(cmds.getAttr( s + ".rotate" )[0])
	scl = list(cmds.getAttr( s + ".scale" )[0])
	
	#Pivot World Positon
	pp = cmds.xform( s, q=True, sp=True, ws=True )
	
	for i in range(3):
		pp[i] *= -1
		
	cmds.setAttr( s + ".translate", trs[0]+pp[0], trs[1]+pp[1], trs[2]+pp[2], type="double3" )
	cmds.setAttr( s + ".rotate", 0, 0, 0, type="double3" )
	cmds.setAttr( s + ".scale", 1, 1, 1, type="double3" )
	
	cmds.makeIdentity( s, a=True, t=True, r=True, s=True, n=0, pn=True )
	cmds.makeIdentity( s, a=False, t=True, r=True, s=True )
	
	for i in range(3):
		pp[i] *= -1
		
	cmds.setAttr( s + ".translate", pp[0], pp[1], pp[2], type="double3" )
	cmds.setAttr( s + ".rotate", rot[0], rot[1], rot[2], type="double3" )
	cmds.setAttr( s + ".scale", scl[0], scl[1], scl[2], type="double3" )
	
	if parent != None:
		cmds.parent( s, parent[0] )

解説

フローについて

フローはこのように考えてみました。
僕はグループ化などを多用することが多いため、親子関係の一時的な解除も行っています。

親子関係があるかどうか?

親子関係があるかどうかを調べるには親を取得してみれば分かります。
Noneが返ってきたら親がない、つまり親子関係を結んでいないということですね。
これはグループ化なども含まれます。
親の取得にはlistRelatives関数を使います。
返ってきた値はNoneでなければ、親子関を結んでいるということですので、
parent関数のworld(w)フラグにTrueを与えて親子関係を解除します。
その後、もともとループしているオブジェクトは親子関係を解除する前のものですので、解除したあとのオブジェクトを再度取得します。

	parent = cmds.listRelatives( s, ap=True, f=True )
	if parent != None:
		cmds.parent( s, w=True )
		s = cmds.ls( sl=True )[0]

Transformアトリビュートの値を取得

予めTransformアトリビュートのtranslate(移動)、rotate(回転)、scale(スケール)の値を取得しておきます。
この値を使って原点に移動するためです。
getAttrを使うのが便利です。
list関数で括っているのは値がタプルで返ってくるのですが、値を後の計算で使いたかったので、listに変換する為です。
もっと良い方法があるかもしれません(;´д`)トホホ

	trs = list(cmds.getAttr( s + ".translate" )[0])
	rot = list(cmds.getAttr( s + ".rotate" )[0])
	scl = list(cmds.getAttr( s + ".scale" )[0])

ピボットの位置を取得

ピボットの位置を取得するにはxform関数を使います。
今回はscaleピボットをワールド座標で取得しました。
#Pivot World Positonコメントといってプログラムの実行には影響がでない文になります。メモを残したりするのに便利ですよ。

	#Pivot World Positon
	pp = cmds.xform( s, q=True, sp=True, ws=True )

原点に移動する

オブジェクトを原点に移動します。
手作業でリセットする場合にも原点に一度移動しますよね?あの作業と同じです。
戻すには移動、回転、スケールで次のような操作をします。

  • 移動   現在の移動値を引いて、ピボットの位置を足す
  • 回転   すべて0(ゼロ)にする
  • スケール すべて1にする

これらの値をsetAttrで各アトリビュートに与えます。
getAttrにはなかったtype=”double3″という記述がありますね?
座標というのは浮動小数からなる3つの値ですよね。
この記述は与えた値がどういうものなのかというのを示しています。。

	for i in range(3):
		pp[i] *= -1
		
	cmds.setAttr( s + ".translate", trs[0]+pp[0], trs[1]+pp[1], trs[2]+pp[2], type="double3" )
	cmds.setAttr( s + ".rotate", 0, 0, 0, type="double3" )
	cmds.setAttr( s + ".scale", 1, 1, 1, type="double3" )

フリーズ&リセット

モデラーの方はよく行う操作ではないでしょうか?移動値などをリセットする操作ですね。これにはmakeIdentity関数を使います。

	cmds.makeIdentity( s, a=True, t=True, r=True, s=True, n=0, pn=True )
	cmds.makeIdentity( s, a=False, t=True, r=True, s=True )

Transformアトリビュートの値を戻す

リセットが終わりましたら、取得していた値を各アトリビュートに与えて戻していきます。移動値は引き算するために一度-1をかけていましたので、再度-1をかけて値を戻しておきました。

	for i in range(3):
		pp[i] *= -1
		
	cmds.setAttr( s + ".translate", pp[0], pp[1], pp[2], type="double3" )
	cmds.setAttr( s + ".rotate", rot[0], rot[1], rot[2], type="double3" )
	cmds.setAttr( s + ".scale", scl[0], scl[1], scl[2], type="double3" )

親子関係を戻す

最後に親子関係があった場合はこれを戻す必要がありますね。
parent関数を使って親子関係を取得してた親オブジェクトの子供として結びます。
第一引数が子供で、第二引数が親です。

	if parent != None:
		cmds.parent( s, parent[0] )

最後に

業務中にオブジェクトを置き換えてようとした際に、位置情報がくるっていたいので、急いで作ったものだったりします。
もっと良い書き方あるのでしょうが、それは僕がプログラマーではないための実力不足でしょうね( ;∀;)もっと勉強せねば!
それなり役にたっていますので、皆さんもぜひ挑戦して下さい。
では、また!

コメント

タイトルとURLをコピーしました