2017年9月11日月曜日

良く使う処理はコマンドで

dirnameなんかもそうですが、良く使う処理は既にコマンド化されていたりするみたいです。

まずは親のオブジェクト名を取得する処理。
{
   string $p[]=listRelatives -p $current`;
   print("\n"+$p[0]+"\n");

}
listRelativesは文字配列を返すため、いったん配列に代入しないといけないのは頂けません。
コレの代替コマンドは
{
    string $p = firstParentOf( $current );
    print("\n"+$p+"\n");

}
文字列で返ってくるのは中々良いのですが、オブジェクト名がロングネームでしか返ってこないので注意。


こういう時など、ロング名をショート名に変更したい場合、
{
    string $tmp[]= stringToStringArray( $long,"|" );
    string $short=$tmp[size($tmp)-1];

    print("\n"+$short+"\n");

}
こんな感じで配列の最後に入った値を取得するみたいな、なかなかの面倒くささ。
ネームスペースも外したい場合、更に複雑になりますね。

でも、この処理にも、こんなそのまんまの名称のコマンドが・・・。
{
    string $short = shortNameOf( $long );

    print("\n"+$short+"\n");
}
ただし、ネームスペースは分離できないようなので、その部分は自前で処理するしかなさそうです。

plugNodeStrippedを使用するとDAGパスとネームスペースを一気に除去できます。
2017/09/20追記


で、いちばん欲しいコマンドなのですが、指定したオブジェクトがどんなタイプなのかを調べる処理。
nodeTypeで調べても大抵 "transform"と返ってきます。
なので、子のshapeノードからタイプを調べる必要があるわけですが、これに専用のコマンドは無いようで、自力で行う必要があるみたいなのですね。
こんな風に。
{
    string $shape[]=`listRelatives -c -pa -ni -s $target`;
    string $type=`nodeType $shape[0]`;

    print("\n"+$type+"\n");

}

まぁ、transformノードに色々ブラ下げていると、nodeTypeに渡す値が$shape[0]に特定できないというのが原因だとは思います。


2017年8月31日木曜日

配列の行と列を入れ替える

ロケータを4つほど作成し、それぞれ適当に移動させます。
そして、下のスクリプトを実行。

{
    string $lines[];
    $lines[0]="nodeName\ttranslateX\ttranslateY\ttranslateZ\tvisibility";
    
    string $lcts[]={"locator1","locator2","locator3","locator4"};
    
    for( $lct in $lcts )
    {
        float $tr[]=`getAttr ($lct+".t")`;
        string $vis=(`getAttr ($lct+".v")`) ? "on": "off";
        
        $lines[size($lines)]=($lct+"\t"+$tr[0]+"\t"+$tr[1]+"\t"+$tr[2]+"\t"+$vis);
        
    }
    
    print $lines;
    
    
}


スクリプトエディタの履歴をコピーしてエクセルへ貼り付けてみます。

エクセルはタブで区切られているとセルに分割された状態で貼り付けられます。
便利ですね。

上では、まだ列が少ないので良いのですが、アトリビュート値を大量にリスト化した場合、アトリビュートのヘッダーを列方向ではなく行方向に並べたい場合があります。
エクセルであれば、いったんセルをコピーして、ホームの「貼り付け」から「形式を選択して貼り付け」を選びます。

出てきたダイアログから「行列を入れ替える」にチェックを入れて[OK]します。

すると、行列が入れ替わった状態で貼り付けされました。

で、これを何回も行う場合、面倒なので行列の入れ替をMEL側で行いたい。
そんなスクリプトを作成。


引数に「文字配列」と「セパレータの文字」を渡すと行列を入れ替えてくれます。
冒頭のスクリプトであれば、print $lines;の下に


    print("\n-- new lines --\n");
    string $newLines[]=stringArrayTranspose( $lines,"\t");
    print $newLines;
    


を追加すれば、
うまく入れ替わってくれているようです。



2017年8月21日月曜日

日本語と英語のフォントサイズ

ツールを作る場合、ウィンドウに項目を並べたい場合があります。
サンプルスクリプトとしてはこんな感じ。

proc string _createLabelFrame(
       int $w ,                         // 幅px
    string $align,                      // 位置合わせ"left","right","center"
    string $label )                     // ラベル文字
{
    string $frame=`frameLayout -lv 0 -bv 1 -w $w -mw 6`;
        text -l $label -al $align;
        setParent ..;
    
    return $frame;
    
}


global proc labelTest()
{
    string $win="testWindow";
    
    if(`window -q -ex $win`) deleteUI $win;
    window $win;
    
        rowLayout -nc 4;
            _createLabelFrame( 46,"center","項目A" );
            _createLabelFrame( 96,"center","けっこう長い項目B" );
            _createLabelFrame( 96,"left","項目C" );
            _createLabelFrame( 96,"right","項目D" );
    
    window -e -w 342 -h 32 $win;
    
    showWindow $win;
    
}


実行するとこんな感じのウィンドウになります。


で自分は普段英語版を使うわけですが、世の中にはmaya日本版と言う物があるのです。
同じスクリプトを日本語版で実行した結果。


ギリギリを攻めていた「項目A」と「けっこう長い項目B」が枠からハミ出ています。
良く見ると高さも若干広まっていますね。

どうやら英語版と日本語版ではフォントサイズが違っているようで、レイアウトが崩れてしまう様子。
けれどもMELにはフォントサイズを変更するオプションはありませんが、フォントスタイルを、
「boldLabelFont」
「smallBoldLabelFont」
「tinyBoldLabelFont」
「plainLabelFont」
「smallPlainLabelFont」
「obliqueLabelFont」
「smallObliqueLabelFont」
「fixedWidthFont」
「smallFixedWidthFont」
から指定できるようです。

ただ、それぞれを指定して比較するのは中々面倒です。
実はmayaのインストールフォルダのresourcesに MayaStrings というファイルがあります。
そのファイルの中から s_TschemeResourcesFlatUI という単語を検索すると、

こんな感じで各言語のフォントサイズらしき物を発見できました。

で、全言語同じフォントで同じサイズの「smallFixedWidthFont」を指定します。
text -l $label -al $align -fn "smallFixedWidthFont";


編集して日本語mayaで実行した結果


英語と同じになりました。
配置に凝ったUIを組む時はFixedWidthFontくらいしか使えないので要注意です。

2017年7月31日月曜日

stringToStringArrayコマンドで注意すること

stringToStringArray、文字列を指定した文字で分割するコマンド 。
で.csvファイルを分割する時に大活躍するコマンドです。

ただ、特定の条件下で想定しない挙動を示します。
ちなみに.csvファイルとは、カンマで区切られた値の集合。

string $csv="A,B,C,D,E,F,";
を分割する場合、
string $array[]=stringToStringArray( $csv,"," );

と書き、戻ってきた$arrayは、こんな感じになります。
0: A
1: B
2: C
3: D
4: E
5: F

しかし、渡す文字列の「C」を削って、
string $csv="A,B,,D,E,F,";
こういう風にカンマが連続している場合の$arrayは
0: A
1: B
2: D
3: E
4: F

と、「C」に当たる$array[2]がブランクではなく「D」以降の文字が繰上げで代入されています。

string $csv="A,B, ,D,E,F,";
とスペースを入れてあったりする場合は、
0: A
1: B
2:  
3: D
4: E
5: F

と、$array[2]にはスペースが入ります。
stringToStringArrayと似たようなコマンド、tokenizeでも同じ事が起きます。
これがバグなのか仕様なのかは不明。

回避するためには自分でナントカするしかないようです。
で、ナントカしたスクリプト。

引数の文字数を2回ループさせているので、処理速度的に1回で済ますようにした方が良いのかなぁ・・・。
1回にするとifを挟むので、それがネックになりそうだし。
難しい。

2017年7月24日月曜日

ノードをレイヤーに登録させない

表示/非表示を簡単に切り替えたりするのに便利なレイヤーですが、モーションなどを外注に出したりした場合、まれにコチラで作成したリグをレイヤーに登録しやがる不届き者が居たりします。
コレをやられると、リグのcurveShapeに設定した overrideColor がレイヤーの色で上書きされてしまい復元できなくなります。要するにリグを破壊されてしまうと言うわけですね。

多くの人は、階層をレイヤーへ登録する場合、なにげなく Select Hierarchy でオブジェクトを選択して、なんとなくレイヤーへ Add Selected Objects で追加していると思います。


意外と忘れられがちですが、こういう風に選択すると shapeノードも選択していることになります。

nodeEditorで確認すると・・・


レイヤーから shapeノードへ素敵なサムシングが接続されています。
Relationsip Editorでも確認できますね。

こうしない為には、Select Hierarchyの後に、

select -d (`ls -sl -s`);

をコマンドラインで実行させる必要があるのです。

面倒です。

発注書とかでネガティブリストを作っても、まぁ守られることはありません。
で、防衛の為にレイヤーへノードを登録させないように細工をしておく必要があるのです。

要は接続できないようにアトリビュートをロックしておけば良い訳です。
どのアトリビュートに接続されているかを確認。


drowOverrideと云うアトリビュートらしい。
いったん全てのオブジェクトをレイヤーから外して、アトリビュートをロックするためのコマンド

setAttr -lock on "locatorShape1.drawOverride";

を実行します。
すると、先ほどの手順でレイヤーへ追加しようとしても

// Error: line 0: Connection not made: 'layer1.drawInfo' -> 'locatorShape.drawOverride'.  Destination is locked. // 

と、エラーでレイヤーへの追加処理が止まりました。
最低でも shapeノード、できればリグのノードの全部のアトリビュートをロックしておけば、レイヤーへ登録しようとしている輩の心をへし折る事ができるでしょう。

こういう事をしておくと、たまに闘志を燃やす変態さんも居たりしますけどね。

ここに・・・。