Ramp制御を含むGUIを作る

この記事はMaya Advent Calender 2020の3日目の記事です。
AdventCalenderに初めて参加させていただきます。

#はじめに

Rampのカーブを入力として利用したツールを制作する為に調べました。
今回は、PySideではなくmayaコマンドでGUIを作っています。

![GUI.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491414/d1a5bf10-6e19-3d8e-6c35-3aa2a6dd38b8.png)


#サンプル
下記のコードを実行すると、GUIが表示されます。

```Python
import maya.cmds as cmds
import maya.mel as mel

class rampWindow(object):
	@classmethod
	def showUI(cls):
		"""
		showUI
			UIを表示させます。
		"""	
		win = cls()
		win.create()
		return win

	def deleteUI(self, *args):
		"""
		deleteUI
			UIを削除します。
			rampアトリビュート用のNullを削除します。
		"""	
		cmds.deleteUI(self.window, window=True)
		self.deleteRampNode()

	def deleteRampNode(self, *args):
		"""
		deleteRampNode
			rampアトリビュート用のNullを削除します。
			ウィンドウの×を押した時のコマンド用。
		"""	
		if cmds.ls(self.nodeName):
			cmds.delete( self.nodeName )
					
	def __init__(self):
		"""
		__init__
			初期化。
		"""	
		self.window = 'rampWindow'
		self.title = 'rampWindow'
		self.width=200

		self.rampName = "ramp"
		self.nodeName = "rampNull"

	def create(self):
		"""
		create
			レイアウト作成。
		"""	

		#	多重ウィンドウ対応
		if cmds.window(self.window, exists=True):
			self.deleteUI()

		#	rampアトリビュート用Nullを作成
		cmds.group(em=True, n=self.nodeName)
		createRampAttrbute( self.nodeName, self.rampName )

		#	ウィンドウ作成
		self.window = cmds.window( self.window, t=self.title, w=self.width, cc=self.deleteRampNode )
		cmds.columnLayout()
			
		#	Layout　Frame Range
		rampLayout( self.nodeName, self.rampName )

		cmds.showWindow(  )

def createRampAttrbute( nodeName, rampName ):
	"""
	createRampAttrbute
		RampAttrbuteを設定します。	
	Args:
		String　nodeName  :   RampAttrbuteの追加するノード名
		String　rampName  :   RampAttrbute名
	"""
	cmds.addAttr( nodeName, ln=rampName, at='compound', nc=3, m=True)
	cmds.addAttr( nodeName, ln='ramp_Position', at='float', p=rampName, dv=-1)
	cmds.addAttr( nodeName, ln='ramp_FloatValue', at='float', p=rampName, dv=-1)
	cmds.addAttr( nodeName, ln='ramp_Interp', at='enum', en='None:Linear:Smooth:Spline', dv=1, min=0, max=3, p=rampName)
	cmds.setAttr( '{0}.{1}[0]'.format(nodeName, rampName), 0, 1, 2)
	cmds.setAttr( '{0}.{1}[1]'.format(nodeName, rampName), 1, 1, 2)

def rampLayout( nodeName, rampName ):
	"""
	rampLayout
		rampをレイアウトします。
	Args:
		String　nodeName  :   RampAttrbuteの追加されているノード名
		String　rampName  :   RampAttrbute名
	"""
	mel.eval('if (! exists("AEmakeLargeRamp")) source AEaddRampControl')
	mel.eval('AEmakeLargeRamp("{0}.{1}", 0, 0, 0, 0, 0)'.format(nodeName, rampName))


if __name__ == '__main__':
	rampWindow.showUI()
	
```	
#解説

+ レイアウトを行う前に、GUIで使用するRampのパラメータを保持する為にNullを用意しています。
そのNullにRampアトリビュートを追加します。

```python
#	rampアトリビュート用Nullを作成
cmds.group(em=True, n=self.nodeName)
createRampAttrbute( self.nodeName, self.rampName )
```
![ramp2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491414/07068f99-c5a2-6aff-cfd5-63d0dcccfa13.png)

+ ウィンドウを用意し、Rampをレイアウトします。

```python
mel.eval('if (! exists("AEmakeLargeRamp")) source AEaddRampControl')
mel.eval('AEmakeLargeRamp("{0}.{1}", 0, 0, 0, 0, 0)'.format(nodeName, rampName))
```

+ AEmakeLargeRamp コマンド。引数が6個必要ですが、rampのアトリビュート名を指定すれば、後は0で問題ないと思います。

```mel:AEaddRampControl.mel
global proc AEmakeLargeRamp( string $nodeAttr,
							int $bound,
							int $indent,
							int $staticEntries,
							int $staticPositions,
							int $adaptiveScaling )
```

#おまけ

実行ボタンを起動しランプの値をとる際には、Fit関数を用意すると便利です。
この関数で、パラメータの「開始値1・終了値1」間の変化を、「開始2・終了2」間の変化にマッピングします。
HoudiniのVEXライクな関数を作ってみました。

```Python
def fit(parameter, startValue1, endValue1, startValue2=0, endValue2=1):

	"""
	fit
		値の範囲を別の値にマッピングする。
	Args:
		Float　parameter  :   パラメータ
		Float　startValue1  :   開始値1
		Float　endValue1  :   終了値1
		Float　startValue2 :   開始値2
		Float　endValue2  :   終了値2
	Returns:
		Float	value  :   マッピングされたの値
	"""	

	if parameter < startValue1:
		parameter = startValue1
	if parameter > endValue1:
		parameter = endValue1
	
	Span1 = endValue1 - startValue1
	Span2 = endValue2 - startValue2

	rate = float( parameter - startValue1 ) / Span1
	value = startValue2 + ( rate * Span2 )
	return value
```

#参照
ryusas/test_falloffCurveAttr.py
https://gist.github.com/ryusas/699ad3f5fa8469a00e8df4b3672aa89f

***
Maya Python Advent Calender 2020の4日目は、it_ksさんの記事です！！