mayaの環境を構築していく 8日目

花粉がつらくなってきたので、引き籠ってmayaの環境を整えよう。

さてさて前回はメニューバーにツールを登録したわけで、今回は少しリグっぽい事を進めようかと。

リグを組むにあたって必要なものは膨大にありますが、ビジュアル面だとコントローラー（マニュピレーター）の見た目。

コントローラーの見た目をどう作るか

- nurbsCurveで作成
- nurbsSurfaceで作成
- カスタムロケーターで作成

まぁ色々ありますね。

カスタムロケーター
-
プラグインを作らねばならぬと・・・・
ちょっと今の自分にはハードル高めなので、未来への遺産としてメモ

https://dftalk.jp/?p=3175

nurbsCurveで作成　nurbsSurfaceで作成
-
この辺を参考にしてみれば、作れますね。

https://tech-art.online/maya-design-rigctrl/

とりあえず nurbsCurveで作る事にします。

形状の取得
-
nurbsCurveで色んな形状つくりたいですが、いきなりコマンドから作るのは難しいので

- まず手動で作成
- 作成したカーブの形状情報を取得
- 形状情報を元に再現する

という流れで。

形状情報を元に再現する為に必要な情報を調べる為に、

**OpenMaya.MFnNurbsCurve.create()**

を調べてみる
cvs, knots, degree, form, is2D, rational, parent.....
なるほど。

- **cvs(CVの位置情報)**
既存のnurbsCurveからCVの位置を取得したい。
眺めているとそれっぽいものを発見。
**OpenMaya.MFnNurbsCurve.cvPositions()**

```
sellist = om.MGlobal.getSelectionListByName(target)
dagPath = sellist.getDagPath(0)
FnShape = om.MFnNurbsCurve(dagPath)
targetCvPositions = FnShape.cvPositions(om.MSpace.kWorld)
```
MPointで返ってくるのか・・・・
もし [[x,y,z],[x,y,z].....]な感じのarrayで返ってきてほしいなら

```
sellist = om.MGlobal.getSelectionListByName(target)
dagPath = sellist.getDagPath(0)
FnShape = om.MFnNurbsCurve(dagPath)
targetCvPositions = []
for position in FnShape.cvPositions(om.MSpace.kWorld):
    targetCvPositions.append(list(position)[:3])
```
と、こんな感じかしら。

- **knots**
既存のnurbsCurveからknotを取得したい。
眺めているとそれっぽいものを発見。
**OpenMaya.MFnNurbsCurve.knots()**

```
sellist = om.MGlobal.getSelectionListByName(target)
dagPath = sellist.getDagPath(0)
FnShape = om.MFnNurbsCurve(dagPath)
targetKnots = FnShape.knots()
```
ok　取れた。
※以前は取得の方法が判らなかったので、生成時にknotsも別途算出して生成してました。

- degree と form
**OpenMaya.MFnNurbsCurve.degree**
**OpenMaya.MFnNurbsCurve.form**
はい。

一旦まとめると

```
sellist = om.MGlobal.getSelectionListByName(target)
dagPath = sellist.getDagPath(0)
FnShape = om.MFnNurbsCurve(dagPath)
targetCvPositions = FnShape.cvPositions(om.MSpace.kWorld)
targetKnots = FnShape.knots()
targetForm = FnShape.form
targetDegree = FnShape.degree
```

is2D, rational, parent この辺は今はいらないので無視。

形状の作成
-
取った情報からOpenMaya.MFnNurbsCurve.create()が実行できるかやってみる。

適当なnurbsCurveを用意
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/60da94d2-a25f-0e28-f1e5-ece6b46967c9.png)

空のMFnNurbsCurveを作ってcreate
```
target = "curve1"
sellist = om.MGlobal.getSelectionListByName(target)
dagPath = sellist.getDagPath(0)
FnShape = om.MFnNurbsCurve(dagPath)
targetCvPositions = FnShape.cvPositions(om.MSpace.kWorld)
targetKnots = FnShape.knots()
targetForm = FnShape.form
targetDegree = FnShape.degree
NewFnShape = om.MFnNurbsCurve()
NewFnShape.create(targetCvPositions, targetKnots, targetDegree, targetForm, False, False)
```
はいできた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/ea9afaea-b882-7835-8002-c5b89e361a28.png)

形状情報のdict化
-
過去に作った形状をいつでも呼び出せるように、形状情報をdict化して呼び出せるようにしておく。

再現したい形状を手動で作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/0df10398-f4a4-ed52-f3fb-0d3b991ed581.png)

形状情報を取得してprint
```
import maya.api.OpenMaya as om
target = "curve1"
sellist = om.MGlobal.getSelectionListByName(target)
dagPath = sellist.getDagPath(0)
FnShape = om.MFnNurbsCurve(dagPath)
targetCvPositions = FnShape.cvPositions(om.MSpace.kWorld)
targetKnots = FnShape.knots()
targetForm = FnShape.form
targetDegree = FnShape.degree
targetInfoDict = {
                    "cvs":targetCvPositions,
                    "knots":targetKnots,
                    "form":targetForm,
                    "degree":targetDegree
                    }
print targetInfoDict 
```

arrowって名前にしましょう
```
curveShapeDict = {
"arrow":{'knots': maya.api.OpenMaya.MDoubleArray([0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]), 'cvs': maya.api.OpenMaya.MPointArray([maya.api.OpenMaya.MPoint(-0.099999994039535522461, 0, -0.5, 1), maya.api.OpenMaya.MPoint(-0.099999994039535522461, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(-0.30000001192092895508, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(0, 0, 0.5, 1), maya.api.OpenMaya.MPoint(0.30000001192092895508, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(0.10000002384185791016, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(0.10000002384185791016, 0, -0.5, 1), maya.api.OpenMaya.MPoint(-0.099999994039535522461, 0, -0.5, 1)]), 'form': 1, 'degree': 1}
}
```



```
import maya.api.OpenMaya as om

def createCurveShape(shapeName):
    curveShapeDict = {
    "arrow":{'knots': maya.api.OpenMaya.MDoubleArray([0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]), 'cvs': maya.api.OpenMaya.MPointArray([maya.api.OpenMaya.MPoint(-0.099999994039535522461, 0, -0.5, 1), maya.api.OpenMaya.MPoint(-0.099999994039535522461, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(-0.30000001192092895508, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(0, 0, 0.5, 1), maya.api.OpenMaya.MPoint(0.30000001192092895508, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(0.10000002384185791016, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(0.10000002384185791016, 0, -0.5, 1), maya.api.OpenMaya.MPoint(-0.099999994039535522461, 0, -0.5, 1)]), 'form': 1, 'degree': 1}
    }
    
    NewFnShape = om.MFnNurbsCurve()
    NewFnShape.create(is2D = False,rational =False,**curveShapeDict[shapeName])

createCurveShape("arrow")

```
あれ？上手く行かない。エラー出る。
```
# Error: TypeError: file <maya console> line 9: Required argument '' (pos 1) not found # 
```

うーんちょっと眠くて考えるのが面倒だから、
```
import maya.api.OpenMaya as om

def createCurveShape(shapeName):
    curveShapeDict = {
    "arrow":{'knots': maya.api.OpenMaya.MDoubleArray([0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]), 'cvs': maya.api.OpenMaya.MPointArray([maya.api.OpenMaya.MPoint(-0.099999994039535522461, 0, -0.5, 1), maya.api.OpenMaya.MPoint(-0.099999994039535522461, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(-0.30000001192092895508, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(0, 0, 0.5, 1), maya.api.OpenMaya.MPoint(0.30000001192092895508, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(0.10000002384185791016, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(0.10000002384185791016, 0, -0.5, 1), maya.api.OpenMaya.MPoint(-0.099999994039535522461, 0, -0.5, 1)]), 'form': 1, 'degree': 1}
    }
    
    NewFnShape = om.MFnNurbsCurve()
    NewFnShape.create(
                        curveShapeDict[shapeName]["cvs"],
                        curveShapeDict[shapeName]["knots"],
                        curveShapeDict[shapeName]["degree"],
                        curveShapeDict[shapeName]["form"],
                        False,
                        False
                       )
                       
createCurveShape("arrow")
```
はい、再現できた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/a6853324-4005-034f-109a-47a0ea695da4.png)

shapeだけ作ってtransformノードは自動でなので、transformノードを返すようにしようか。
dictを内包するのはちょっと違う気もするので、これも外に移動。
単純にcurveだけを作るようにしてしまうとこんな感じかしら

```
import maya.api.OpenMaya as om

def createCurveShape(cvs,knots,degree,form):    
    NewFnShape = om.MFnNurbsCurve()
    NewFnShape.create(cvs,knots,degree,form,False,False)
    return NewFnShape.parent(0)


def createCtrlNode(shapeName,nodeName):
    curveShapeDict = {
        "arrow":{'knots': maya.api.OpenMaya.MDoubleArray([0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]), 'cvs': maya.api.OpenMaya.MPointArray([maya.api.OpenMaya.MPoint(-0.099999994039535522461, 0, -0.5, 1), maya.api.OpenMaya.MPoint(-0.099999994039535522461, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(-0.30000001192092895508, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(0, 0, 0.5, 1), maya.api.OpenMaya.MPoint(0.30000001192092895508, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(0.10000002384185791016, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(0.10000002384185791016, 0, -0.5, 1), maya.api.OpenMaya.MPoint(-0.099999994039535522461, 0, -0.5, 1)]), 'form': 1, 'degree': 1}
    }
    
    ctrlNode = createCurveShape(**curveShapeDict[shapeName])        
    dgModifier = om.MDGModifier()
    dgModifier.renameNode(ctrlNode, nodeName)
    dgModifier.doIt()    
    return ctrlNode
    
createCtrlNode("arrow","hoge_ctrl")
```

これだとサイズが指定できないので、サイズも指定できるようにしておこうかと思います。



```
import maya.api.OpenMaya as om

def createCurveShape(cvs,knots,degree,form):    
    NewFnShape = om.MFnNurbsCurve()
    NewFnShape.create(cvs,knots,degree,form,False,False)
    return NewFnShape.parent(0)


def createCtrlNode(shapeName,nodeName,size):
    curveShapeDict = {
        "arrow":{'knots': maya.api.OpenMaya.MDoubleArray([0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]), 'cvs': maya.api.OpenMaya.MPointArray([maya.api.OpenMaya.MPoint(-0.099999994039535522461, 0, -0.5, 1), maya.api.OpenMaya.MPoint(-0.099999994039535522461, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(-0.30000001192092895508, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(0, 0, 0.5, 1), maya.api.OpenMaya.MPoint(0.30000001192092895508, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(0.10000002384185791016, 0, 0.19999998807907104492, 1), maya.api.OpenMaya.MPoint(0.10000002384185791016, 0, -0.5, 1), maya.api.OpenMaya.MPoint(-0.099999994039535522461, 0, -0.5, 1)]), 'form': 1, 'degree': 1}
    }
    
    ctrlNode = createCurveShape(**curveShapeDict[shapeName])
        
    dgModifier = om.MDGModifier()
    dgModifier.renameNode(ctrlNode, nodeName)
    dgModifier.doIt()
                    
    cmds.xform(om.MFnDagNode(ctrlNode).fullPathName(), scale = [size,size,size], ws = True)
    cmds.makeIdentity(om.MFnDagNode(ctrlNode).fullPathName(), a =True, r=True, s =True)
    
    return ctrlNode
    
createCtrlNode("arrow","hoge_ctrl",1.0)

```

xformのところがなんか不細工なので、なんとかしたいなぁ・・・・

**とここでundoがおかしい。**
**というかundoできない。**
はて？

https://www.klab.com/jp/blog/creative/2019/22254719.html

>openmaya for Python API では、undo・redo機能は提供されていません。
そもそも処理したことが待ち行列にスタックされないため、undoを行っても
openmaya for Python APIを実行する前の履歴が実行され、処理したことはそのまま残り続けます。

おー・・・・・どおりで。
変えましょう。


```
import maya.api.OpenMaya as om

def createCurveShape(cvs,knots,degree,form):
    periodic = False
    if form == 3:
        periodic = True
        
    curve = cmds.curve(point = cvs, knot = knots, degree = degree,periodic = periodic)    
    return curve

def createCtrlNode(shapeName,nodeName,size):
    curveShapeDict = {
        "arrow":{'knots': [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 'cvs': [[-0.09999999403953552, 0.0, -0.5], [-0.09999999403953552, 0.0, 0.19999998807907104], [-0.30000001192092896, 0.0, 0.19999998807907104], [0.0, 0.0, 0.5], [0.30000001192092896, 0.0, 0.19999998807907104], [0.10000002384185791, 0.0, 0.19999998807907104], [0.10000002384185791, 0.0, -0.5], [-0.09999999403953552, 0.0, -0.5]], 'form': 1, 'degree': 1}
    }
    
    ctrlNode = createCurveShape(**curveShapeDict[shapeName])

    ctrlNode = cmds.rename(ctrlNode,nodeName)
    cmds.xform(ctrlNode, scale = [size,size,size], ws = True)
    cmds.makeIdentity(ctrlNode, a =True, r=True, s =True)
    
    return ctrlNode
    
createCtrlNode("arrow","hoge_ctrl",1.0)

```
はい undo　効くようになりました。
GUIはまぁ適当に作っていこう。