2016年2月11日木曜日

選択したキーフレームのリストを取得する

基礎の話なのですが、恥ずかしながらつい先日知ったことを、こちらにも載せておきます。

通常、グラフエディタで選択したキーフレームは、

keyframe -q -sl;

で取得できますが、これは単に、選択したフレーム=time(時間)のリストを返すだけで、
たとえば、複数アトリビュートのキーを同時選択していたとしても、いっしょくたに値が返されます。

アトリビュートとノードのリストは、

keyframe -q -n;

から取得可能ですが、それぞれ別々に実行すると、キーフレームとアトリビュートが関連していません。
このままでは、たとえば「選択したキーすべてにある処理を加える」などの処理がしにくい。。
方法を探していたのですが、何のことはない、「keyframe -q -sl;」の時、そのカーブの名前を指定してあげればよかったのでした。。

つまりは…
…で、各アニメーションカーブごとに、各々選択したキーフレームが取得できました。

…基礎です。(恥


2016年1月5日火曜日

【Maya】 【python】ポリゴンの凹面を判別する。

少し前からですが、アーティストの方から割と要望をいただく件として、
「ポリゴンメッシュの凹面を自動判別する機能」があります。

早めに開発着手したかったのですが、なかなか手が空かず、
時間ばかりいただいてしまいました。。
で、ちょうど年末年始、数学に強い従兄の助言もいただき、
時間のあるこの時期に大体形にしてみたので、こちらでも紹介します。

■どうやって凹凸を判別するか?
 チェックするポリゴンは4頂点の4角形であることが前提です。
 そもそも3角形だったら平面だし。5角形だったらそもそもポリゴン割れし。
 
 で、仕組みはこうです。
 ずばり内積と外積を使います。

 ベクトルの内積と外積を使って、4頂点のうち、
 3頂点の平面から見た残りの1点の位置を判別します。












 








~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
かんたんに外積:
2つのベクトルに垂直なベクトルを算出します。

 

















 
かんたんに内積:
ベクトルAをベクトルBに成分分解したときの、そのベクトルの長さを求めます。



















~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 その手順は…、

 ①3頂点で作る、1点から伸びる2本のベクトルの外積を出して、
 この3角形に垂直なベクトルを算出します。





















 ②残り1頂点で作るベクトルと、①の三角形に垂直なベクトルの内積を求めます。





















 この内積の値が正か負かで、残りの1点の位置が算出できるはずです。

■しかし、ポリゴンのみかたで凹か凸かが変わってしまう。
 この4頂点ですが…

こうみるか




















こうみるかで、凹か凸かが変わってしまいます。




















 要は、どの頂点を判別するのか、準点を定める必要があるわけです。
 ここは、判別の基準をアーティストさんに確認する必要がありますが、、、
 とりあえず、一度Triangulateをかけた時の形状が、凹か凸かを判別するように
 考えることにしました。

 要は、このポリゴンを…





















 Triangulateをかけて…


 この3角形に含まれない頂点…


 つまり、この頂点を判別することにします。


■melに便利なコマンドが
 melにズバリ、内積・外積を算出するコマンドがあるので、これを使うっきゃない。
 
 外積:cross  http://download.autodesk.com/global/docs/maya2014/ja_jp/Commands/cross.html
 内積:dot    http://download.autodesk.com/global/docs/maya2014/ja_jp/Commands/dot.html 

 しかし、頂点計算など、数が多い処理は全てmelで処理するには重たすぎるので、
 基本はすべてpythonで書くことにし、pythonからmelプロシージャを呼び出すようにします。

そんな感じで、ぱっと作ってみました。
※使用方法は、mel文を先に実行しておくか、sourceコマンドで読んでおいた上で
ポリゴンを選択し、python文を実行します。
すると、凹んだ角形のみが選択された状態で終了します。

実際にまだ使っていないので、信頼性は低いですが。
いろいろテストなどして、ブラッシュアップしていこうと思います。
 
以下ソース

2016年1月4日月曜日

centos7 rc.localからだと起動スクリプトがうごかない。。。

以前svnserveを導入した際、rc.localにsvnserveの起動スクリプトを記述して、
サーバーの起動時にsvnserveが自動的に立ち上がるように設定したのですが、
単にこれだけだと、自動起動してくれないことが分かりました。

実は、centos7から従来のrc.localにとる起動スクリプト管理ではなく、systemedにて
起動スクリプトの管理を行うようになったようです。

…てか、本にもそう書いてあった。全然読んでないじゃん。orz


起動スクリプトの管理方法は、他サイト様にていろいろ紹介されてありますが、
方法は2つ。
①rc.localを従来通り使うか
②systemedに乗り換えるか

です。

①に関しては、単にrc.localに実行権限を与えてあげるだけでOK。
実際やってみて、OKでした。

chmod u+x /etc/rc.d/rc.local

参考サイト:http://kantaro-cgi.com/blog/etc-server/cant_run_rclocal_centos7.html

②に関しては、
 ・専用シェルスクリプトを用意し、
 ・「/etc/systemd/systemの下に、拡張子が .serviceのテキストファイルを作る。」
   →参考サイト:tire.retire ガジェット好きおじさんの日記 より引用
 ・systemedに登録してあげる。

参考サイト:http://tire-retire.blogspot.jp/2014/12/centos7rclocal.html
参考サイト:http://motw.mods.jp/shellscript/tutorial.html

僕は①を試したのち、今後のことも考えて、systemedの対応を進めてみました。
シェルスクリプトは書いたことがありませんでしたが、初心者の自分にも難しくはなかったです。

ただ、現状まだうまく自動起動設定ができていない状態です。
systemedはサービスの起動順序をいろいろ指定できるのですが、依存関係にあるサービスが立ち上がる前にsvnserveの自動起動スクリプトが実行されているのではないか、と考えています。

今のところ、現状サーバー再起動時に再度立ち上げないといけないものは少ないので、
しばらく手動で対応しますが、頃合いをみて再挑戦したいところです。

2015年11月8日日曜日

centos7にSVN1.8とsvnserveを導入する

仕事では、Maya等のテクニカル対応のほかに、実はファイルサーバーやSVNの管理などもやっております。
…とはいえ、サーバー周りの技術なり知識は、今の職場に来てから習得した…というよりも習得中(…汗)なので、正直な話、ずぶの素人と大してかわんないんですけど。
ともあれ、やらねばならぬ、ということで、やってます。

で、今回はSVN対応の話。仕事でsvnserveの対応をしたのですが、細かなところでつまづくところがありましたので、メモの意味もふくめ、僕の対応手順を書き記すことにしました。


サーバーはLinuxでCentOS7。クライアントはwindows7。
クライアント側にすでにインストールされていたsvnが1.8だったので、svn1.8でsvnserve対応をする必要がありました。

そんなわけで、僕が行った手順は以下の通りです。
~~~~~~~~
① SVN1.8の導入
→通常インストールでは1.7が入るため、WandiscoRPMリポジトリから落とす。

参考サイト:CentOS 6でsubversionのバージョンを上げる
http://www.torutk.com/projects/swe/wiki/CentOS_6でsubversionのバージョンを上げる

② 競合するSVN1.7をアンインストール
 # yum remove package name
        →svn1.7とライブラリ周りが競合したので、アンインストール

③ svnserveを起動
参考サイト:subversionのインストール(CentOS,svnserve)
http://blog.myspoon.info/2011/07/subversioncentossvnserve.html
→すでにリポジトリは作成済みだったため、上記記事のうち、リポジトリ作成部分・アクセス権部分は割愛
→service svnserve STATUSでsvnserveの起動状況を確認しつつ…
→svnserve –d –r ルートパス で起動

④ リポジトリのフォルダ内の、confフォルダの中身…
svnserve.conf …を編集
   [general]
   anon-access = read →ユーザー認証なしの人:読み込みのみ
   auth-access = write →ユーザー認証ありの人:読み書きOK
   password-db = passwd →パスワード定義ファイルの名前
   authz-db = authz →ユーザーごとのアクセス権設定ファイルの名前
   realm = My First Repository →認証の名前

「password」 …を編集
   [users]
   testUser = testuser

「authz」 …を編集
   [groups]
   superUser = testUser    ←ユーザーをグループに分ける

   [/]
   @superUser = rw   ←グループごとにアクセス権を設定
   * = r

⑤ ポートの開放
   参考サイト:http://blog.layer8.sh/ja/2011/12/28/subversionのサーバーをsvnserveで構築する/
                 →このあと、#servuce iptables restartで再読み込み

~~~~~~~~
…ひとまず、この手順でsvnserveの起動が確認でき、RedmineやJenkins、TortoiseSVNから「svn://...」でアクセスすることができました。
あとは起動スクリプトに svnserveを起動するスクリプトを追加して、OSが立ち上がる際に自動でsvnserveも起動するように設定して、完了です。

あと、余談ですが、SVNやRedmineをLinuxサーバーで運用していて思ったのですが、
Centos7でSVNサーバーを運用するのは、現状ではまだ避けたほうがいいんじゃないか、ということです。
Centos7だとsvn1.8 webDAVがリリースされていないのか、wandiscoのリポジトリなどを探しても見当たらず、webdav認証が出来ずにすごく苦労しています。
←結局、アクセス権は、svnserveか、sambaを介して行っているのが現状です。

ただし、Centos6ではsvn1.8のwevdavがリリースされていたり、また、様々なノウハウも蓄積していて、web上のドキュメントも多いです。
Centos7ではなく、centos6を選択したほうが現状ではまだ有利だったかもしれません…。

2015年9月5日土曜日

Maya UVTextureEditorをカスタマイズする。



会社で、以前勤めていた方が、UV TextureEditorをカスタマイズしたmelを作成されてました。
先日、このmelの修整依頼をいただき、中身を解析したところ、割と面白かったので、
Tipsをこちらでも紹介しようと思います。

要は、MayaのデフォルトのUVTextureEditorにカスタマイズしたレイアウトをねじ込む…というものです。
では、僕がやってみた手順を順番に紹介したいと思います。

まず、UVTextureEditorはMayaのランタイムコマンドで、以下で生成できます。
(scriptEditorの履歴からもわかります。)

TextureViewWindow;

で、この生成されたウインドウにレイアウトをねじ込みたいわけですが、
ここでほしい情報は、
1)このウインドウの名前
2)中に入っている各々レイアウト構造の名前
です。

生成したTextureWindowのパネル名は、以下コマンドで求めることができます。

string $texWinName[] = `getPanel -sty polyTexturePlacementPanel`;
(これはMayaユーザーガイドに載ってます)

ここで取得したTextureWindowの親レイアウトをフルパス取得すれば、1)と2)が解決したも同然なので、

string $texWinParent = `textureWindow -q -p $texWinName[0]`;

…で、親レイアウトを求めてみました。
すると、帰ってきた文字列が…

polyTexturePlacementPanel1Window|TearOffPane|polyTexturePlacementPanel1|formLayout109
※1

なるほどー。
TextureWindowはformLayoutに入っているのですな。
前任の方は、ここにformLayoutを横付けして、レイアウトにカスタマイズ領域を確保してました。
今回の要望は、Maya2011以降のバージョンだと、レイアウトの幅が太くなってしまって、使いにくい、細くしてほしいということだったので、ここのところを改造します。

細くしてほしい…とは言っても、人によって好みもありますから(笑)、paneLayoutで、幅を可変にします。

※1で求めた、
polyTexturePlacementPanel1Window|TearOffPane|polyTexturePlacementPanel1|formLayout109
から、
polyTexturePlacementPanel1Window|TearOffPane|polyTexturePlacementPanel1
…の部分に、paneLayoutをねじ込みます。

string $texPanel = `formLayout -q -p $texWinParent`;
string $HOS_paneLayout = `paneLayout -p $texPanel -configuration "vertical2" -ps 1 20 100`;
   columnLayout -p $HOS_paneLayout -adj 1;
      button -w 80;
      intSliderGrp -w 80;
      button -w 80;
      button -w 80;

   setParent..;
※2

で、※1で求めたtextureWindowの親を、※2のpaneLayoutに入れてあげればできるはず。。

formLayout -e -p $HOS_paneLayout $texWinParent;


できた!
あとは、※2でとりあえず入れ込んだcolumnLayout部分を必要に応じてカスタマイズしてあげればOKですね!


ソース全容です。
----------------------
proc test(){
   string $texWinName[] = `getPanel -sty polyTexturePlacementPanel`;
   if(size($texWinName)>0){
      for ($panel in $texWinName){
         string $parentList = `textureWindow -q -p $panel`;
         string $win[] = stringToStringArray($parentList,"|");
         if(`window -q -ex $win[0]`)deleteUI $win[0];
      }
   }
   TextureViewWindow;
   clear $texWinName;
   $texWinName = `getPanel -sty polyTexturePlacementPanel`;
   string $texWinParent = `textureWindow -q -p $texWinName[0]`;
   string $texPanel = `formLayout -q -p $texWinParent`;
   string $HOS_paneLayout = `paneLayout -p $texPanel -configuration "vertical2" -ps 1 20 100`;
      columnLayout -p $HOS_paneLayout -adj 1;
         button -w 80;
         intSliderGrp -w 80;
         button -w 80;
         button -w 80;
      setParent..;
   formLayout -e -p $HOS_paneLayout $texWinParent;
}

test;
----------------------


2015年5月3日日曜日

スキンウエイト値を切り捨て・切り上げ・四捨五入するプロシージャ

引き続き、モデラーさん用Toolを作成してます。
表題のような機能を持ったToolの作成依頼があったので、対応してました。

最初melで処理を作ったのですが、頂点数が多いと途端に重たくなり、
えっなに、フリーズ!?...みたいな状態。。。せいぜい2000頂点とかその程度で
重たくなりました。

パイソン…やるか。。

というわけで、今回はpythonのお話です。
どっちにせよ、ゆくゆく.pyは習得するつもりで、チマチマ勉強はしていたので、
ついに日の目を見る時が来たか。。。という感じで、練習&実習がてら.pyでプロシージャを
組んでみました。

以下ソースです。

mode=1で切り捨て・mode=2で切り上げ・mode=3で四捨五入。
CUL_floatは、切り上げ・切り下げの目安の数値 ※四捨五入モードでは無視されます。
CUL_ROUNDは、小数点第何位かの指定、です。

例)
mode=1,CUL_float=2.0,CUL_ROUND=2.0で、0.02で切り上げ
mode=2,CUL_float=2.0,CUL_ROUND=1.0で、0.2で切り上げ
mode=3,CUL_float=5.0,CUL_ROUND=2.0で、0.05で切り上げ


import maya.cmds as mc
import maya.mel as mel
import math as math
def ARKW_skinWeightAdjustProc(mode=0,CUL_float=2.0,CUL_ROUND=2.0):
    skincluster=[]
    vtx_list=mc.ls(sl=True,fl=True)
    #頂点ごとの処理
    for vtx in vtx_list:
        inflnode_list=[]
        inflpct_list=[]
        new_inflpct_list=[]
        node_name=vtx.split('.')[0]
        #スキンクラスタを探す
        skincluster=mel.eval('findRelatedSkinCluster %s'%node_name)
        #スキンクラスタがなければスキップ
        if skincluster is None:
            mc.error('スキンクラスタが見当たりません。\n',sl=False)
        else:
            #インフルエンスオブジェクトのリストを取得する
            inflnode_list=mc.skinPercent(skincluster,vtx,q=True,t=None)
            #インフルエンスオブジェクトごとにスキン数値の取得
            for inflnode in inflnode_list:
                inflpct_list.append(mc.skinPercent(skincluster,vtx,t=inflnode,q=True))
            i=0
            while(i<len(inflpct_list)):
                #切り捨て
                if mode==0:
                    inflpct_list[i] = math.floor(inflpct_list[i]*10.0**CUL_ROUND)
                    REM = inflpct_list[i]%CUL_float
                    QUO = math.floor(inflpct_list[i]/CUL_float)
                    if REM>0:
                        inflpct_list[i] = CUL_float*QUO
                    inflpct_list[i] *= 1/10.0**CUL_ROUND
                #切り上げ
                elif mode==1:
                    inflpct_list[i] = math.ceil(inflpct_list[i]*10.0**CUL_ROUND)
                    REM = inflpct_list[i]%CUL_float
                    QUO = math.floor(inflpct_list[i]/CUL_float)
                    if REM>0:
                        inflpct_list[i] = CUL_float*QUO+CUL_float
                    inflpct_list[i] *= 1/10.0**CUL_ROUND
                #四捨五入            
                else:
                    inflpct_list[i] = round(inflpct_list[i],int(CUL_ROUND))
                i+=1
            #値の正規化
            i=0
            j=0
            while(i<len(inflpct_list)-1):
                if inflpct_list[i]<inflpct_list[i+1]:
                    j=i
                elif inflpct_list[i]>inflpct_list[i+1]:
                    j=i+1
                i+=1
            total_skinpct=0.0
            i=0
            while(i<len(inflpct_list)):
                total_skinpct=total_skinpct+inflpct_list[i]
                i+=1
            if total_skinpct!=1:
                inflpct_list[j] += 1-total_skinpct
            #スキンウエイトの適応
            mc.setAttr((skincluster + '.normalizeWeights'),0)
            i=0
            while (i<len(inflnode_list)):
                mc.skinPercent(skincluster,vtx,nrm=False,tv=(inflnode_list[i],inflpct_list[i]))
                i+=1
            mc.setAttr((skincluster + '.normalizeWeights'),1)
            #print (inflpct_list)
            del inflnode_list
            del inflpct_list


---------------
今回、慣れない.pyだったので、いろいろ苦労しましたが、
ポイントは3点ほどありました。

①melにしかないコマンドは、pythonからmelを呼ぶ
 #スキンクラスタを探す
 skincluster=mel.eval('findRelatedSkinCluster %s'%node_name)
↑ここですね。

②skinPercentコマンドで、transformをqモードで呼び出したいときはNoneで指定する
#インフルエンスオブジェクトのリストを取得する
inflnode_list=mc.skinPercent(skincluster,vtx,q=True,t=None)
↑これですね。。。
ここは結構詰まりました。
melでの書き方では…
string $inflnode_list[]=`skincluster -q -t skincluster vtx`;
…ですので、最初は、
inflnode_list=mc.skinPercent(skincluster,vtx,q=True,t=True)
とか
inflnode_list=mc.skinPercent(skincluster,vtx,q=True,t='')
とか
inflnode_list=mc.skinPercent(skincluster,vtx,q=True,t=)
とか、試しましたが、すべて怒られましたw
t=None と指定しないといけなかったのですね!
参考:http://forums.cgsociety.org/archive/index.php/t-928526.html
調べたら、割と結構同じ個所で悩まれた方がいるみたいで。。
てっとり早くmelから呼び出して解決された方なんかもいらっしゃるみたいですね。。。

③ceil/floorしたfloat数値をリストに入れ、そのまま照会すると、ceil/floorされてない!
これも。。。悩みました。
たとえば、

d_list=[]

a=0.4966666
b=100.0
c=math.floor(a*b)
d_list.append(c/b)

print (d_list)

print (d_list[0])

・・・を実行すると、

[0.48999999999999999]
0.49

・・・という結果が返ってきます。
リストに入れたままprintすると、近似値が返ってくるんですね。。。
ちゃんと数値を扱いたい場合は、取り出してあげないといけないのかな??

pythonのドキュメントを呼んでいたところ、
Python は格納されている値の10進小数での近似値を表示するので、格納されている値が元の10進小数の近似値でしか無いことを忘れがちです。」http://docs.python.jp/2/tutorial/floatingpoint.html
・・・との表記が。
これは仕様なのかな。。


ともあれ、なんとか形にできそう。
Pythonは、文法自体はすごくわかりやすいし、いろいろてっとり早かったりするので、
慣れると作業が速くなるかもしれません。処理も早くなるし、APIにもアクセスできるし、
他にもいろいろなモジュールがあるから、便利だし。。。
pythonはいいことづくしという感じでしょうか。

python開発の、よい一歩になりました。

2015年4月21日火曜日

ポリゴン境界を選択するプロシージャ

モデラーさん向けmelToolの開発中、ポリゴンの境界を検出するmelを探していたところ、
Mayaにあらかじめ実装されているプロシージャーで、以下のようなものを見つけました。

polySelectBorderShell(int $borderOnly)

さっと中身を呼んだところ、
これは、すでに選択されているエッジのうち、境界であるものを残して選択する...
というようなプロシージャーのようです。

ポリゴンの境界を検出する際、
あらかじめすべてのエッジを選択しておいて、上記のプロシージャーを走らせれば、
簡単にポリゴン境界を検出できそうです。


これはモデリング作業のとき、ポリゴンマージの漏れなどチェックするときに便利かも??

以下、サンプルソースでありんす。

proc SELECT_BORDER_EDGE(){
    string $NODE_NAME;
    string $NODE_LIST[] = `ls -sl`;
    if(size($NODE_LIST)<1){
        error "ポリゴンノードを二つ以上選んでね。";
    }
    else{
        select -cl;
        for($NODE_NAME in $NODE_LIST){
            //ポリゴンの末端のエッジを選択
            select -add ($NODE_NAME + ".e[*:*]") ;       
        }
        polySelectBorderShell(1); 
    }
}
SELECT_BORDER_EDGE;