2016年11月28日月曜日

GitHubに登録してみました

完全に半年に一回更新ペースになってますね笑
しかも最近はこんなツール作りましたってネタしか投稿してないw

まぁ今回は久しぶりに技術ネタをやろうかなと。


今までGitHubで色んな方々のコードは拝見してきたのですが
自分ではあまりコードを公開してこなかったというか
複数で開発していくような環境にいたことがなかったというのが
自分の中の大きな要因でGitHubにのメリットを感じてなく
やっていなかった原因だったのですが、
少し時間もあったので登録して投稿してみました

ただ、まだあまり使い方を理解してないので間違っていたら
ご指摘頂けるとありがたいです!



で、今回のネタ自体ですが
以前メモ程度に公開していたcorrectiveShapeの記事を書いていた
当時のスクリプトを少し体裁を整えて公開してみようかなと。

correctiveShapeは先日のcgwcc2016のザ・リギング・マニアックス 2016セッション内でも
・Shapes(Mayaの3rdPartyプラグイン)を使ってリガーがフェイシャルターゲットを作る方法
・RBF補完を使ってクロスシミュレーションをブレンドシェイプターゲットに効率よく置き換える方法
(引用)
等で使われる技術?のひとつです。

ポーズベースで形状を作成し、デフォーム前からの逆算された形状を作成することで
front of chainのblendShape等を使うことでデフォーム後の形状変化を加えることができます。
(↑なに言ってるかわからんww)
以前公開していたTYSSWEでも使ってます

TYSSWE from Takayuki Yanagisawa on Vimeo.



で、GitHubはココ→correctiveShape
考え方はChad Vernon氏のcvShapeInverterというplug-inを参考にさせて頂いてます。
http://www.chadvernon.com/blog/resources/cvshapeinverter/

何かスクリプト内で間違ってるとかもっとこっちが書き方良いとかあったら
教えて頂けると嬉しいですー

2016年3月6日日曜日

Rivet Brush

たまにはrigネタ以外のツール作ってみました。

シュッとやってガッとやってバッでrivet配置できます。
良かったら見てやってください。
  
Rivet Brush from Takayuki Yanagisawa on Vimeo.

たまにはツールとか公開してみようとも思いましたが
そんな勇気もないので、需要あるかわかりませんが
欲しい方いればひとまずご連絡くださいー

2015年9月15日火曜日

TYSSWE

新しいtool作りました。

だいぶ前から中身は出来ていたんですが
ちょっとした機能面とかUIとか動画とかをダラダラと作ってたら
かなり経ってしまってました。

ちょっとキャプチャーはやっつけ感が出ちゃってますかね笑


一応、今回のはrig組む人向け?ですかね?
何ができるのか動画で伝えきれてないかもしれませんが...

plug-inとかは使ってないので気持ち的にも試しやすいと思います。


TYSSWE from Takayuki Yanagisawa on Vimeo.


ではではー

2015年6月21日日曜日

Corrective Shapeの考え方

お久しぶりです。
気づけば前回から半年も投稿が開いてました;;



今回は『corrective shape』というものをスクリプトで最近作ったので
自分のメモ的な意味も含めて書いておきます。

ここで言うcorrective shapeとは既にデフォームしているオブジェクトに対して
blend shapeをfront of chainで使用した時に目的の形状になるための
『逆算された形状』という意味です。


















(gif作ってから思いましたが分かりにくいww)


例えば、既にdeformerによってデフォームしているオブジェクトをduplicateし
形状を変化させてblend shapeを入れたいとします。

deformer → blendShape
とすると目標のオブジェクトの形状にはなりますが
これではdeformerの効力がなくなります。

なので
blendShape → deformer
の順にするとblendShapeで変形した後に
deformerが動作しますがdeformer変形後に形状を作っているので
目的の形状にはなりません。

それを
blendShape → deformer
のノードコネクションでも目的の形状になるよう逆算した形状を作るのが
今回のcorrective shapeです。

とまぁ偉そうに書いてますがcorrective shapeの考え方自体は私が考えたものではないです。
まぁ詳しくはcorrective shapeでググってみてくださいw



さて本題。
説明しやすくするために名前を決めます。

original ・・・ deformerが入っているオブジェクトの元々形状
target ・・・ deform後にduplicateして変化させた目的の形状
base ・・・ deformerが入ったあとのオブジェクトの形状

※baseはtargetをduplicateしたときと同じdeform状態です



作成するための考え方

1.baseの頂点の位置を取得
2.baseの頂点のxyz軸をmatrixとして取得
3.targetの頂点の位置を取得
4.3から1の値を減算しローカライズ
5.2のmatrixと4の値の積を求める(座標変換)
6.originalの頂点に5の値をセット
7.完成!

※今回作成したスクリプト自体は全てobject spaceでやりとりをしています



matrixつかうと座標変換がめちゃめちゃ楽ですね。

今回はopenmayaのMMatrixを使ってますが
書き方で
× MMatrix × MPoint
○ MPoint × MMatrix
という使い分けがあるようです。ややこしや。


今回のようなイテレートが必要なものはopenmayaとかapiの
ありがたみをすごく感じますね。



今回はこの辺でー
次回はまた気が向いたときに更新しますw

2015年1月19日月曜日

描いて動かすMaya tool

今回は久しぶりにtoolっぽいものを作ったのでご紹介します。


特に細かい設定とかは必要なく、選択して描いて動かすそれだけのtoolです。
まぁ過去素材も流用しつつ動画も作ってみたのでご覧頂ければと思います。


DOOTY from Takayuki Yanagisawa on Vimeo.

UIはPySideで中身はOpenMayaで書いてます。

割と簡単に実行部はできたので今回はUIをちゃんと作ってみました。
時間的に 中身 : 外身 = 3 : 7 って感じです。
















なんかチョコレートが食べたくなるUIって感じです(別に狙ってない)


ではまたー

2014年12月24日水曜日

PySideを使ってMayaでwebを表示してみる

今回は現在勉強中のPySideネタ書いてみます。
自分なりの言い回しで書いてるので本来の意味と違うかもしれませんがご容赦ください。

PySideはたしか2014からデフォルトで入ってるpythonのライブラリです。
詳しくはググってください(おきまり)


PySideを使ってMayaでwebを表示したい!とふと思ったので挑戦してみました。
qtDesignerという便利ツールもありますが今回は勉強のために一からPySideと向き合ってみます。

と言いつつも特に解説もせず、早速結論です。笑

####################################################################

# まずは必要なライブラリをインポートします。
from PySide import QtCore, QtGui, QtWebKit
from maya import OpenMayaUI, cmds
import shiboken

# QWidgetを継承してブラウザーを作成するクラス
class browserUI(QtGui.QWidget):
# 初期化関数
def __init__(self, parent=None):
# スーパークラス(QWidget)のインスタンスメソッドからparentを使いたいのでsuper関数を使う
super(browserUI, self).__init__(parent)
# showUIメソッドの呼び出し
self.showUI()

def showUI(self):
# レイアウトの作成
vbox = QtGui.QVBoxLayout(self)

# ブラウザの作成
self.browser = QtWebKit.QWebView(self)
# URLの設定
self.browser.load(QtCore.QUrl('http://null0218.blogspot.jp/'))
# レイアウトにアタッチ
vbox.addWidget(self.browser)

#親レイアウトに合わせて伸縮する設定
self.setSizePolicy(QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding)

# 実行関数
def viewBrowser():
# mayaの裏側に行かないように設定
# mayaのメインウィンドウを取得
mayaMain = OpenMayaUI.MQtUtil.mainWindow()
# 取得したメインウィンドウをPySideのUIとして取得
parent = shiboken.wrapInstance(long(mayaMain), QtGui.QWidget)
# mayaのメインウィンドウの子供としてUIを作成
mainUI = QtGui.QMainWindow(parent)

# 上で書いたのQWidgetの呼び出し
browser = browserUI()
# QWidgetをMenuとしてQMainWindowにアタッチ
mainUI.setMenuWidget(browser)
# QMainWindowの表示
mainUI.show()

# おまじない
if __name__ == '__main__':
viewBrowser()

####################################################################
タブがスペースになってしまった;;
試す方はインデント調整してください;;

今回はざっくりした解説も書いてるので参考にしてもらえればと思います。

↓とまぁこんな感じで意外とすんなりできちゃいました。
こだわったポイントはmayaの裏側に行かないように設定ってとこですかねー



















ただ、どうやら今のPySideの実行環境だとプラグインとかをロードしても
HTML5がダメみたいでyoutubeとかが見れない、うぬぬ。

↓こんな感じでmayaのレイアウトをちょっと改造してyoutube見たかったー






















見れる方法ご存知の方、是非ご教授ください。



それにしても、PySideはいろいろな場所で使えていいですねー
ちょっと環境を整えればmayaだけじゃなくて
独立したアプリケーションとして面白いことができます。

















ノードエディタっぽいのも作れちゃいます。

まだまだ勉強すること多いですがやってみると楽しいので皆さんもぜひー
ではでは。

2014年11月3日月曜日

UV座標からワールド座標を求める云々を使ったツール

前回の記事でご紹介してたMELを公開するだけという手抜き記事です。

使い方は動画を見てください。
最近使ってるわけでもないのでツールの
エラーとかも対応しかねますので自己責任でお試しください。

仕様としてはnearestPointOnMeshを使って
UV座標 ⇔ ワールド座標 を行き来してjointを配置していくものだったと思います。
※ペイントエフェクトのような規則正しいUVを使わないとうまくいかなかった気がします。

jointはIKスプラインの仕込み、hairの仕込みなどが選択できたと思います。


TYGrassesSetUpTool();
global proc TYGrassesSetUpTool(){
    //同じウインドウが存在する場合は削除
    if(`window -exists TYGrassesSetUpToolWindow`){
        deleteUI TYGrassesSetUpToolWindow;
    }
    //ウインドウの作成
    window -t "草花セットアップツール" -w 250 TYGrassesSetUpToolWindow;
    string $windowRootLayout =`columnLayout -adj true`;
        string $stepTabs =`tabLayout -imw 5 -imh 5`;
            //STEP1
            string $step1 =`columnLayout -adj true`;
                text -fn "boldLabelFont" -bgc 0.18 0.18 0.18
                 -l "\n ターゲットメッシュのUV座標を基に\n等間隔でジョイントを配置しします\n";
                columnLayout;
                    text -l "\n ① 配置させるジョイントの数と半径を指定します\n";
                    intFieldGrp -l "ジョイント " -v1 10 -el "個" jointQuantityField;
                    floatFieldGrp -l "半径 " -v1 0.01 -pre 3 jointRadiusField;
                    text -l "\n ② 配置させるUVマップの名前を指定します\n";
                    rowLayout -nc 2;
                        text -l "                            ";
                        textField -tx "map1" UVmapNameField;
                    setParent..;
                    text -l "\n ③ 配置させるUV座標を指定します\n";
                    floatFieldGrp -l "U座標位置の割合 " -v1 50.0 -el "%" -pre 2
                     -ann "V座標上に一列で配置するときのU座標位置の割合です" uPerPositionField;
                    text -l "\n ④ バインドするか指定します\n";
                    rowLayout -nc 3;
                        text -l "     ";
                        radioCollection bindSelectField;
                       radioButton -l "バインドする" -sl -w 100 bindSelectTrue;
                       radioButton -l "バインドしない" -w 100 bindSelectFalse;
                    setParent..;
                    text -l "\n ⑤ ヘアシステムとカーブを作成するか指定します\n";
                    rowLayout -nc 3;
                        text -l "     ";
                        radioCollection makeRigSelectField;
                       radioButton -l "作成する" -sl -w 100
                        -onc "text -e -en true nucleusText;\
                        radioButton -e -en true makeNsysSelectTrue;\
                        radioButton -e -en true makeNsysSelectFalse;"
                        makeRigSelectTrue;
                       radioButton -l "作成しない" -w 100
                        -onc "text -e -en false nucleusText;\
                        radioButton -e -en false makeNsysSelectTrue;\
                        radioButton -e -en false makeNsysSelectFalse;"
                        makeRigSelectFalse;
                    setParent..;
                    text -l "\n   ヘアシステムにnucleusを接続するか指定します\n" nucleusText;
                    rowLayout -nc 3;
                        text -l "     ";
                        radioCollection makeNsysSelectField;
                       radioButton -l "接続する" -sl -w 100 makeNsysSelectTrue;
                       radioButton -l "接続しない" -w 100 makeNsysSelectFalse;
                    setParent..;
                    text -l "\n ⑥ meshノードを選択し、作成を実行します\n";
                setParent..;
                button -l "作成" -c "TYGrassesSetUp(\
                 `intFieldGrp -q -v1 jointQuantityField`\
                 ,`floatFieldGrp -q -v1 jointRadiusField`\
                 ,`textField -q -tx UVmapNameField`\
                 ,`floatFieldGrp -q -v1 uPerPositionField`\
                 ,`radioCollection -q -sl bindSelectField`\
                 ,`radioCollection -q -sl makeRigSelectField`\
                 ,`radioCollection -q -sl makeNsysSelectField`)";
            setParent..;
            //STEP2
            string $step2 =`columnLayout -adj true`;
            text -fn "boldLabelFont" -bgc 0.18 0.18 0.18
             -l "\n バインドされたソースメッシュを基に\nジョイントを配置しバインドやnHair等を実行します\n";
                columnLayout;
                    text -l "\n ① 配置させるジョイントの半径を指定します\n";
                    floatFieldGrp -l "半径 " -v1 0.01 -pre 3 jointCopyRadiusField;
                    text -l "\n ② 配置させるUVマップの名前を指定します\n";
                    rowLayout -nc 2;
                        text -l "                            ";
                        textField -tx "map1" UVmapCopyNameField;
                    setParent..;
                    text -l "\n ③ バインドするか指定します\n";
                    rowLayout -nc 3;
                        text -l "     ";
                        radioCollection bindCopySelectField;
                       radioButton -l "バインドする" -sl -w 100 bindCopySelectTrue;
                       radioButton -l "バインドしない" -w 100 bindCopySelectFalse;
                    setParent..;
                    text -l "\n ③ ヘアシステムを継承し作成するか指定します\n";
                    rowLayout -nc 3;
                        text -l "     ";
                        radioCollection succeedNsysSelectField;
                       radioButton -l "継承し作成する" -sl -w 100
                        -onc "textField -e -en true hairSystemShapeNameField;\
                        text -e -en true succeedHairSysText;"
                        succeedNsysSelectTrue;
                       radioButton -l "作成しない" -w 100
                        -onc "textField -e -en false hairSystemShapeNameField;\
                        text -e -en false succeedHairSysText;"
                        succeedNsysSelectFalse;
                    setParent..;
                    text -l "\n   継承するhairSystemShapeの名前を指定します\n" succeedHairSysText;
                    rowLayout -nc 2;
                        text -l "                            ";
                        textField -tx "hairSystemShape1" hairSystemShapeNameField;
                    setParent..;
                setParent..;
                button -l "実行" -c "TYGrassesSetUpCopy(\
                `floatFieldGrp -q -v1 jointCopyRadiusField`\
                ,`textField -q -tx UVmapCopyNameField`\
                ,`radioCollection -q -sl bindCopySelectField`\
                ,`radioCollection -q -sl succeedNsysSelectField`\
                ,`textField -q -tx hairSystemShapeNameField`)";
            setParent..;
            //タブレイアウトにペアレント
            tabLayout -e -tl $step1 "STEP1" -tl $step2 "STEP2" $stepTabs;
        setParent..;
        button -l "閉じる" -c "deleteUI TYGrassesSetUpToolWindow";
    setParent..;
    showWindow;
}

global proc TYGrassesSetUp(int $jointQuantity, float $jointRadius, string $UVmapName,
 float $uPerPosition, string $bindSelect, string $makeRigSelect, string $makeNsysSelect){
    pickWalk -d down;
    //選択されたオブジェクトのチェック
    string $targetMesh[] = `ls -sl -typ mesh`;
    if(`objExists $targetMesh[0]`){
        if(`objExists $targetMesh[1]`){
            error "複数選択されています。一度に作成できるベースセットアップは一つのみです。";
        }
        else;
    }
    else error "メッシュが選択されていません。";
    //uvSetの名前のチェック
    int $flag = 0;
    if(catch(size(`getAttr -s ($targetMesh[0] + ".uvSet[*].uvSetName")`))){
        if(`getAttr ($targetMesh[0] + ".uvSet[0].uvSetName")` == $UVmapName){
            $flag = 1;
        }
        else;
    }
    else{
        string $uvSetNameList[] = `getAttr ($targetMesh[0] + ".uvSet[*].uvSetName")`;
        int $j;
        for($j=0;$j<=(size($uvSetNameList)) && $flag!=1;$j++){
            if($uvSetNameList[$j] == $UVmapName){
                $flag = 1;
            }
            else;
        }
    }
    //指定した値のチェック
    if($jointQuantity <= 1 || $jointRadius <= 0 || $flag == 0){
        error "入力値が不正です。";
    }
    else;
    //transformノードの取得
    string $targetTransform[] = `pickWalk -d up`;
    //ジョイントの配置
    int $i;
    string $jointList[];
    for($i=1;$i<=$jointQuantity;$i++){
        select -cl;
        string $jointName = `joint -rad $jointRadius -n "TYGrassBaceJoint"`;
        //階層化
        $jointList[($i - 1)] = $jointName;
        if($i!=1){
            parent $jointName $jointList[($i - 2)];
        }
        //UV座標を基にジョイントを配置
        string $constName[] = `pointOnPolyConstraint $targetMesh[0] $jointName`;
        int $k,$UVmapNumber,$nFlag = 0;
        for($k=0;$nFlag!=1;$k++){
            string $selectUVmapName = `getAttr ($targetMesh[0] + ".uvSet[" + $k + "].uvSetName")`;
            if($selectUVmapName == $UVmapName){
                $UVmapNumber = $k;
                $nFlag = 1;
            }
            else;
        }
        connectAttr -f ($targetMesh[0] + ".uvSet[" + $UVmapNumber + "].uvSetName")
         ($constName[0] + ".target[0].targetUVSetName");
        float $uvSize[] = `polyEvaluate -b2 -ae -uvs $UVmapName $targetMesh[0]`;
        float $uPosition = ($uvSize[1] - $uvSize[0]) * $uPerPosition * 0.01 + $uvSize[0];
        float $vPosition = ($uvSize[3] - $uvSize[2]) / ($jointQuantity - 1)
         * ($i - 1) + $uvSize[2];
        setAttr ($constName[0] + "." + $targetTransform[0] + "U0") $uPosition;
        setAttr ($constName[0] + "." + $targetTransform[0] + "V0") $vPosition;
        setAttr ($constName[0] + ".offsetRotateX") -90;
        setAttr ($constName[0] + ".offsetRotateY") 90;
        delete $constName[0];
        //回転値をジョイントの方向へ移行させ0にする
        float $jointRotateValue[] = `getAttr ($jointName + ".rotate")`;
        joint -e -o $jointRotateValue[0] $jointRotateValue[1] $jointRotateValue[2] $jointName;
        setAttr ($jointName + ".rotate") 0 0 0;
    }
    //バインドの実行
    if($bindSelect == "bindSelectTrue"){
        select $targetMesh[0] $jointList;
        SmoothBindSkin;
    }
    else;
    //nHairの作成
    if($makeRigSelect == "makeRigSelectTrue"){
        //ikHandleの作成
        string $ikHandleName[] = `ikHandle -sj $jointList[0]
         -ee $jointList[($jointQuantity -1)] -sol ikSplineSolver -scv false`;
        select $ikHandleName[2];
        //assignHairSystemのプロシージャから引用
        string $sel[] = `ls -sl`;
        string $hsys = `createNode hairSystem`;
        connectAttr time1.outTime (".currentTime");
        string $inCurveName[] = `ls -dag -type nurbsCurve $sel`;
    attachCurvesToHairSystem( $hsys, $inCurveName, false );
    //作成したものを変数に代入
    select $hsys;
    convertHairSelection( "follicles" );
    pickWalk -d down;
    select `listConnections -s false -t "nurbsCurve"`;
        string $outCurveShapeName[] = `pickWalk -d down`;
        select $inCurveName[0];
        string $inCurveShapeName[] = `pickWalk -d down`;
        //ikをhiarカーブに添わせる
        disconnectAttr ($inCurveShapeName[0] + ".worldSpace[0]") ($ikHandleName[0] + ".inCurve");
        connectAttr ($outCurveShapeName[0] + ".worldSpace[0]") ($ikHandleName[0] + ".inCurve");
        //hairのアトリビュート設定
        setAttr ($hsys + ".bendResistance") 50;
        setAttr ($hsys + ".startCurveAttract") 0.1;
        setAttr ($hsys + ".selfCollide") 1;
        setAttr ($hsys + ".selfCollideWidthScale") 0.1;
        //nucleusの接続
        if($makeNsysSelect == "makeNsysSelectTrue"){
            string $nucleusName = `createNode nucleus`;
            connectAttr time1.outTime (".currentTime");
            connectAttr ($hsys + ".currentState") ($nucleusName + ".inputActive[0]");
            connectAttr ($hsys + ".startState") ($nucleusName + ".inputActiveStart[0]");
            connectAttr ($nucleusName + ".outputObjects[0]") ($hsys + ".nextState");
            connectAttr ($nucleusName + ".startFrame") ($hsys + ".startFrame");
            setAttr ($hsys + ".active") 1;
        }
    }
}

global proc TYGrassesSetUpCopy(float $jointCopyRadius, string $UVmapCopyName
 , string $bindCopySelect, string $succeedNsysSelect, string $hairSystemShapeName){
    pickWalk -d down;
    string $meshList[] = `ls -sl `;
    //uvSetの名前のチェック
    int $k,$flag = 0;;
    for($k=1;$k<size($meshList);$k++){
        if(catch(size(`getAttr -s ($meshList[$k] + ".uvSet[*].uvSetName")`))){
            if(`getAttr ($meshList[$k] + ".uvSet[0].uvSetName")` == $UVmapCopyName){
                $flag = 1;
            }
            else;
        }
        else{
            string $uvSetNameList[] = `getAttr ($meshList[$k] + ".uvSet[*].uvSetName")`;
            int $j;
            for($j=0;$j<=(size($uvSetNameList)) && $flag!=1;$j++){
                if($uvSetNameList[$j] == $UVmapCopyName){
                    $flag = 1;
                }
                else;
            }
        }
    }
    if(`objExists $hairSystemShapeName`){
        if(`nodeType $hairSystemShapeName` != "hairSystem"){
            $flag = 0;
        }
        else;
    }
    else{
        $flag = 0;
    }
    //指定した値のチェック
    if($flag == 0){
        error "入力値が不正です。";
    }
    else;
    //nearestPointOnMeshの作成
    loadPlugin -qt "nearestPointOnMesh.mll";
    string $nPOM = `createNode "nearestPointOnMesh"`;
    string $checker[] = `spaceLocator`;
    connectAttr ($checker[0] + ".translate") ($nPOM + ".inPosition");
    connectAttr ($meshList[0] + ".worldMesh[0]") ($nPOM + ".inMesh");
    //メッシュからジョイントを取得
    string $jointList[] =`skinCluster -q -inf $meshList[0]`;
    //ソースメッシュにバインドされたジョイントのソースメッシュ上UV位置を取得
    float $uPosition[],$vPosition[];
    for($jointName in $jointList){
        float $jointPosition[] = `xform -q -ws -t $jointName`;
        move -rpr $jointPosition[0] $jointPosition[1] $jointPosition[2] $checker[0];
        $uPosition[`size($uPosition)`] = `getAttr ($nPOM + ".parameterU")`;
        $vPosition[`size($vPosition)`] = `getAttr ($nPOM + ".parameterV")`;
    }
    delete $nPOM $checker[0];
    //ジョイントの配置
    int $i;
    string $ikHandleList[],$jointCopyList[];
    for($i=1;$i<size($meshList);$i++){
        float $uvboundingBox[] = `polyEvaluate -b2 -ae -uvs $UVmapCopyName $meshList[$i]`;
        string $jointName[] = {};
        for($j=0;$j<`size($jointList)`;$j++){
            //ソースのバウンディングボックス内にジョイントがあった場合ターゲットも作成(誤差0.0001)
            if(($uvboundingBox[3] + 0.0001) > $vPosition[$j]){
                select -cl;
                $jointName[$j] = `joint -rad $jointCopyRadius -n "TYGrassBaceJoint"`;
                string $constName[] = `pointOnPolyConstraint $meshList[$i] $jointName[$j]`;
                //指定したuvマップが何番目の配列にあるか確認
                int $l,$UVmapNumber,$nFlag = 0;
                for($l=0;$nFlag!=1;$l++){
                    string $selectUVmapName = `getAttr ($meshList[$i] +
                     ".uvSet[" + $l + "].uvSetName")`;
                    if($selectUVmapName == $UVmapCopyName){
                        $UVmapNumber = $k;
                        $nFlag = 1;
                    }
                    else;
                }
                connectAttr -f ($meshList[$i] + ".uvSet[" + $UVmapNumber + "].uvSetName")
                 ($constName[0] + ".target[0].targetUVSetName");
                select $meshList[$i];
                string $transformMesh[] = `pickWalk -d up`;
                setAttr ($constName[0] + "." + $transformMesh[0] + "U0") $uPosition[$j];
                setAttr ($constName[0] + "." + $transformMesh[0] + "V0") $vPosition[$j];
                setAttr ($constName[0] + ".offsetRotateX") -90;
                setAttr ($constName[0] + ".offsetRotateY") 90;
                delete $constName[0];
                //ソースを参考に階層化
                select $jointList[$j];
                int $m,$num = 0;
                string $sourceParentJoint[] =`pickWalk -d up`;
                if($jointList[$j] != $sourceParentJoint[0]){
                    for($m=0;$m<size($jointList);$m++){
                        if($jointList[$m] == $sourceParentJoint[0]){
                            $num = $m;
                        }
                    }
                parent $jointName[$j] $jointName[$num];
                }
            }
        }
        $jointCopyList[size($jointCopyList)] = $jointName[0];
        //バインドの実行
        if($bindCopySelect == "bindCopySelectTrue"){
            select $meshList[$i] $jointName[0];
            SmoothBindSkin;
        }
        else;
        //ikHandleの作成
        if($succeedNsysSelect == "succeedNsysSelectTrue"){
            string $ikHandleName[] = `ikHandle -sj $jointName[0]
             -ee $jointName[(size($jointName) - 1)] -sol ikSplineSolver -scv false`;
            $ikHandleList[size($ikHandleList)] = $ikHandleName[0];
            //assignHairSystemから一部引用
            string $curves[] = `ls -dag -type nurbsCurve $ikHandleName[2]`;
            attachCurvesToHairSystem( $hairSystemShapeName, $curves, false );
            //hairSystemShapeから正しいfollicleshapeを取得
            select $hairSystemShapeName;
            convertHairSelection( "follicles" );
            string $follicleShapeList[] = `pickWalk -d down`;
            string $trueFollicleShape;
            for($follicleShapeName in $follicleShapeList){
                string $plugList[] = `listConnections -d false $follicleShapeName`;
                for($plugName in $plugList){
                    if($plugName == $ikHandleName[2]){
                        $trueFollicleShape = $follicleShapeName;
                    }
                    else;
                }
            }
            //follicleshapeの中から作られたカーブを取得
            select $trueFollicleShape;
            select `listConnections -s false -t "nurbsCurve"`;
            string $outCurveName[] = `pickWalk -d down`;
            //curveShapeを取得
            select $ikHandleName[2];
            string $inCurveName[] = `pickWalk -d down`;
            //ikをhiarカーブに添わせる
            disconnectAttr ($inCurveName[0] + ".worldSpace[0]") ($ikHandleName[0] + ".inCurve");
            connectAttr ($outCurveName[0] + ".worldSpace[0]") ($ikHandleName[0] + ".inCurve");
        }
        else;
    }
    group -n "TYGrassesIkHandleGp" $ikHandleList;
    group -n "TYGrassesJointGp" $jointCopyList;
    select -cl;
}




久しぶりにMELのツールを見るとpythonのほうが
書きやすい感じがしますね。(慣れかな?)

最近はOpenMayaとかPySideと戯れているのでそういうのもあるんでしょうけど。


んーbloggerってtextファイルアップロードできないのかなー

2014年10月13日月曜日

Google Maps APIさわってみたよ

記事を書く度にお久しぶりですとか言ってる気がするw


最近pythonとかmelとかをガリガリ書いていたので
一年と三カ月ぶりにHTMLとかCSSとかJava Scriptとか触ってみます。

といっても過去に作った簡単なプログラムを公開するだけなんですけどね(手抜き)



やりたいことはgoogle map上でクリックしたところにマーカーを立てて
経度、緯度を取得して表示 → csvファイルとして書きだし

とまぁこんな感じです。

ちなみにcsvファイルってのはカンマ( , )とかで情報を区切るだけで
エクセル等のソフトでも枠を区切って認識してくれるファイル形式です。
まぁ詳しくはぐぐってください。


今回はソースコードの解説などは特にしません。←
(べつに久しぶりに弄ったら結構忘れてて解説する自信がないとかではないですよ;;)

まぁ結構この手の内容は一文づつググったらかなりの量の解説がヒットしますので
まぁ詳しくはぐぐってください。w


///////////////////////////////////////////////////////

<!DOCTYPE html>
<html>
<head>

<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0px; padding: 0px }
#map { height: 100% }
</style>

<script src="http://maps.google.com/maps/api/js?v=3&sensor=false"
type="text/javascript" charset="UTF-8">
</script>

<script type="text/javascript">
//<![CDATA[

var map;
var markersArray = [];
var flag = 0;

function init() {

var latlng = new google.maps.LatLng(39, 138);
var opts = {
zoom: 6,
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: latlng
};

map = new google.maps.Map(document.getElementById("map"), opts);

google.maps.event.addListener(map, 'click', mylistener);
}

function mylistener(event) {
if(flag == 0){
document.getElementById("left_up_lat").innerHTML = event.latLng.lat();
document.getElementById("left_up_lng").innerHTML = event.latLng.lng();
}else {
document.getElementById("right_under_lat").innerHTML = event.latLng.lat();
document.getElementById("right_under_lng").innerHTML = event.latLng.lng();
}

var latlng=new google.maps.LatLng(event.latLng.lat(), event.latLng.lng());
var marker = new google.maps.Marker({position:latlng, map:map});

markersArray.push(marker);
}

function writeText() {
var fs = new ActiveXObject("Scripting.FileSystemObject");

var outf = fs.CreateTextFile("outText.csv", true);
outf.Write(document.getElementById("file_name").value + "," + document.getElementById("left_up_lat").innerHTML + "," + document.getElementById("left_up_lng").innerHTML + "," + document.getElementById("right_under_lat").innerHTML + "," + document.getElementById("right_under_lng").innerHTML);
outf.Close();
}

function clearOverlays() {
if (markersArray) {
for (i in markersArray) {
markersArray[i].setMap(null);
}
}
}

function leftUp() {
flag = 0;
}

function rightUnder() {
flag = 1;
}

//]]>
</script>
</head>

<body onload="init()">

<div id="map" style="height:560px"></div>

<table border="1" cellspacing="2" width="100%">
<tr><th>ファイル名</th><th><button onclick="leftUp()" type=button>LEFT UP</button></th><th><button onclick="rightUnder()" type=button>RIGHT UNDER</button></th></tr>
<tr><th rowspan="2"><input type="text" size=30 value="file name" id="file_name"></th><th id="left_up_lat"></th><th id="right_under_lat">
<tr><th id="left_up_lng"></th><th id="right_under_lng"></th></tr>
</table>
<form>
<input type="button" value="マーカーを削除" onclick="clearOverlays()" /><button onclick="writeText()" type=button>書きこみ</button><br>
</form>
</body>

</html>


///////////////////////////////////////////////////////


とまぁこんな感じなんですが
これを書いてた頃はIEユーザーだったのでActiveXObjectという
IEでファイルを書きだすやつを使ってたんですが
現状IEユーザーが減っちゃったのと、バージョンアップによって
IEでもたぶん使えないと思います←

かきだすwriteText()の中身だけ書き変えたら動くはずですが
使うタイミングがないので使いたい方は書き変えて使って下さい。
firefoxやchromeなどでも確かそんなやつがあったと思います。

まぁ一応コピーして.htmlで保存すればそれ以外は動くはずです。たぶん。




はい、まぁ今回はかなり雑でしたがこんな感じで終わりますw
今後も雑な感じで過去のスクリプトとか投下するかもしれませんが悪しからず。

2014年7月9日水曜日

mayabatchを使ってちょっと効率up

おひさしぶりです。
ブログを書こうと思いつつもどんどん先延ばしになって、かなり期間が開いてしまいました(・へ・)

4月からいっぱしのクリエーターになっていろいろな意味でこのブログも
書きにくくなってしまいました;;


とまぁあまり書いていると睡眠時間がどんどん無くなるので
さっそくですが本題ですよ



社会人になって友達の幅もかなり増えたりして仕事の色々な話を聞く機会がふえました
そんな中で効率を上げたいという話をよく耳にします

なので今回は同じ修正をカット毎しなければならないめんどくさい作業をもっと効率化しよう!
という内容です。

ちょっとこのブログではそこまでmel等のスクリプトを取り上げていませんが
今回はmelありきになってしまうかもしれません。ご了承を。



mayabatchというものをご存じでしょうか。
GUIを立ち上げずにmayaの処理を行ってくれるヤツです。

windowsのコマンドプロンプトからコマンドを打って実行します。

例)
C:\"Program Files"\Autodesk\Maya2013\bin\mayabatch.exe -file "C:\Users\ty\Desktop\test01.mb" -command "polyCube;file -save;"
pause > nul

こんな感じです。
今回はキューブを作成し保存するという処理を行っています。
一文ずつ解説します。


C:\"Program Files"\Autodesk\Maya2014\bin\mayabatch.exe
まずはmayabatch.exeまでのパスを書きます

-file "C:\Users\ty\Desktop\test01.mb"
続けてfileフラグでデータまでのフルパスを書きます。
※フルパスでなくてもいけたはずですがまぁフルパスにこしたことはないです

-command "polyCube;file -save;"
commandフラグでmelコマンドを書いていきます。
長くなる場合はmayaのmelのパスが通っている場所にプロシージャとして登録しておき
それを読んできた方がスマートだと思います。
※ここまでが↑一文です

pause > nul
これはコマンドプロンプトから実行したときに処理が終わるとすぐ実行画面が消えてしまうので
確認しやすいようポーズしているだけです。まぁなくても問題はありません。



こんな感じで実行すればGUIを立ち上げずに処理を行ってくれるので早いですし
メモ帳等にこの文を保存して拡張子を.batにすればバッチファイルの出来上がりです。

さらに改行して別データの処理を書けば上から順に実行していってくれます。


batだけ作ってしまってPCに処理をさせておいて優雅にランチタイムなんてどうでしょうか
効率的ってすばらしい!!




まぁ簡単ですが今回はおわりです
またそのうち更新しますねー

2014年3月11日火曜日

3.11 追悼




なかなか更新出来ず申し訳ありません。
また時間を見つけて更新します。

2013年11月16日土曜日

ただいま・・・

ただいま、卒業制作の日々に追われておりまして
なかなか更新できず、申し訳ないです。














また、時間の余裕を見つけ次第更新しますので
もうしばらくお待ちをー(ToT)/~~~

あ、別に待ってないか。笑

2013年9月18日水曜日

Egg man animation

お久しぶりです。
最近、2週間弱くらいで10秒のアニメーションを作りました。

まぁ今回はモーションキャプチャーの検証と質感の検証など
実験的にいろいろやってみました。



Eggman Animation from Takayuki Yanagisawa on Vimeo.

最近、いろいろたてこんでいてなかなかブログが更新出来てないです。
せめて最低、月一では更新したい・・・

一応、音はフリー素材を使わせて貰いました。
BGMはMusic is VFRさんより
SEは聞き取りにくいのでイヤホン等をおススメします。

次回はきちんと技術的なとこかけるといいな。
ではでは。

2013年8月24日土曜日

tyDisplaceDeformer

今回は、pythonでmaya APIを触ってpluginを作ってみたのでご紹介します。

まだ処理が重かったりで実装は難しいのでコードの公開は控えます。


tyDisplaceDeformer from Takayuki Yanagisawa on Vimeo.

pymelを使ったら遅くなった?んでしょうか?

またpythonなどもblogでやっていけたらと思います。

2013年7月8日月曜日

2013年7月7日日曜日

サウンドウェーブをmayaのtlanslateに持っていく

お久しぶりです。


今回は音声ファイルをmayaにもっていこうと思います。

単純に再生するだけならタイムラインにドラッグ&ドロップで出来ますが、
サウンドウェーブを使ったアニメーション等はできません。

なので今回はサウンドウェーブをmayaのtlanslateへもっていく方法を
ご紹介したいと思います。


まずは、サウンドウェーブをmayaからでも読み取れるカタチに
しなければなりませんので、今回はAfter Effectsを使いたいとおもいます。




















コンポジション設定はこんな感じです。
デュレーションは音声ファイルの長さに合わせてください。

タイムラインに音声ファイルをのっけたら
真っ黒な平面を作成し、その上に真っ白な平面を作成します。














こんな感じです。





















次に、音声ファイルを右クリックし
キーフレーム補助 → オーディオをキーフレームに変換
を実行します。









するとオーディオ振幅というレイヤーができ、
右と左と両方のチャンネルがスライダとしてキーフレームに変換されています。

次に、真っ白な平面の不透明度のストップウォッチのアイコンを
Altキーを押しながらクリックします。
すると、エクスプレッションが打てるようになります。














エクスプレッションの渦巻状のアイコンをドラッグして
スライダの上でドロップします。

では、再生してみてください。
サウンドウェーブに合わせて白黒するアニメーションができていると思います。


つまり、この白黒情報をmayaで読み取りtranslateにもっていこうという算段です。


なので、これをレンダリングします。
※注意 後でテクスチャアニメーションで読み込むので
soundWave.[###].png のように連番の前は必ず.にして下さい。

ファイルフォーマットは非可逆圧縮のpngとかをおススメします。



ここからはmayaでの作業
(maya 2013だと一部melがうまく実行されないので(バグ?)
今回はmaya 2011を使っています)














ハイパーシェードからファイルノードを作成します。

ファイルノードに先ほど作成した画像を読み込みます。






















Use Image Sequenceにチェックを入れると連番で画像を読み込んでくれます。
※注意 AEで書きだしたファイルは0から始まるので0フレーム目が
1枚目のテクスチャになっています。
これを変更したい時は紫色になっているImage Numberの
エクスプレッションを変更する必要があります。

次に、スクリプトエディタを開き以下のMELを実行します。

//////////////////////////////////////////////////////
{
    float $value[];
    string $loc[] =`spaceLocator`;
    for($i=開始フレーム;$i<=終了フレーム;$i++){
        currentTime $i;
        $value =`colorAtPoint -u 0.5 -v 0.5 -o A ファイルノード名`;
        setAttr ($loc[0] + ".ty") $value[0];
        setKeyframe ($loc[0] + ".ty");
    }

}
//////////////////////////////////////////////////////


日本語のところは半角英数字に書き換えて使ってください。

ちなみに今回の場合はこんな感じ。

//////////////////////////////////////////////////////
{
    float $value[];
    string $loc[] =`spaceLocator`;
    for($i=0;$i<=899;$i++){
        currentTime $i;
        $value =`colorAtPoint -u 0.5 -v 0.5 -o A file1`;
        setAttr ($loc[0] + ".ty") $value[0];
        setKeyframe ($loc[0] + ".ty");
    }

}
//////////////////////////////////////////////////////


実行してうまくいけばlocatorが現れ、上下に動きます。

これをスケールの値に入れたりなどして
簡単なモーショングラフィックスなんかも作れますね!



今回のMELの実行内容はこんな感じです。

float $value[];
//float型の配列を定義します

string $loc[] =`spaceLocator`;
//ロケーターを作成し、作成されたロケーター名を配列の0番目にいれます

for($i=0;$i<=899;$i++){ 実行 }
//$iの初期値(0)から$i<=899が成り立っている間ループし、毎回ループ終了後に$iに1を足します

currentTime $i;
//タイムスライダを$iに以降します

$value =`colorAtPoint -u 0.5 -v 0.5 -o A file1`;
//MELのcolorAtPointコマンドを実行し色情報を取得します(詳しくはMELコマンドヘルプへ)

setAttr ($loc[0] + ".ty") $value[0];
//ロケーターの移動Yに色情報から取得した値をいれます

setKeyframe ($loc[0] + ".ty");
//ロケーターの移動Yにキーフレームを打ちます



このブログではMELの解説等を一切してなかったので
MELってなんぞ?って方もいらっしゃるかもしれませんが
簡単に言うとMaya専用のスクリプト言語です。
繰り返し処理等をする時はとても便利です。

もし興味のある方は意外と独学でgoogle先生に聞きながらでも出来ると思いますので
チャレンジしてみてください。

2013年6月1日土曜日

フェースにコンストレインする

今回は、動画でチュートリアルを作ってみました。
試験的にささっと作ったので見にくかったり、
分かりにくかったりするかもしれませんがご容赦下さい。


さて今回は、フェースにコンストレインするという事ですが
用途は、服にボタン等のオブジェクトが付いている場合等に使えると思います。

服のボタンはスキンウェイトを振るとオブジェクトが伸びてしまうが
骨にコンストレインすると位置がずれる・・・
なんて状況ありますよね?



ちなみに先に書いておきますが今回の肝は
アトリビュートの転送です。
これを使ってUV座標からワールド座標に追従させます。
まぁ見てもらえば分かると思いますが。


ただ今回は最近発見したばっかりで簡単な検証しかおこなっておりません
もし不具合などありましたらコメント頂けると嬉しいです。



face constraint tutorial from Takayuki Yanagisawa on Vimeo.


質問や感想等ありましたらコメントお願いします!

2013年5月22日水曜日

membrane node

今回は面白いmayaの隠しノード(?)を見つけたのでご紹介します。

サスペンションのバネは現在、記事作成中です。
まぁそのうち書きます・・・


タイトルの通りmayaの隠しノードとはmembrane nodeのことです。

mayaの隠しノードは私の知っている限りいくつかあります。
例えばimplicit nodeです。
これは形のあるnullのようなもので3つの形状があり
更に形状を変更するアトリビュートがあります。

maya2013以降であればノードエディタで簡単に作れますが
それ以前ならMELで

//球体
createNode implicitSphere;

//立方体
createNode implicitBox;

//円錐
createNode implicitCone;

とそれぞれ作ることができます。
まぁ使い道があるのかは知りませんが。


さて、本題のmembrane nodeですが直訳で『皮膜』という意味だそうです。
mesh同士のコリジョンや、布っぽい動きを非シュミレーション、
リアルタイムで動かすことが出来ます。

まぁイメージしにくいと思いますので実際に作ってみましょう。

















まずは、どんな形でも構いませんがメッシュの細かなオブジェクトを用意します。

次にそのオブジェクトを選択し
createMembrane;
とMELを実行します。

すると勝手にmembraneノードがコネクションされたり
meshがコネクションされたりします。

この状態でアトリビュートを弄っても面白いのですが
他のオブジェクトとコリジョン(衝突)させてみましょう。

















先ほどのオブジェクトは置いといて
コリジョンさせたいオブジェクトを新しく作ります。

先ほどのオブジェクトと新しく作ったオブジェクトを選択し
ハイパーシェードでコネクションを見てみます。






















このようにシェイプが表示されると思います。

これをコリジョンさせたいオブジェクトのシェイプノードからmembrane1へ
中ボタンドラッグで引っ張り、その他を選択しコネクションエディタを開きます。






















そしてこのようにworldMeshとcollideMeshをコネクションします。


これで完成です!

あとはお好みでアトリビュートを弄ってみてください。


















するとこんな感じで動かしながらリアルタイムで
コリジョンができたと思います。



単純に乱気流や風圧を弄ってワイヤーフレームをレンダリングして
モーショングラフィックスとかも作れそうですね。

まぁ色々使い道はありそうですが、法線の反転等
弄っているとmeshが崩壊してしまうことも・・・

少々、脆弱性が気になるところが隠されている所以なのでしょうか・・・


まぁ一度、試してみる価値アリです!!

2013年5月6日月曜日

Suspension setup

今回は車やロボットのセットアップの時に使えそうな
サスペンションのリギングをご紹介します。

毎度ですがこれはあくまで一つの方法ですので他にもたくさんの方法があると思いますし
もっとスマートなセットアップがあかもしれませんので悪しからず。


さて何はともあれモデルを作成しましょう。






















こんな感じでしょうか?

今回は見て分かる通り2段階になっております。
段階ごと別オブジェクトでやる方法もありますが今回はくっついています。






















まずハイライトになっている部分をクラスタ化します。
ちなみにクラスタ化の方法は
コンポーネントを選択している状態で
アニメーションタブ → デフォーマの作成 → クラスタ
で出来ます。






















お次はここです。






















最後に残ったここです。

次に三か所にロケーターを配置します。
これは位置を取得する目的と
もしもの時の為のかませです。



場所は画像参照です。
①一番上の中心
②2段目の中心
③一番下の中心

配置出来たらロケーターをトランスフォームのフリーズをして
それぞれ上から順にロケーターとクラスタをペアレントコンストレインします。
※順番は ロケーター → クラスタ です

次にこのようにロケーターを上のロケーターが親になるようペアレント化します。
(上の①、②、③はそれぞれlocator1、2、3になっています)




















そして、ハイパーシェードのユーティリティからプラスマイナス平均を押し作業領域に表示させ
アウトライナでロケーター3つを選択し中ボタンドラックで作業領域に表示させてください。
(↑みたいな感じ)
※一気に3つを持ってくと重なって表示されるのでずらしてください。






















次にlocator1のtranslateYをplusMinusAverage1のinput1D[0]にコネクションします。
※input1Dをクリックしたら自動的にinput1D[0]にコネクションされます。

同様にlocator3のtranslateYをplusMinusAverage1のinput1D[1]にコネクションします。
が!
コネクションエディタではinput1D[1]が表示されずコネクションできません!
色々と原因はありますが今回は別のコネクション方法で・・・


ハイパーシェードの作業領域を見てください。

locator3の右下に右向きの▲があるのでそこを右ドラックしてtranslateYを選択してください。
そのまま、plusMinusAverage1の左下の右向き▲で
また右ドラックしてinput1D[0]を選択してください。

これでコネクションが出来ます。


そして、plusMinusAverage1のoutput1Dからlocator2のtranslateYとコネクションします。

最後にplusMinusAverage1のアトリビュートエディタの操作から平均を選択します。

これで完成です。
試しにlocator1やlocator3のtranslateYを動かしてみてください。
locator2が1と3のちょうど真ん中のポジションに動いてくれます!


あとは他オブジェクトにペアレント化したり、エイムコンストレインすれば
向きなども自由自在になると思います。
(ここは少し考えないともしかしたら難しいかも;)
まぁ分かりにくかったらコメント下さい。



また今度、この記事の内容を使ってサスペンションにばねを付けていみたいと思います。

ではでは

2013年5月4日土曜日

transform node等

前回しれっと使ってしまった『transform node』という単語みなさん理解していたでしょうか。


そもそもMayaはnode(ノード)で出来ています。
そしてノードは大きく分けて二つの種類に分けられます。
DAGノードと、DGのノードです。
詳しくは↓
http://mukaimame-cg.jugem.jp/?eid=100

今回は、その中でもオブジェクトを作る上でかかせない
DAG ノードで DG ノードの一種でもあるtransform nodeとshape nodeについて書きます。










まず、ポリゴンの球を作ってハイパーシェードの入出力コネクションをしてみます。
上のような関係が出ると思います。

左から説明すると、
create node
shape node
shading group node
transform node
となっています。

まず、create nodeですがこれが今回で言う球の形状を決めています。
この中に半径、分割数といった値が入っています。

そしてcreate nodeのoutputからshape nodeのinMeshに繋がれています。
shape nodeではcreate nodeからきた形状を
私達がUI上で見れるように形作ってくれます。
他にもレンダリングの詳細やスムースメッシュなどの値が入っています。
ちなみにUI上でヒストリの削除をすると
このshape nodeのoutMeshの前に繋がれていたノード達が消えていきます。

そしてshading group nodeはおおまかにいうとshape nodeで形作ったものに色を付けています。
ここではディスプレイメントやレンダリングの設定等様々な値が入っています。

そして最後transform nodeですがこれら設定がされたオブジェクトが
どこに配置されるのかどこにピボットがあるのかなどの値が入っています。























さてお次はアウトライナです。
ディスプレイ → シェイプ にチェックを入れています。

見て分かるようにpSpere1には二つのノードによる階層が出来ています。
ちなみに上がtransform node下がshape nodeです。

つまり何が言いたいかというとtransform nodeとshape nodeは親子関係があるということです。

では試しにUI上でpSpere1を選択し、↓キーを押してみて下さい
ちなみに↓キーはpick workのdownのショートカットでひとつ下の階層を選択します。

右下のスクリプトエディタに
// 結果: pPlaneShape1 //
と表示されshape nodeが選択できたかと思います。



・・・と、このような意外と基礎知識は見落としがちです。
これを知っていたら何ができるという具体例はあまり浮かびませんが
これを知っているのと知っていないのとでは制作において大きく違うと思います。

とくにバインド時のshape nodeの繋がりは理解しておくと
後からブレンドターゲットを追加したりなど活用できると思います。


なんか今回は活字ばっかになってしまいましたが参考になればと思います。

2013年4月30日火曜日

matrixについて

諸事情によりだいぶ期間が開きましたが今回はmatrixについてです。

mayaのtransform nodeには移動(translate)、回転(rotate)、スケール(scale)、シアー(shear)
というお馴染みのアトリビュートがありますがこれらを全て合わせたものがmatrixです。
(シアーはあまり使わないですかね・・・)

matrixは16個の数字を持ちます。
ちなみに移動(translate)は3つの数字(X、Y、Z)ですよね。
その数字についてとても分かりやすく解説して下さってるブログをご紹介します。
http://melpystudio.blog82.fc2.com/blog-entry-69.html


さて、ではmatrixをどんな時に使えばいいのかということですが
以前decomposeMatrixに触れたのでそれを使った
グレードアップ版ペアレントコンストレインをご紹介します。
(ちなみに今回はmaya2011で作ってます)















まずはこのようにオブジェクトを2つ用意し、トランスフォームのフリーズをしておきます。

プラグインマネージャでdecomposeMatrix.mllというのをロードしておいて下さい。

次に、ハイパーシェードを開いて下さい。




次に、画面左下のMELのところに
createNode decomposeMatrix;
と打ちこんでEnterキーを押してください。

するとハイパーシェードの作業領域にdecomposeMatrix1というノードが
一つ出来上がったと思います。
もし表示されない場合は
select decomposeMatrix1;
と同じくMELのところにうって入出力コネクションボタンを押してみてください。


ちなみにmaya2013の場合はノードエディタを開きTABキーを押し
decぐらいまで打ったらdecomposeMatrixが出てくるのでそれを押せば出来ます。


decomposeMatrixノードはmatrixの16個数字から移動(translate)、回転(rotate)、
スケール(scale)、シアー(shear)の値に変換してくれるノードです。






















では次にコネクションエディタを開き右側にpCube1
左側にdecomposeMatrix1をロードします。

そしてworldMatrixからinputMatrixへコネクションします。

ちなみにtransformノードにはmatrixが幾つもあるのですが
なぜworldMatrixなのかというとペアレントコンストレインのように
world座標で制御したい為です。






















次に左側にdecomposeMatrix1、右側にpSphere1をロードします。
そしてそのまま
outputTranslateとtranslate
outputRotateとrotate
outputScaleとscale
outputShearとshear
をコネクションします。

これで完成です!


で、なにがグレードアップ版かというとスケール
シアーの値もコンストレインされているという点と
コネクションされている数が全然違うので処理が軽いということです。

ハイパーシェード等で見てもらえば分かると思いますが
通常のペアレントコンストレインは17つコネクションされているのに対し
グレードアップ版ペアレントコンストレインは5つしかコネクションされていません。


今回は簡単な使い方だけでしたがいろいろと使い道はあると思います。
ペアレント化されている子供の階層のワールド座標を取得できるというだけで
夢がひろがりますよね?・・・よね・・・?

はい、ではまぁ色々とチャレンジしてみてください。