LoginSignup
2
0

More than 1 year has passed since last update.

nurbsCurveでzipperする

Last updated at Posted at 2022-11-30

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

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

案だし

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

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

blendShapeでやってみる

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

image.png

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

まずは 青カーブをターゲットとしてblendShapeを適用。
image.png

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

image.png

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

image.png

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

スクリプト化

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

まずは blendShapeの適用

import maya.cmds as cmds

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

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

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

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)
 

パラメーターを設置するノードを指定し、主パラメーターを追加。

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にコネクト
という流れ

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

ひとまず出来ました。

課題

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0