nurbsCurveでzipperする

nurbsCurveを使って　zipperの様な構造を作りたいなぁと。
片方の端から順番にくっついていくイメージで。

CVが指定の位置に移動してくれればいいのだけども、さてCVの位置をどのように移動させたものか

案だし
--

+ cvPosition　にコネクト
割とお手軽な気もするんだけども、スキニングできなくなってしまう。
zipperするカーブ -> スキニングするカーブ　ってヒストリ繋げちゃえば大丈夫かも？

+ blendShape
形状とか考えると手間はすくなそう。
blendShape後にスキニングも可能。
ただし一斉に移動してしまう。CV毎のウェイトを操作すればいけるかも？


blendShapeでやってみる
--

今回はblendShapeでやってみようかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/7f55c361-3fb8-9081-47e4-90411e7fcb86.png)

赤いカーブを青いカーブにフィットさせてみます。

まずは 青カーブをターゲットとしてblendShapeを適用。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/d07a0395-cfcd-4005-6483-9219f2aa4414.png)

それぞれのCVが対応するCVに対してリニアに移動していきます。
ただ、今回はこれは理想的ではないので各コンポーネントのウェイトを見てみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/4bd9868a-dcd2-c7b3-3348-67f234128676.png)


全体のweightに対して、各コンポーネントのウェイトが乗算される感じですね。
さて、このアトリビュートの本体はどこにあるか・・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/16ef3ede-0986-21c4-3741-bf1e3b711612.png)

色々いじってみて発見。 targetWeights
このattrに対して順番に数値を入れて行けばzipperできる　はず。


スクリプト化
--

- 全体のパラメーターは 0 ~ 1.0
- CVのindex は 0 ～　順番に処理(今回両端は元からくっ付いてるけども無視）


まずは blendShapeの適用

```python
import maya.cmds as cmds

def curveZipper(startCurve,targetCurve):
    cmds.blendShape(targetCurve,startCurve,parallel =False, o = "local",name = startCurve + "_BS", w = [(0,1)])

```
ウェイトは各コンポーネントのウェイトで制御するので、ターゲットウェイトは最初から１に設定

blendShapeNodeのtargetWeightsを順番に処理したいので、
cvのindexを取得。今回はかなり適当に取得


```python
import maya.cmds as cmds

def curveZipper(startCurve,targetCurve):
    BSNode = cmds.blendShape(targetCurve,startCurve,parallel =False, o = "local",name = startCurve + "_BS", w = [(0,1)])[0]

    CVs = cmds.ls(startCurve + ".cv[*]",fl =True)
 
```

パラメーターを設置するノードを指定し、主パラメーターを追加。
```python
import maya.cmds as cmds

def curveZipper(startCurve,targetCurve,paramCtrl):
    BSNode = cmds.blendShape(targetCurve,startCurve,parallel =False, o = "local",name = startCurve + "_BS", w = [(0,1)])[0]

    CVs = cmds.ls(startCurve + ".cv[*]",fl =True)
    cmds.addAttr(paramCtrl, ln = "zipper",at = "double", dv = 0.0, min = 0.0, max = 1.0, k = True)        
 
```

0.0~1.0 を cvの数で分割し、各範囲の数値をsetRangeをつかって0.0~1.0 に変換。
その結果を各targetWeightにコネクト
という流れ

```python
import maya.cmds as cmds
def curveZipper(startCurve,targetCurve,paramCtrl):
    BSNode = cmds.blendShape(targetCurve,startCurve,parallel =False, o = "local",name = startCurve + "_BS", w = [(0,1)])[0]

    CVs = cmds.ls(startCurve + ".cv[*]",fl =True)
    cmds.addAttr(paramCtrl, ln = "zipper",at = "double", dv = 0.0, min = 0.0, max = 1.0, k = True)
    paramDif = 1.0 / len(CVs)

    for i in range(0,len(CVs)):
        setRange = cmds.createNode("setRange")
        startParam = paramDif * i
        endParam = paramDif * (i+1)

        cmds.connectAttr(paramCtrl + ".zipper", setRange + ".valueX")
        cmds.setAttr(setRange + ".oldMinX",startParam)
        cmds.setAttr(setRange + ".oldMaxX",endParam)        

        cmds.setAttr(setRange + ".minX",0.0)
        cmds.setAttr(setRange + ".maxX",1.0) 

        cmds.connectAttr(setRange + ".outValueX",BSNode + ".inputTarget[0].inputTargetGroup[0].targetWeights["+str(i)+"]")

curveZipper("curve1","curve2","null1")

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/b69e7ece-ed75-2321-31c0-e25edb3051f2.png)

ひとまず出来ました。

課題
--

- 元からくっ付いてる　最初と最後は処理から除外してもいいかもしれない
- CVの位置が均等ではないので、0.0～1.0を均等に分割すると移動速度に差が出てしまう。
- 0~-1.0で反対向きからとかもできるかもしれない。
- 1CVに１つsetRangeが作られるのがなんか無駄感ある。