2014年12月25日木曜日

Mayaから複数テイクを含めた状態で、FBX出力する方法

Unityなどで複数アニメーションを使用する場合、FBXであらかじめ複数テイクにアニメーションが分かれていると便利なわけですが。

MayaからFBX出力する場合、複数テイクを含めることができない…と、思っていたのですが、
できたようです。
詳しい内容は、あとでもう少し調べてみますが、とりあえずメモ。走り書き。

スクリプティングで出力します。
出力する際、以下のコマンドで条件を定義してやります。

FBXExportSplitAnimationIntoTakes -v \"モーション名"\ int $start_F int $end_F

上司に「MayaからだとTake分けできないっぽいっす」とか抜かしてしまった手前…うーむ。恥ずかしい。。。

参照ドキュメント↓
http://download.autodesk.com/global/docs/maya2014/ja_jp/index.html?url=files/WN_Cloth.htm,topicNumber=d28e13616

2014年12月16日火曜日

コンストレイント・コネクション・ついでにジョイントアトリビュート一括エディット

リガー仕事で、コンストレイントやコネクションを設定することはかなり頻繁にあります。
だけど、いちいちノードひとつずつコンストレイントを設定するのは面倒だし、場合によってはポイント・オリエントコンストレイントを設定して…、ポイントコンストレイントはオフセット設定は切り…、など、いちいち細かな設定をひとつずつ行うのは時間ばかりかかって、大変です。
コネクションにしても、コネクションエディタでやるのか、ハイパーシェードでやるのか…、どちらにせよ、何らかのウインドウを開いて、いちいち設定…。結構うっとうしいです。

ちょうど今週、インフルエンザで家にこもったので(笑)、以下のようなmelツールを作成しました。

--------------------------------
①複数選択から、各種コンストレイントを1ボタンで一括設定できる
②計算式のない、単純なコネクションを同様に1ボタンで一括設定できる。
③ついでに各種ジョイントアトリビュートも同様に1ボタンで一括設定できる。
--------------------------------



他にも、割とジョイントアトリビュートの、rotateOderを再設定することがあるので、ついでに機能を追加。また、スケール対応なんかもすると、segmentScaleCompensateもいじったりするので、これも追加。
あと、蛇足ですが、ついでのついでに、ジョイントRadiusも一括設定できるように追加。
(…まぁ、Radiusは一括選択後、チャンネルボックスから設定すればいいんですけど…)

--------------------------------
以下ソース
使用の場合は、スクリプトエディタにコピーして、シェルフなどに登録して使用してください。
あとは自由に改造していただいてかまいません。

/*
------------------------------------
Constraint/Connection/Joint Edit mel
------------------------------------
*/
if(`window -q -exists CCJ_Setting`)deleteUI  CCJ_Setting;
window -s 0 CCJ_Setting;
    columnLayout -adj 1;
        string $F_LAYOUT = `frameLayout -bs "in" -cll 1 -cl 0 -l "<CONSTRAINT SET>"`;
            columnLayout -adj 1 -co "left" 1;
                rowLayout -nc 3 -cw3 110 110 110;
                    string $POC = `checkBox -label "Poin Constraint"`;
                    string $ORC = `checkBox -label "Orient Constraint"`;
                    string $SCC = `checkBox -label "Scale Constraint"`;
                setParent..;
                rowLayout -nc 3  -cw2 110 110 -cat 3 "left" 20;
                    string $PVC = `checkBox -label "poleVec Constraint"`;
                    string $PAC = `checkBox -label "Parent Constraint"`;
                    button -w 80 -l "Done" -c ("CONSTRAINT_SET(\"" + $F_LAYOUT + "\")");
                setParent..;
                frameLayout -cll 1 -cl 1 -l "Option Setting"; 
                    rowLayout -nc 4 -cw 1 80 -cat 2 "left" 0;
                        text -al "left" -l "Target Attribute";
                        string $CONST_X = `checkBox -label "X" -v 1`;
                        string $CONST_Y = `checkBox -label "Y" -v 1`;
                        string $CONST_Z = `checkBox -label "Z" -v 1`;
                    setParent..;
                    rowLayout -nc 2 -cw 1 80 -cat 2 "left" 0;
                        text -l "Maintain Offset";
                        string $CONST_OFST = `checkBox -v 1 -l ""`;
                    setParent..;
                    rowLayout -nc 3 -cw 1 80 -cat 2 "left" 0;
                        text -al "left" -l "SetTarget Mode";        
                        radioCollection;
                        string $TGT_MODE = `radioButton -label "Even-Odd" -sl`;
                        radioButton -label "Harf-Harf";                
                    setParent..;
                setParent..;
            setParent..;        
        setParent..;
        //コンストレイントセットのレイアウト情報を格納する
        frameLayout -e -docTag
                    ($POC + ";" +  $ORC + ";" +  $SCC + ";" +  $PVC + ";" +  $PAC
                    + "&" + $CONST_X + ";" + $CONST_Y + ";" + $CONST_Z
                    + "&" + $CONST_OFST + ";" + $TGT_MODE)
                    $F_LAYOUT;
        string $CNCT_F = `frameLayout -bs "in" -cll 1 -cl 0 -l "<CONNECTION SET>"`;
            columnLayout -adj 1 -co "left" 1;
                rowLayout -nc 4 -rat 1 "top" 0 -rat 2 "top" 0 -rat 3 "top" 0 -rat 4 "top" 0;
                    frameLayout -w 80 -h 84 -bs "in" -l "Attribute";
                        columnLayout ;                    
                            string $CNCT_T = `checkBox -label "translate"`;
                            string $CNCT_R = `checkBox -label "rotate"`;
                            string $CNCT_S = `checkBox -label "scale"`;
                        setParent..;                
                    setParent..;
                    frameLayout -w 78 -h 84 -bs "in" -l "source";
                        columnLayout -adj 1;
                            string $CNCT_X = `checkBox -label "X"`;
                            separator;
                            string $CNCT_Y = `checkBox -label "Y"`;
                            separator;                        
                            string $CNCT_Z = `checkBox -label "Z"`;            
                        setParent..;                
                    setParent..;
                    frameLayout -w 80 -h 84 -bs "in" -l "target";
                        columnLayout ;
                            string $TGT_X = `optionMenu -w 60`;
                                menuItem -l "X" -p $TGT_X;
                                menuItem -l "Y" -p $TGT_X;
                                menuItem -l "Z" -p $TGT_X;
                                optionMenu -e -sl 1 $TGT_X;
                            string $TGT_Y = `optionMenu -w 60`;
                                menuItem -l "X" -p $TGT_Y;
                                menuItem -l "Y" -p $TGT_Y;
                                menuItem -l "Z" -p $TGT_Y;
                                optionMenu -e -sl 2 $TGT_Y;
                            string $TGT_Z = `optionMenu -w 60`;
                                menuItem -l "X" -p $TGT_Z;
                                menuItem -l "Y" -p $TGT_Z;
                                menuItem -l "Z" -p $TGT_Z; 
                                optionMenu -e -sl 3 $TGT_Z;           
                        setParent..;                
                    setParent..;
                    columnLayout -adj 1;
                        text -l " SetTarget Mode";
                        radioCollection;
                        string $CNCT_TGT_MODE = `radioButton -label "Even-Odd" -sl`;
                        radioButton -label "Harf-Harf";
                        separator;
                        button -w 80 -l "Done" -c ("CONNECTION_SET(\"" + $CNCT_F + "\")");
                    setParent..;
                setParent..;
            setParent..;
        setParent..;
        frameLayout -e -docTag 
        ($CNCT_T + ";" + $CNCT_R + ";" + $CNCT_S + "&" + 
        $CNCT_X + ";" + $CNCT_Y + ";" + $CNCT_Z + "&" + 
        $TGT_X + ";" + $TGT_Y + ";" + $TGT_Z + "&" +
        $CNCT_TGT_MODE)
        $CNCT_F;
        
        string $JOINT_EDIT_F = `frameLayout -cll 1 -cl 0 -l "<JOINT EDIT SET>"`;
            columnLayout -adj 1 -co "left" 1;
                rowLayout -nc 2 -cat 2 "left" 5 -rat 2 "top" 1;                    
                    frameLayout -lv 0 -bs "etchedIn";                        
                        columnLayout -co "both" 5;                        
                            rowLayout -nc 2 -cw 1 80;
                                string $JON_RAD_YN = `checkBox -l "Radius"`;                   
                                string $JON_RAD = `floatField -w 60 -v 1.0 `;
                            setParent..;                    
                            rowLayout -nc 2 -cw 1 80;
                                string $JON_ROD_YN = `checkBox -l "Rotate Oder"`;                   
                                string $JON_ROD = `optionMenu -w 60`;
                                menuItem -l "XYZ" -p $JON_ROD;
                                menuItem -l "YZX" -p $JON_ROD;
                                menuItem -l "ZXY" -p $JON_ROD;
                                menuItem -l "XZY" -p $JON_ROD;
                                menuItem -l "YXZ" -p $JON_ROD;
                                menuItem -l "ZYX" -p $JON_ROD;
                                optionMenu -e -sl 1 $JON_ROD;
                            setParent..;
                                string $JON_SEG = `checkBox -v 1 -l "Segment Scale Compensate"`;
                        setParent..;
                    setParent..;
                    button -w 80 -l "Done" -c ("JOINT_EDIT_CMD(\"" + $JOINT_EDIT_F + "\")");              
                setParent..;
            setParent..;
        setParent..;
        frameLayout -e -docTag
            ($JON_RAD_YN + ";" + $JON_RAD + ";" + $JON_ROD_YN + ";" + $JON_ROD + ";" + $JON_SEG)
            $JOINT_EDIT_F;       
    setParent..;
showWindow CCJ_Setting;

//-----------------------------------------------
//ロックアトリビュートを検出
global proc vector CHECK_ATTR_LOCK(string $ATTR){
    vector $LOCKSTATE =<<0,0,0>>;
    if (`getAttr -l ($ATTR + "x")`)$LOCKSTATE = $LOCKSTATE + <<1,0,0>>;
    if (`getAttr -l ($ATTR + "y")`)$LOCKSTATE = $LOCKSTATE + <<0,1,0>>;
    if (`getAttr -l ($ATTR + "z")`)$LOCKSTATE = $LOCKSTATE + <<0,0,1>>;
    return $LOCKSTATE;
}
//-----------------------------------------------
global proc string SET_TGT_LIST(string $RADIO_BUTTON){
    //ソースノード・ターゲットノードの選択
    string $LIST[] = `ls -sl`;
    string $SCE_NODE_LIST[];
    string $TGT_NODE_LIST[];
    if(`radioButton -q -sl $RADIO_BUTTON` == 1){
        int $i = 0;
        int $j = 0;
        int $k = 0;        
        for($i = 0; $i < size($LIST)-1;$i = $i +2){            
            $SCE_NODE_LIST[$j] = $LIST[$i];
            $TGT_NODE_LIST[$k] = $LIST[$i +1];
            $j++;
            $k++;
        }
    }
    else{
        int $i = 0;
        int $j = 0;
        int $k = 0;        
        for($i = 0; $i < size($LIST);++$i){            
            if($i < (size($LIST)/2)){
                $SCE_NODE_LIST[$j] = $LIST[$i];
                $j++;
            }
            else{
                $TGT_NODE_LIST[$k] = $LIST[$i];
                $k++;
            }
        }
    }
    string $SCE_NODE_STR = stringArrayToString($SCE_NODE_LIST,";");
    string $TGT_NODE_STR = stringArrayToString($TGT_NODE_LIST,";");
    string $RETURN_STR = $SCE_NODE_STR + "&" + $TGT_NODE_STR;
    
    return $RETURN_STR;
}
//-----------------------------------------------
//一括コンストレイント処理
global proc CONSTRAINT_SET(string $F_LAYOUT){
    //レイアウト情報の格納
    string $LAYOUT_INFO[] = stringToStringArray(`frameLayout -q -docTag $F_LAYOUT`,"&");    
    string $CNST_INFO[] = stringToStringArray($LAYOUT_INFO[0],";");
    string $SKIP_INFO[] = stringToStringArray($LAYOUT_INFO[1],";");
    string $OPTN_INFO[] = stringToStringArray($LAYOUT_INFO[2],";");
    //-----------------------
    //ソースノード・ターゲットノードの選択
    string $LIST[] = `ls -sl`; 
    string $SCE_TGT_LIST[] = stringToStringArray(`SET_TGT_LIST($OPTN_INFO[1])`,"&");
    string $SCE_NODE_LIST[] = stringToStringArray($SCE_TGT_LIST[0],";");
    string $TGT_NODE_LIST[] = stringToStringArray($SCE_TGT_LIST[1],";");
    //-------------------
    //ターゲットアトリビュートの取得
    vector $TGT_ATTR = <<0,0,0>>;
    if(`checkBox -q -v $SKIP_INFO[0]` == 1)$TGT_ATTR = $TGT_ATTR + <<1,0,0>>;
    if(`checkBox -q -v $SKIP_INFO[1]` == 1)$TGT_ATTR = $TGT_ATTR + <<0,1,0>>;
    if(`checkBox -q -v $SKIP_INFO[2]` == 1)$TGT_ATTR = $TGT_ATTR + <<0,0,1>>;
    //ポイントコンストレイント処理   
    if(`checkBox -q -v $CNST_INFO[0]`){     
        string $TGT_NODE;
        int $i = 0;    
       for($TGT_NODE in $TGT_NODE_LIST){
           //ロックアトリビュートを除外する
            vector $LOCKSTATE = `eval ("CHECK_ATTR_LOCK(\"" + $TGT_NODE + ".t\")")`;
            if($LOCKSTATE < <<1,1,1>>){         
                vector $SKIP_ATTR = $TGT_ATTR - $LOCKSTATE;
                //コンストレイント文を変数定義する
                string $EVAL_STRING = "pointConstraint -weight 1";
                if(`checkBox -q -v $OPTN_INFO[0]` == 1) $EVAL_STRING = $EVAL_STRING + " -mo";
                if($SKIP_ATTR.x <1) $EVAL_STRING = $EVAL_STRING + " -sk x";
                if($SKIP_ATTR.y <1) $EVAL_STRING = $EVAL_STRING + " -sk y";
                if($SKIP_ATTR.z <1) $EVAL_STRING = $EVAL_STRING + " -sk z";
                $EVAL_STRING = $EVAL_STRING + " " + $SCE_NODE_LIST[$i] + " " + $TGT_NODE + ";";
                eval $EVAL_STRING;
            }
            else{
                print $TGT_NODE;
                print " : pointConstraint Skipped...\n";
            }        
            ++$i;       
       }
    }
    //オリエントコンストレイント処理   
    if(`checkBox -q -v $CNST_INFO[1]`){     
        string $TGT_NODE;
        int $i = 0;    
       for($TGT_NODE in $TGT_NODE_LIST){
           //ロックアトリビュートを除外する
            vector $LOCKSTATE = `eval ("CHECK_ATTR_LOCK(\"" + $TGT_NODE + ".r\")")`;
            if($LOCKSTATE < <<1,1,1>>){         
                vector $SKIP_ATTR = $TGT_ATTR - $LOCKSTATE;
                //コンストレイント文を変数定義する
                string $EVAL_STRING = "orientConstraint -weight 1";
                if(`checkBox -q -v $OPTN_INFO[0]` == 1) $EVAL_STRING = $EVAL_STRING + " -mo";
                if($SKIP_ATTR.x <1) $EVAL_STRING = $EVAL_STRING + " -sk x";
                if($SKIP_ATTR.y <1) $EVAL_STRING = $EVAL_STRING + " -sk y";
                if($SKIP_ATTR.z <1) $EVAL_STRING = $EVAL_STRING + " -sk z";
                $EVAL_STRING = $EVAL_STRING + " " + $SCE_NODE_LIST[$i] + " " + $TGT_NODE + ";";
                eval $EVAL_STRING;
            }
            else{
                print $TGT_NODE;
                print " : orinetConstraint Skipped...\n";
            }        
            ++$i;       
       }
    }
    //スケールコンストレイント処理   
    if(`checkBox -q -v $CNST_INFO[2]`){     
        string $TGT_NODE;
        int $i = 0;    
       for($TGT_NODE in $TGT_NODE_LIST){
           //ロックアトリビュートを除外する
            vector $LOCKSTATE = `eval ("CHECK_ATTR_LOCK(\"" + $TGT_NODE + ".s\")")`;
            if($LOCKSTATE < <<1,1,1>>){         
                vector $SKIP_ATTR = $TGT_ATTR - $LOCKSTATE;
                //コンストレイント文を変数定義する
                string $EVAL_STRING = "scaleConstraint -weight 1";
                if(`checkBox -q -v $OPTN_INFO[0]` == 1) $EVAL_STRING = $EVAL_STRING + " -mo";
                if($SKIP_ATTR.x <1) $EVAL_STRING = $EVAL_STRING + " -sk x";
                if($SKIP_ATTR.y <1) $EVAL_STRING = $EVAL_STRING + " -sk y";
                if($SKIP_ATTR.z <1) $EVAL_STRING = $EVAL_STRING + " -sk z";
                $EVAL_STRING = $EVAL_STRING + " " + $SCE_NODE_LIST[$i] + " " + $TGT_NODE + ";";
                eval $EVAL_STRING;
            }
            else{
                print $TGT_NODE;
                print " : scaleConstraint Skipped...\n";
            }        
            ++$i;       
       }
    }
    //ポルベクコンストレイント処理   
    if(`checkBox -q -v $CNST_INFO[3]`){     
        string $TGT_NODE;
        int $i = 0;    
       for($TGT_NODE in $TGT_NODE_LIST){
            //コンストレイント文を変数定義する
            string $EVAL_STRING = "poleVectorConstraint -weight 1";
            $EVAL_STRING = $EVAL_STRING + " " + $SCE_NODE_LIST[$i] + " " + $TGT_NODE + ";";
            eval $EVAL_STRING;
            ++$i;       
       }
    }
    //ペアレントコンストレイント処理   
    if(`checkBox -q -v $CNST_INFO[4]`){     
        string $TGT_NODE;
        int $i = 0;    
       for($TGT_NODE in $TGT_NODE_LIST){
            string $EVAL_STRING = "parentConstraint -weight 1";
            if(`checkBox -q -v $OPTN_INFO[0]` == 1) $EVAL_STRING = $EVAL_STRING + " -mo";
            //ロックアトリビュートを除外する
            //移動アトリビュートチェック
            int $ALL_LOCK_FLUG = 0;
            vector $LOCKSTATE = `eval ("CHECK_ATTR_LOCK(\"" + $TGT_NODE + ".t\")")`;
            if($LOCKSTATE < <<1,1,1>>) ++$ALL_LOCK_FLUG;                               
                vector $SKIP_ATTR = $TGT_ATTR - $LOCKSTATE;
                if($SKIP_ATTR.x <1) $EVAL_STRING = $EVAL_STRING + " -st x";
                if($SKIP_ATTR.y <1) $EVAL_STRING = $EVAL_STRING + " -st y";
                if($SKIP_ATTR.z <1) $EVAL_STRING = $EVAL_STRING + " -st z";              
            //回転アトリビュートチェック
            $LOCKSTATE = `eval ("CHECK_ATTR_LOCK(\"" + $TGT_NODE + ".r\")")`;
            if($LOCKSTATE < <<1,1,1>>) ++$ALL_LOCK_FLUG;    
                vector $SKIP_ATTR = $TGT_ATTR - $LOCKSTATE;
                if($SKIP_ATTR.x <1) $EVAL_STRING = $EVAL_STRING + " -sr x";
                if($SKIP_ATTR.y <1) $EVAL_STRING = $EVAL_STRING + " -sr y";
                if($SKIP_ATTR.z <1) $EVAL_STRING = $EVAL_STRING + " -sr z";            
            if($ALL_LOCK_FLUG > 0){
                $EVAL_STRING = $EVAL_STRING + " " + $SCE_NODE_LIST[$i] + " " + $TGT_NODE + ";";
                eval $EVAL_STRING;
            }
            else{
                print $TGT_NODE;
                print " : parentConstraint Skipped...\n";
            } 
            ++$i;       
       }
    }
}
//-----------------------------------------------
//コネクション 処理
global proc CONNECTION_SET(string $F_LAYOUT){
    //レイアウト情報の格納
    string $LAYOUT_INFO[] = stringToStringArray(`frameLayout -q -docTag $F_LAYOUT`,"&");    
    string $ATTR_INFO[] = stringToStringArray($LAYOUT_INFO[0],";");
    string $SCE_INFO[] = stringToStringArray($LAYOUT_INFO[1],";");
    string $TGT_INFO[] = stringToStringArray($LAYOUT_INFO[2],";");
    string $SLCT_INFO[] = stringToStringArray($LAYOUT_INFO[3],";");
    //-----------------------
    //ソースノード・ターゲットノードの選択
    string $LIST[] = `ls -sl`; 
    string $SCE_TGT_LIST[] = stringToStringArray(`SET_TGT_LIST($SLCT_INFO[0])`,"&");
    string $SCE_NODE_LIST[] = stringToStringArray($SCE_TGT_LIST[0],";");
    string $TGT_NODE_LIST[] = stringToStringArray($SCE_TGT_LIST[1],";");
    //-------------------
    //ターゲットアトリビュートの取得
    vector $TGT_ATTR = <<0,0,0>>;
    if(`checkBox -q -v $SCE_INFO[0]` == 1)$TGT_ATTR = $TGT_ATTR + <<1,0,0>>;
    if(`checkBox -q -v $SCE_INFO[1]` == 1)$TGT_ATTR = $TGT_ATTR + <<0,1,0>>;
    if(`checkBox -q -v $SCE_INFO[2]` == 1)$TGT_ATTR = $TGT_ATTR + <<0,0,1>>;
    string $TGT_X = `optionMenu -q -v $TGT_INFO[0]`;
    string $TGT_Y = `optionMenu -q -v $TGT_INFO[1]`;
    string $TGT_Z = `optionMenu -q -v $TGT_INFO[2]`;    
    //translate コネクション
    if(`checkBox -q -v $ATTR_INFO[0]`){
        string $TGT_NODE;
        int $i = 0;    
        for($TGT_NODE in $TGT_NODE_LIST){
            //ロックアトリビュートを除外する
            vector $LOCKSTATE = `eval ("CHECK_ATTR_LOCK(\"" + $TGT_NODE + ".t\")")`;
            if($LOCKSTATE < <<1,1,1>>){
                vector $SKIP_ATTR = $TGT_ATTR - $LOCKSTATE;
                if($SKIP_ATTR.x > 0)connectAttr -f ($SCE_NODE_LIST[$i] + ".tx") ($TGT_NODE + ".translate" + $TGT_X);
                if($SKIP_ATTR.y > 0)connectAttr -f ($SCE_NODE_LIST[$i] + ".ty") ($TGT_NODE + ".translate" + $TGT_Y);
                if($SKIP_ATTR.z > 0)connectAttr -f ($SCE_NODE_LIST[$i] + ".tz") ($TGT_NODE + ".translate" + $TGT_Z);
            }
            ++$i;
        }
    }
    //rotate コネクション
    if(`checkBox -q -v $ATTR_INFO[1]`){
        string $TGT_NODE;
        int $i = 0;    
        for($TGT_NODE in $TGT_NODE_LIST){
            //ロックアトリビュートを除外する
            vector $LOCKSTATE = `eval ("CHECK_ATTR_LOCK(\"" + $TGT_NODE + ".r\")")`;
            if($LOCKSTATE < <<1,1,1>>){
                vector $SKIP_ATTR = $TGT_ATTR - $LOCKSTATE;
                if($SKIP_ATTR.x > 0)connectAttr -f ($SCE_NODE_LIST[$i] + ".rx") ($TGT_NODE + ".rotate" + $TGT_X);
                if($SKIP_ATTR.y > 0)connectAttr -f ($SCE_NODE_LIST[$i] + ".ry") ($TGT_NODE + ".rotate" + $TGT_Y);
                if($SKIP_ATTR.z > 0)connectAttr -f ($SCE_NODE_LIST[$i] + ".rz") ($TGT_NODE + ".rotate" + $TGT_Z);
            }
            ++$i;
        }
    }
    //scale コネクション
    if(`checkBox -q -v $ATTR_INFO[2]`){
        string $TGT_NODE;
        int $i = 0;    
        for($TGT_NODE in $TGT_NODE_LIST){
            //ロックアトリビュートを除外する
            vector $LOCKSTATE = `eval ("CHECK_ATTR_LOCK(\"" + $TGT_NODE + ".s\")")`;
            if($LOCKSTATE < <<1,1,1>>){
                vector $SKIP_ATTR = $TGT_ATTR - $LOCKSTATE;
                if($SKIP_ATTR.x > 0)connectAttr -f ($SCE_NODE_LIST[$i] + ".sx") ($TGT_NODE + ".scale" + $TGT_X);
                if($SKIP_ATTR.y > 0)connectAttr -f ($SCE_NODE_LIST[$i] + ".sy") ($TGT_NODE + ".scale" + $TGT_Y);
                if($SKIP_ATTR.z > 0)connectAttr -f ($SCE_NODE_LIST[$i] + ".sz") ($TGT_NODE + ".scale" + $TGT_Z);
            }
            ++$i;
        }
    }
}
//-----------------------------------------------
//ジョイントアトリビュート エディット
global proc JOINT_EDIT_CMD(string $JOINT_EDIT_F){
    //レイアウト情報の格納
    string $LAYOUT_INFO[] = stringToStringArray(`frameLayout -q -docTag $JOINT_EDIT_F`,";");
    string $TGT_JOINT_LIST[] = `ls -sl -type "joint"`;
    string $TGT_JOINT;    
    for($TGT_JOINT in $TGT_JOINT_LIST){
        if(`checkBox -q -v $LAYOUT_INFO[0]`){
            setAttr ($TGT_JOINT + ".radius") `floatField -q -v $LAYOUT_INFO[1]`;
        }
        if(`checkBox -q -v $LAYOUT_INFO[2]`){
            setAttr($TGT_JOINT + ".rotateOrder") (`optionMenu -q -sl $LAYOUT_INFO[3]` - 1);
        }
        setAttr($TGT_JOINT + ".segmentScaleCompensate")`checkBox -q -v $LAYOUT_INFO[4]`;
    }
}
-----------------------------------
<蛇足ながら解説>
一括コンストレイントで、以下のところで、ロックアトリビュートの検出を行っています。
//-----------------------------------------------
//ロックアトリビュートを検出
global proc vector CHECK_ATTR_LOCK(string $ATTR){
    vector $LOCKSTATE =<<0,0,0>>;
    if (`getAttr -l ($ATTR + "x")`)$LOCKSTATE = $LOCKSTATE + <<1,0,0>>;
    if (`getAttr -l ($ATTR + "y")`)$LOCKSTATE = $LOCKSTATE + <<0,1,0>>;
    if (`getAttr -l ($ATTR + "z")`)$LOCKSTATE = $LOCKSTATE + <<0,0,1>>;
    return $LOCKSTATE;
}
これは、対象のアトリビュートの途中までのstringを渡してやれば、x、y、zに関してロックされているかどうかをチェックして、vectorを返すプロシージャです。
今回、アトリビュートの有効・無効を0・1のvectorの値で管理しています。
(x:ロック y:アンロック z:ロック ・・・なら、結果は<<1,0,1>>・・・というわけです。)
実は今までにも何度か一括コンストレインmelを組んだことがあり、単純にアトリビュートごとに処理する方法を数パターン試したのですが、いずれもソースが長くなって、見直すのが面倒なことに。。。
そこで、ここ最近、vector形式で管理する方法にしてみたのですが、これが割りと楽で、ソースもシンプルになりました。
たとえば、最終的に、処理を行うアトリビュートを決めるソースの部分では…、

vector $SKIP_ATTR = $TGT_ATTR - $LOCKSTATE;

この一文だけですんじゃうわけです。ウヒヒ…って感じです。
vector形式で管理すると、このように3つの値をまとめて処理できるため、シンプルで便利だなという印象を持ってます。
もちろん、もっといいほかの方法もあるのかも知れませんが…、それは追々。。。

そんな訳で、このmelToolはロックアトリビュートを自動スキップするので、そこで処理がとまることはない…と思われます。
-----------------------------------





2014年8月26日火曜日

EDGE COLOR EDITOR

会社でのキャラセットアップの仕事の折に、こんな感じのmelを作りました。
選択したオブジェクトに関して、エッジの表示色を変更するmelです。



セットアップなどのとき、コントローラーのCURVEにアトリビュートから色を付けたりしますが、いちいちタブを開けたりなんだり…と、数が多いと面倒っくっさい。。。

このToolを使えば、ワンポチで好きな色を設定できる、というものです。

使用方法:
①melを起動するとウインドウが開くので、スライダーかintFieldからColorIndexを入力。
②オブジェクトを選択して、ボタンを押します。

以下ソース

//------------------------
//SET_EDGE_COLOR
//------------------------
/*
作成日:14/08/26
更新日:--/--/--
解説:
このmelは、選択したオブジェクトのエッジカラーを編集するmelです。
ポリゴンオブジェクトや、CURVEの色を変えるのに便利です、
*/

proc SET_EDGE_COLOR_PROC(){
string $NODE_LIST[] = `ls -sl`;
string $NODE_NAME;
int $COLOR_INDEX = `intField -q -value COLOR_INT`;

for($NODE_NAME in $NODE_LIST){
setAttr ($NODE_NAME + ".overrideEnabled") 1 ;
setAttr ($NODE_NAME + ".overrideColor") $COLOR_INDEX; 
}
}

if(`window -q -exists SET_EDGE_COLOR`) deleteUI SET_EDGE_COLOR;
window -s 0  -t "SET_EDGE_COLOR" SET_EDGE_COLOR;
rowLayout -nc 3;
colorIndexSliderGrp -min 0 -max 32 -value 10 COLOR_INDEX;
intField -value 10 -cc SET_COLOR_INDEX COLOR_INT;
button -w 100 -h 30 -l "SET_COLOR";// -c SET_EDGE_COLOR(`colorIndexSliderGrp -q -value COLOR_INDEX`);
setParent..;
showWindow SET_EDGE_COLOR;
proc SET_EDGE_COLOR(int $COLOR_INDEX){
string $NODE_LIST[] = `ls -sl`;
string $NODE_NAME;

for($NODE_NAME in $NODE_LIST){
setAttr ($NODE_NAME + ".overrideEnabled") 1 ;
setAttr ($NODE_NAME + ".overrideColor") $COLOR_INDEX; 
}
}

proc SET_COLOR_INDEX(){
int $COLOR_INDEX = (`intField -q -value COLOR_INT` + 1);
colorIndexSliderGrp -e -value $COLOR_INDEX COLOR_INDEX;
}

proc SET_COLOR_INT(){
int $COLOR_INT = (`colorIndexSliderGrp -q -value COLOR_INDEX` - 1);
intField -e -value $COLOR_INT COLOR_INT;
}
if(`window -q -exists SET_EDGE_COLOR`) deleteUI SET_EDGE_COLOR;
window -s 0  -t "SET_EDGE_COLOR" SET_EDGE_COLOR;
formLayout;
columnLayout ;//-nc 3 -ct3 left left left;
colorIndexSliderGrp -min 1 -max 32 -value 14 -cc SET_COLOR_INT COLOR_INDEX;
intField -value 13 -cc SET_COLOR_INDEX COLOR_INT;
button -w 100 -h 30 -l "SET_COLOR" -c SET_EDGE_COLOR_PROC;
setParent..;
setParent..;

showWindow SET_EDGE_COLOR;


ウエイト付け補助Tool (3)

ウエイト付け補助Toolの続き。
今回は、ポリゴンノード1で囲んだ範囲の、ポリゴンノード2の頂点を選択するところまで。
現在は、
①選択範囲を指定するポリゴンを選択
②トグルで頂点を選択したいポリゴンを選択
③mel起動
 …で使用します。

前回までに作成した部分はプロシージャにして使用しています。



これはこれだけで、「頂点を立体選択するTool」として使えそうです。
しかし、現状の仕様では、真正面向きに作成した立方体でしか範囲を指定できません。
範囲指定する立体が、少しナナメってたり、いびつな形状では、座標の正確な指定ができません。

最終目標が「ウエイト付け補助Tool」なので、モデルのいびつな形を指定するために、ユーザーは頂点を細かく移動して、範囲を指定したいはず。
てゆか、僕がそうしたい(=m=)。
今後は、範囲指定する立体がいびつな形でも頂点選択できるように改良したいです。

以下ソース

//-----------------------------
//プロシージャ;選択したポリゴンの座標を取得する
global proc vector [] getSelectedPosition()
{
//ソース元:http://www.not-enough.org/abe/manual/maya/mel-tips.html#getPosition

vector $POS_POSITION[];
float $val[];

string $sp[] = `ls -sl`;
string $pos[] = `filterExpand -sm 31 $sp`;
int $i = 0;
for($p in $pos)
{
$pv = `pointPosition $p`;
$val[0] = $pv[0];
$val[1] = $pv[1];
$val[2] = $pv[2];
$POS_POSITION[$i] = <<$val[0],$val[1],$val[2]>>;
//print $pv;
$i++;
}
return $POS_POSITION;
//ここまで、引用して修正
}
//-----------------------------
//プロシージャ;指定されたポリゴンの頂点座標をXYZごとにソートする
proc GET_POS_LIST (string $NODE_NAME,float $VAL_LIST_X[],float $VAL_LIST_Y[],float $VAL_LIST_Z[]){
//内部変数の定義
vector $TARGET_POS_VAL;
float $VAL_X;
float $VAL_Y;
float $VAL_Z;
vector $TARGET_POS[];

select -cl;
select ($NODE_NAME + ".vtx[*]");
$TARGET_POS = `getSelectedPosition`;

//座標をソートする
int $i = 0;
for($TARGET_POS_VAL in $TARGET_POS){
$VAL_X = $TARGET_POS_VAL.x;
$VAL_Y = $TARGET_POS_VAL.y;
$VAL_Z = $TARGET_POS_VAL.z;

$VAL_LIST_X[$i] = $VAL_X;
$VAL_LIST_Y[$i] = $VAL_Y;
$VAL_LIST_Z[$i] = $VAL_Z;
$i++; 
}
$VAL_LIST_X = `sort $VAL_LIST_X`;
$VAL_LIST_Y = `sort $VAL_LIST_Y`;
$VAL_LIST_Z = `sort $VAL_LIST_Z`;
}

//-----------------------------
//選択したポリゴンの頂点リストを取得する。
//--------------------------
//変数群の宣言
string $TAGET_NODE; 
string $NODE_LIST[];
string $NODE_NAME ;
string $TARGET_VTX_LIST[];
string $TARGET_VTX;
vector $TARGET_POS_VAL;

string $SELECT_VTX_LIST[];
vector $SELECT_POS[];

float $VAL_LIST_X[];
float $VAL_LIST_Y[];
float $VAL_LIST_Z[];

float $MIN_VAL_X;
float $MIN_VAL_Y;
float $MIN_VAL_Z;
float $MAX_VAL_X;
float $MAX_VAL_Y;
float $MAX_VAL_Z;
//--------------------------
clear $NODE_LIST;
clear $TARGET_VTX_LIST;
clear $SELECT_VTX_LIST;
clear $SELECT_POS;
clear $VAL_LIST_X;
clear $VAL_LIST_Y;
clear $VAL_LIST_Z;
//--------------------------
//選択したオブジェクトごとに処理実行
$NODE_LIST = `ls -sl`;
$NODE_NAME = $NODE_LIST[0];
$TARGET_NODE = $NODE_LIST[1];

  GET_POS_LIST($NODE_NAME,$VAL_LIST_X,$VAL_LIST_Y,$VAL_LIST_Z); //囲むポリゴンメッシュの座標リストの取得

//座標の最大値」・最小値を整理
$MIN_VAL_X =  $VAL_LIST_X[0];
$MAX_VAL_X =  $VAL_LIST_X[`size $VAL_LIST_X`-1];
$MIN_VAL_Y =  $VAL_LIST_Y[0];
$MAX_VAL_Y =  $VAL_LIST_Y[`size $VAL_LIST_Y`-1];
$MIN_VAL_Z =  $VAL_LIST_Z[0];
$MAX_VAL_Z =  $VAL_LIST_Z[`size $VAL_LIST_Z`-1];

print ($MIN_VAL_X + "," + $MAX_VAL_X + "\n");
print ($MIN_VAL_Y + "," + $MAX_VAL_Y + "\n");
print ($MIN_VAL_Z + "," + $MAX_VAL_Z + "\n");

//ターゲットメッシュの頂点から範囲内の頂点を抜き出す、
select ($TARGET_NODE + ".vtx[*]");
$TARGET_VTX_LIST = `ls -sl`;
$TARGET_VTX_LIST = `filterExpand -sm 31 $TARGET_VTX_LIST`;

int $i = 0;
for ($TARGET_VTX in $TARGET_VTX_LIST){
//print $TARGET_VTX;
$TARGET_POS_VAL = `pointPosition $TARGET_VTX`;

if($TARGET_POS_VAL.x >= $MIN_VAL_X && $TARGET_POS_VAL.x<= $MAX_VAL_X){
if($TARGET_POS_VAL.y >= $MIN_VAL_Y && $TARGET_POS_VAL.y <= $MAX_VAL_Y){
if($TARGET_POS_VAL.z >= $MIN_VAL_Z && $TARGET_POS_VAL.z <= $MAX_VAL_Z){
$SELECT_VTX_LIST[$i] = $TARGET_VTX;
$i++;
}

}
}

}

select -cl;

select $SELECT_VTX_LIST;
//おわり

2014年8月11日月曜日

ウエイト付け補助Tool (2)

ウエイト付けToolの続きです。

ひとまず、選択したポリゴンの頂点を取得してリスト化するところまでやってみました。


以下ソース

//---------------------------------------------------------

//選択ポリゴンノードの頂点座標のリストを取得する

//------------------------------------------------------------------------
//選択した頂点の座標を取得する
global proc vector [] getSelectedPosition()
{
//ソース元:http://www.not-enough.org/abe/manual/maya/mel-tips.html#getPosition

vector $POS_POSITION[];
float $val[];

string $sp[] = `ls -sl`;
string $pos[] = `filterExpand -sm 31 $sp`;
int $i = 0;
for($p in $pos)
{
$pv = `pointPosition $p`;
$val[0] = $pv[0];
$val[1] = $pv[1];
$val[2] = $pv[2];
$POS_POSITION[$i] = <<$val[0],$val[1],$val[2]>>;
//print $pv;
$i++;
}
return $POS_POSITION;
}
/*
ここまでのプロシージャは、以下サイト様よりソースをコピー、変数をいじらせていただきました。
http://www.not-enough.org/abe/manual/maya/mel-tips.html#getPosition
いつも(勝手ながら)勉強させていただいているサイト様です。
*/
//------------------------------------------------------------------------
//選択したポリゴンの頂点リストを取得し、選択する
//変数群の宣言
string $NODE_LIST[];
string $NODE_NAME ;
vector $TARGET_POS[];

//選択したオブジェクトのノード名を取得する
$NODE_LIST = `ls -sl`;
for ( $NODE_NAME in $NODE_LIST){
$NODE_NAME = ($NODE_NAME + ".vtx[*]");
select $NODE_NAME;

$TARGET_POS = `getSelectedPosition`;
print $TARGET_POS;
}

//おわり
select -cl;
//------------------------------------------------------------------------



ども、ほっさんといいます。
今月から新しい職場になり、仕事で主にmelを使用した作業用Toolを作成する機会が増えました。

もともと、私は生粋のグラフィックアーティストだったもんで、プログラムの勉強など一切してきませんでした。 ただ、前職で必要にかられてVBAとmelを独学しました。
でも、JavaやC言語は触ったことがないので、全くもってプログラムは初心者といえるでしょう。

そんな私ですが、こうして仕事で主にmeプログラミングを触っていくことになったわけで、日ごろあれやこれや勉強を積み重ねていこうと思うわけです。

そんな徒然を、こちらのブログでは書いてゆければいいかと思っています。

主に掲載するのは、ソースや、もしくは私が作成したmelToolなどになると思います。


ご縁があれば、何卒よろしくお願いいたします。

ウエイト付け補助Tool (1)

melプログラムの練習がてら、スムーススキンでバインドした後のウエイトづけを補助するToolを考えて見ようと思います。

仕様は以下の通り。
1)~1500くらいのローポリゴンモデルでの作業を想定
2)ジョイントに対応したラティス様のものが生成されて、ウエイトの範囲を指定する。
 ※このラティスは分割数などを指定できるといい。
3)任意の範囲を各々ラティスで囲んだら、「実行」ボタンをクリック
4)各々ジョイントに対応したラティスで囲まれた範囲のウエイトが100%でついている。

実用に向くかどうかはおいておいて(笑)。あくまで練習です。


処理順としては、以下を想定してみました。
----------------------------------------------------------
①ジョイントに対応したポリゴンノードか、カーブオブジェクトを作成する。

ユーザーが実行ボタンを押す

②オブジェクトの頂点リストを取得し、X、Y、Z値のMax,minを求め、オブジェクトで囲んだ範囲を定義する。。

③ウエイト付けの対象から頂点のリストを取得する。
 ウエイト付け対象の頂点リストのうち、②で求めたオブジェクトの範囲外の頂点を無視。
 ※もしくは、指定範囲内の頂点のみを選択する

④範囲内の頂点に特定ジョイントのウエイトを設定する
----------------------------------------------------------

時間のある時に、つらつらやってみようと思います。