Pages

ラベル AE の投稿を表示しています。 すべての投稿を表示
ラベル AE の投稿を表示しています。 すべての投稿を表示

2015年12月31日木曜日

2015ラストは検索スクリプト更新ネタ

お疲れ様です。
最終日にしてぎりぎり今年の仕事が収まりました。

***
さて2015年は”今年もよろしく記事”の次が大晦日になってしまいました。

今年は数件、このブログ読んだ方から連絡を頂いたりと嬉しいレスポンスを頂けた年なので、もう少しマメに書かねばと思いつつ、なかなかネタが無かったりもします。

仕事でメインに使うのが秋口までAftereffectsからCINEMA4Dに切り替わっていたこともあり、またコンポジットソフトとしてBlackmagicFusionに目移りしていたこともあったりして、AEについてはあまり新しいネタもなく、かと言ってC4DやFusionは記事にできるほど理解が深まってない、みたいな宙ぶらりんな一年でした。

C4Dでは、VRayforC4Dを実戦投入できたので、そのへんもっと突っ込んでみたいのと、シミュレーションのNAVIE Effexをそろそろまともに動かしたい、というのがちょっと早いですが来年の豊富でしょうか。
あとは、Fusionに絡めてPythonをいい加減まじめに習得したいところです。
次の更新が2016末なんてことになりませんように。


***
さてさて、毎度長い枕はこの辺にして、今回も本題のスクリプトネタです。
この年末に、以前公開したエフェクト検索スクリプト”searchFX.jsx”のダウンロードが急に伸びたことがありました。

だいたい普段は周に5-6件ほどのアクセスですが、今回はその3倍ほど。
急な需要の原因は分かりませんが、どうせ使ってもらうならちょっとでも便利な方が良いかな、と思い、現在自分が現場で使っている更新版を公開することにしました。
(もっと高機能なエフェクト検索スクリプトは他所で幾つも公開されていますけど)

おまけで、テキストレイヤーを探してくるスクリプトも一緒に公開します。



今回ご紹介するのはこちらの2つ。
・1:searchFx+
・2:searchTxtLayer

searchFx+はその名の通り、以前公開したsearchFXの更新版で現行自分が仕事現場で使っているものです。
目的のエフェクト名を入力することで、そのエフェクトを使用しているコンポ、レイヤーを一覧表示します。

検索部分の機能は同じなので、見つける精度が上がったりなどはしていないのですが、
保存されていないコンポでも検索できたり、検索結果をテキストとして吐き出す前に
AE上のプロンプトで簡易確認できたりします(何気に便利)。

検索に関しては、空白などはそのまま入力しないと検出できませんが、大文字小文字については無視できます。
エフェクト&プリセットウィンドウを開いて(ctrl+5)、見つからないエフェクトフォルダあたりから検討をつけて探すと良いのではないでしょうか。


searchTxtLayerもそのまま、テキストレイヤーをすべて探して一覧表示します。
使用しているフォント名なども表示するので、"もらったコンポに持っていないフォントが使われているレイヤーがあるけど、それがどこだか分からん!"なんてときに便利です。
さり気なく重宝しているスクリプトです。


興味を持たれたら、お気軽にDLして使ってみるなり、中身を覗いてみたりしてください。
致命的なエラーやダメージを与えることはないと思いますが、一応使用については自己責任ということで。
ご意見やご質問などもお待ちしております。


それでは今年はこんなところで。
来年もなにか面白いネタを提供できれば幸いです。
良いお年を!!

2015年1月20日火曜日

2015 スクリプト第一弾 も一つおまけのAEスクリプト ”projectOpenerPlus”

年末にちょっと時間が出来たので復習がてら社内で欲しいツールを募集してみたところ、
「Aftereffectsで既存のプロジェクトを開く際に、いちいちファイラーで深い階層まで潜らなくても済むツール」
というオーダーがありました。

そもそも深い階層にファイルを置かざるをえない仕様がどうなのよ、てのはありますが、 自分一人だと普段思いつかない機能だったのでこれ幸いとひとつ作ってみました。
とりあえず、動作に問題は無さそうだったのでこちらでも公開してみようと思います。

 ”projectOpenerPlus” 

何気に初めてのUI付スクリプトだったりします。
基本的にはAdobeデフォルトのpromptで十分だと思っているのですが、今回はドロップダウンリストを使ったほうが便利かな、というのもありましたし、
そろそろUI周りの作法もひと通り抑えておいたほうが良いかと思ったので、半分勉強も兼ねて…という感じです。

UI周りの参考資料は信頼のAEP PROJECT,ほぼこちらのページの引き写しです。

以下簡単に機能を説明します。

・LaunchPadから起動して、データベース内のフォルダを列挙、直接ファイルを開けるようにします  (ファイルメニューから起動しても問題無いとは思いますが…ひとまず、LaunchPad用アイコンも用意しました)
  データベース(要は普通のテキストデータです)への読み書きを行うので、Afterefects環境設定での「スクリプトによるファイルの読み書き」は必須です。

・指定場所に置かれた、特定書式で記述されたテキストファイルを読み込み、確認できたフォルダをリスト表示。
  そこからドロップダウンリストで選択されたフォルダを開き、AEPファイルのオープンダイアログを起動します。
  スクリプトUIからデータファイルを開くこともできるので、ファイラーに戻らなくても、良く使うプロジェクトのリストを整理することができるかと思います。

・検証はAftereffectsCS6で行っています。
  ファイルの削除などは行わないので危険性は相当低いかと思いますが、念の為使用は自己責任ということでお願いします。
  バグなどございましたらお気軽にご連絡下さい。

さて、以下に毎度恒例のスクリプト本文直貼り。
今回は目新しいところではUI周りくらいでしょうか。
お気づきの方はすぐに分かるかと思いますが、ほとんど上記参考ページのままです。
(古橋様、いつもお世話になっております) 

データベーステキストファイルのパスは、スクリプト自身のパスを基準に取得しようとしたのですが、 LaunchPadからの起動だと上手く取得できなかったためアプリのセッティングパラメータから引っ張ってきました。
 (”app.settings.getSetting("Adobe", "launchPad_scriptsFolder")”) 
その他、リロードの際にドロップダウンリストを一度削除してからもう一度配置するなど、あまりクレバーではない気もするのですが、 どなたか解決策などお持ちではないでしょうか。


(function(){
    /*Main Function---------------------------------------------------------------------------------*/
    function showDialog(){
        
        //1:データベースファイルを読み込む
        var dbFileName="projectOpenerPlus_db.txt";
        var dbFilePass=app.settings.getSetting("Adobe", "launchPad_scriptsFolder")+"/"+dbFileName;
        var dbFileObj=new File(dbFilePass);
        if(dbFileObj.exists){            
            var selectedIndex=-1;
            var db=readDb(dbFileObj);
            //2:フォルダの存在が確認できたデータからだけ、リストを作成する
            var dList=checkFolderExistence(db);
            if(dList.length<1 10="" 240="" 250-10="" 250-b1w="" 250="" 40="" 50="" alert="" amp="" b1h="" b1t="" b1w="" b2h="" b2t="" b2w="" btncancel="w.add(" btndbedit.onclick="function(){" btndbedit="w.add(" btnok="w.add(" btnreload.onclick="function(){" btnreload="w.add(" button="" cancel="" dbfileobj.execute="" dbfileobj.open="" ddl.items="" ddl.onchange="function(){" ddl.selection.tostring="" ddl="w.add(" dialog="" dlist="" dropdownlist="" e="" edit="" else="" g="" if="" name:="" ok="" projectopenerplus="" rdb="readDb(dbFileObj);" rdlist="" reload="" replace="" return="" s="" selected="true;" selectedindex="" split="" this.result="function(){return" this.show="function(){return" var="" w.center="" w.remove="" w.show="" w="new" window="">=0));}

        }else{
            alert("スクリプトと同階層にデータベースファイルを確認して下さい(`・ω・´)ゞ");
            return;
        }        
    }

 /*Sub Functions--------------------------------------------------------------------------------------*/
    function readDb(fileObj){
        if (fileObj.open("r")){
            var dbText=new Array();
            while(!fileObj.eof){
                var tText=fileObj.readln();
                if(tText.charAt(0)=="*"){
                    dbText.push(tText);
                }
            }
            fileObj.close();
            return dbText;
        }else{
            alert("データベースファイルが開けませんでした(´・ω・`)");
            return;
        }
    }
 /*---------*/
 function checkFolderExistence(list){
        var checkedList=new Array();
        for(var i=0; i>> Entry Point
    /*---------------------------------------------------------------------------------------------------------*/
    var dlg=new showDialog;
    if(dlg.show!=undefined){
        if (dlg.show()==true){
            var parentFileObj=new Folder(dlg.result());
            if(parentFileObj.exists){
                var result=parentFileObj.openDlg("Select the aep file", "*.aep");
                if(result!=null){
                    var openFileObj=new File(result);
                    app.open(openFileObj);
                }
            }else{
                alert("選択したプロジェクトのファイルパスが合致しません(´・ω・`)");
            }
        }
    }
})();
こんな感じです。
僕は現状仕事では3案件同時並行中だったりしますが、チェックしたり作業したり、ローカルだったりネットワーク上だったりと作業データ代わりと散らかっているので何気にこのスクリプトを重宝しています。
やればそこそこ出来るじゃないか。 

ちなみに、オーダーをくれた子がその後このスクリプトを使ってくれているかどうか…あまり現場を見た記憶がありません(´・ω・`)
宜しくば、一度お手にとってみて下さい。

それでは、今年も思いついた頃にまたスクリプトネタを上げていくかと思いますので、お付き合い頂ければ幸いです。
そろそろ、CINEMA4DやFusionのスクリプトも書けるようになりたいですね。

ではまた、いつかの次回に。


恒例のダウンロードはこちらからどうぞ。
いつの間にかBox.netのUIも洗練されてきてますね。
(15/01/24 肝心のダウンロードリンク先間違ってたので修正(´・ω・`))
 

2014年3月23日日曜日

帰ってきたお手軽AEスクリプト

気がつけば2014年ももう1/4近くが過ぎてしまい、幾ら何でもおめでたい御挨拶やら新年の抱負を語る空気でもなくなってしまいました…

今年は、新年早々某アイドルアニメ映画のコンポジット手伝いをしていたり、担当していた1年もののTVシリーズアニメが最終回を迎えたりと何だかんだで忙しい第一四半期でした。(反動で今はデータ整理しかしてませんが)
会社もスタッフが増えたり、それに伴って引っ越しを考えたりと慌ただしく、なかなかブログネタも思い浮かばない…という言い訳がすぐ口をついて出て来るのですががが。

以前公開したAfter Effectsのスクリプトがいまだにそこそこ需要があるようなので、これに気を良くして2014最初のネタはこの続編としてみました。

***

今回のネタは、
「選択レイヤの長さをアクティブコンポの尺に合わせるスクリプト」
です。

これはもともと、別に作っていた一連の作業自動化スクリプトの一部なのですが、なかなかに重宝するツールなのです。
(似たような作業をしている方なら思い当たるかもしれませんが、主にAE上でコンポジションとして読み込んだPSDとその内包するレイヤ群の尺を親コンポの尺に合わせる際に使います。
所謂美術素材の扱いですね)

今回のポイントは「再帰処理」を上手く使うことです。
まあ、見た方が早いので早速サンプル行ってみましょう。

/*---------------------------------------------------------------------------------------------------------*/
    function fitDuration(comp){
        var tgtList=comp.selectedLayers;    //選択したレイヤ(配列)
        var sList=[];                                 //処理をスキップしたレイヤリスト(配列)
        var txt="skipped layers\n";            //スキップしたレイヤリスト
        var ct=1;                                      //スキップしたレイヤ数
        
        for(var i=0; i<tgtList.length; i++){
            if(tgtList[i].source instanceof CompItem){
                sList[i]=recSetDur(tgtList[i].source, comp);
                
                if(sList[i]!=undefined){
                    for(var l=0; l<sList[i].length; l++){
                        txt=txt+(ct).toString()+" : "+sList[i][l][0].toString()+" > #"+sList[i][l][1].toString()+" "+sList[i][l][2].toString()+"\n";
                        ct=ct+1;
                    }
                }else{
                    sList.pop();
                }
            }
            tgtList[i].outPoint=comp.duration;
        }
    
        if(txt!="skipped layers\n"){
            alert(txt);            
        }        
    }
    
    function recSetDur(cC, pC){
        var dD=cC.duration;              //渡されたコンポの元尺(変更前の尺)
        var nD=pC.duration;              //親コンポの尺(変更後の尺)
        
        cC.frameRate=pC.frameRate;
        cC.duration=nD;
        
        var lFlag=false;                    //レイヤロックの有無
        var slList=[];                        //処理をスキップしたレイヤリスト(配列)
        var tmpSlList=[];                  //プリコンポ内での処理をスキップしたレイヤリスト(配列)
        
        for(var j=1; j<=cC.numLayers; j++){
            if(cC.layer(j).locked){
                cC.layer(j).locked=false;
                lFlag=true;
            }
        
            if(cC.layer(j).source instanceof CompItem){
                tmpSlList=recSetDur(cC.layer(j).source, cC);
                if(tmpSlList!=""){
                    for(var k=0; k<tmpSlList.length; k++){
                        if(tmpSlList[k]!=""){
                            slList.push(tmpSlList[k]);
                        }
                    }
                }
            }
        
            if(cC.layer(j).outPoint==dD){
                cC.layer(j).outPoint=nD;
            }else{
                slList.push([cC.name, cC.layer(j).index, cC.layer(j).name]);
            }
            if(lFlag){
                cC.layer(j).locked=true;
            }
        }
        return slList;
    } 

/*---------------------------------------------------------------------------------------------------------*/
(ちょっと今回SyntaxHighlighterで上手く貼れていないようなんですが、如何でしょう?)


 それでは、恒例の要領を得ない解説をば。

 今回はざっくり2つの関数に分かれています。


 一つ目の”fitDuration”が基準となる親コンポを渡され、その中の選択レイヤに対して尺調整をする関数です。 
変数定義時に簡単にコメントしてありますが、変数tgtListに選択レイヤを格納し、その数だけ繰り返し処理を回しています。 
もし単純にプリコンポされたレイヤを含まない状況であれば、
”tgtList[i].outPoint=comp.duration;”を繰り返すだけです。

が、もし選択レイヤがプリコンポ状態でその内部に更にレイヤ要素を含む場合、上述の再帰処理を使ってその奥まで確認をする必要があります。
それが、2つ目の関数”recSetDur”の役割です。


この関数では、まず尺の基準になる親コンポと処理対象のコンポの2つが渡されます。
対象コンポの尺(とフレームレート)を合わせるのは簡単なのですが、問題はその内包するレイヤ群です。
対象レイヤはロックされているかもしれないし、コンポ尺の一部でしか使われていないかもしれない。
更には、もう一段プリコンポされて更に深い構造を持っているかもしれない…


そこで今回の処理では、
☆ロックされたレイヤも処理対象とする(ロックを外して尺変更処理をし、再度ロックをかける)
☆コンポ尻まで尺のあるレイヤのみを処理対象とする(連番ファイルだと尺を伸ばしようがないレイヤもありますが)
☆プリコンポされたレイヤは更にその奥までチェックする

★処理対象外のレイヤは、その名前と親コンポ名をチェックして処理完了後に警告表示する

という方針にしてみました。


ロックされたレイヤまで処理されては困る、余計なアラートは要らない、という方は適宜条件を調整してみてください。
(そもそも、ここで見逃している条件もあるかもしれませんし)


ちなみにこのアラート処理は今回用に思いついた機能なのですが、思いの外面倒くさく、コードも冗長になってしまいました。
自分だけが使うツールの場合は、もっとシンプルなコードにします。


閑話休題。
recSetDur関数中程の”tmpSlList=recSetDur(cC.layer(j).source, cC)”が再帰処理と言われる部分ですね。
対象レイヤがプリコンプされたものの場合、渡してやる変数をちょっと変えて、再度同じ関数(自分自身)に処理を投げています。
この辺使えると、簡単なスクリプトでも一気に処理の汎用性が広がります。
してやったりの瞬間です。

その後の配列(slList,tmpSlList)を使ってのやりとりは、処理を飛ばしたレイヤ情報の受け渡し部分になります。
それらをまとめて、元のfitDuration関数に戻してやったら、最後に該当レイヤの尺を調整して(内⇒外の順番を間違えると予想外の結果になってしまいます)処理は終了です。


処理を飛ばしたレイヤがあれば、最後に一覧表示します。
以上の処理をいつものテンプレにまとめたjsxファイルをアップしておきましたので、宜しければ見てみてください。




今回のスクリプトはコンポの内容を変更してしまうのでundoGroupの登録は必須です。
これをしておかないと、間違った処理をした後に何度Ctrl+Zしなくてはいけないか分かりません。

上記アップロードファイルは対応済みですが、念の為ご使用前にプロジェクトを保存しておいて頂けると良いかと思います。(一応いつものご使用は自己責任というやつです)

という訳で、例によってツッコミ宜しくお願いします。Twitter辺りが手っ取り早いかと。

こういうちょっとした機能でも、必要とした時にササッと書けるとなかなか重宝すると思いますので(経験談)、皆様お気軽に取り組んで頂き、そしてあわよくばネットにバンバン公開していって頂けると良いのではないでしょうか。

2013年5月23日木曜日

お手軽AEスクリプト(その一)

書いた本人も半分忘れていたこのブログですが、気がつけば1年以上更新していなかった…となると急に気になりだすのが人情というもの、ひと月ぶりにお休み貰ったことだし、何か書いてみることにしました。

と、ちょうど手元に良いネタがあったので、今回はコレをご紹介。先日社内で別チームのスタッフに頼まれて作った、After Effects用単機能スクリプトです。
わずか数十行とネタとしても手頃ですし、春の新番ラッシュを乗り越え、5月病をクリアし、そろそろスクリプトにでも手を出してみようかな~という殊勝な業界若人のヒントにでもなるかな?と。
ある程度書ける人には今更な内容かと思いますが、まあ、こんなもんでも役に立つんだよ、という事例紹介みたいなノリで行きたいと思います。


◆その1:指定エフェクトを使用しているレイヤー一覧を書き出す ”searchFx.jsx"
短いのでそのまま書いてみます。

(function(){
    // ---------------------------------------------------
    var p=app.project;
    var txt="";
    var idx=1;
    // ---------------------------------------------------
    if(p.file.exists){
        var defaultPath=p.file.parent.fsName+"/";        
        main();
    }else{
        alert("プロジェクトを保存してからスクリプトを実行して下さい");
    }
    // ---------------------------------------------------
    function main(){
        var tgtFxName=prompt("検索するエフェクト名を入れて下さい 完全一致オプションは「^プラグイン名$」", "プラグイン名");
        var result="";
  if(tgtFxName!=null){
   for (var i=1; i<=p.numItems; i++){
    if(p.item(i) instanceof CompItem){
     result=searchFxLayer(p.item(i), tgtFxName); 
    }
   }
   dumpTxt(result, tgtFxName);
   alert("完了しました!(`・∀・´)"+"\n"+defaultPath+" 直下を確認して下さい");
  }
    }
    //
    function searchFxLayer(tgtComp, srcStr){
        for(var j=1; j<=tgtComp.numLayers; j++){
            var tLayer=tgtComp.layer(j);
            if(tLayer.matchName!="ADBE Camera Layer" && tLayer.matchName!="ADBE Light Layer"){
                var m=tLayer.property("Effects").numProperties;
            
                for(var k=1; k<=m; k++){
                    if(tLayer.effect(k).name.match(srcStr)!=null){
                        txt=txt+"\n"+idx+" :使用コンポ名: "+tLayer.containingComp.name+" // 使用レイヤー名: "+tLayer.index+" ; "+tLayer.name;
                        idx=idx+1;
                    }
                }
            }
        }
        return txt;
    }
    //
    function dumpTxt(rslt, sfxn){
        var logObj=new File(defaultPath+"searchResult_"+p.file.name.split(".")[0]+"_"+sfxn.replace(/\s| /g,"")+".txt");

        if(logObj.open("w")){
            logObj.writeln("<<< 検索対象プロジェクト名:"+decodeURI(p.file.name)+"   /   検索対象エフェクト名 : "+sfxn.replace(/\s| /g,"")+" >>>");
            logObj.write(rslt);
            logObj.close();
        }else{
            alert("ログファイルを開けませんでした");
            return;
        }
    }
})();

こんな感じで。
順に見えてもらえばやっていることはまあ分かるかと思いますが、一応簡単な解説をば。


◆その前に
まず大前提として、このスクリプトではログとしてテキストファイルを書き出すのでAE側で「編集」⇒「環境設定」⇒「一般設定」⇒”スクリプトによるファイルへの書き込みと~”にチェックを入れておく必要があります。


* * *
では頭から。
1行目、及び最終57行目で使用している”(function(){})();”は、所謂無名関数というものです。要は変数のスコープをこの内側に限定する目的で使用されてます(たぶん)。

7行目で、実行時のプロジェクトがファイルとして保存されているか否かを以下のスクリプト実行のスイッチとしています。プロジェクトファイルが存在すれば、そこからファイル名やプロジェクトファイルがあるフォルダパスなど様々な情報を取得出来ます。

14-26行目がメインとなる関数部分。ダイアログで検索するエフェクト名を取得し、その「名前」のエフェクトを使っているレイヤーを、プロジェクト内全てのコンポから洗い出します。
入力されたエフェクト名と、実際にプロジェクト内で使用されているエフェクト名の照会は、正規表現を用いたmatchメソッドを使用しているため、入力時の検索オプションとして(手入力による ><; )前方、後方完全一致オプションを使用できるようになっています。

出来れば、きちんとUIをデザインしてボタンオプションなどで実装したいところですが、AEは非常にUIデザインに向いていないのでとりあえずコレでお茶を濁します。隣でデザイナーがまだかまだかと期待の眼差しを向けてくる状況では、優雅さよりスピードだったりもするのです。


閑話休題。
19行目でプロジェクト内のデータを頭から虱潰しにしていきながらコンポアイテムに当たった場合、そのコンポアイテムと、検索エフェクト名を次の「コンポ内のすべてのレイヤーから、指定した名前のエフェクトを使用しているレイヤーを洗い出す」関数(”searchFxLayer”)に渡します。

この関数も、基本は上の「プロジェクト内のすべてのアイテムから、コンポアイテムを洗い出す」main関数の機能と同じです。

ここで特徴的なのは、31行目の”matchName”と32行目の”property("ADBE Effect Parade")”でしょうか。

”matchName”はAEのUI上で表示される名称とは別にAE内部で各プロパティを認識するための名前で、使用言語による変化が無いため、スクリプトでプロパティを指定する際には(大抵の場合)通常のname属性よりオススメされています。

2つ目の”property("ADBE Effect Parade")”は、エフェクトのmatchNameを使用したエフェクトプロパティへのアクセスで、そのレイヤーの総エフェクト数を取得しています。
(カメラ、ライトオブジェクトはエフェクトを持てないので、ここでは最初に除外している訳です。matchNameを使用することで、カメラ、ライトレイヤーの名前を変更していても抽出に影響ないのがミソです)

この辺りのProperty/PropertyGroup objectについて話しだすと長くなる上に、恐らく僕の手には余るので、既にネット上で詳しく説明されているページを紹介して逃げたいと思います。
⇒After Effectsユーザーのための、プログラミング入門 その7 スクリプト作成補佐スクリプト Property/PropertyGroupについて


さて、気を取り直して、そのレイヤーのエフェクト総数が分かったらまたしても同型の処理、「エフェクトの数だけ総当りで調べて、指定エフェクト名と一致するエフェクトを洗い出す」のが、34-35行目の処理になります。
見つかったら、そのコンポ名、レイヤー名を内部的にメモして、次のエフェクトへ。
一つのレイヤーを調べ尽くしたら、そのコンポ内の次のレイヤーへ、そのコンポ内も全て調べつくしたら、元のmain関数に戻って、プロジェクト内の次のコンポへ…
と渡って、プロジェクト内の全てのレイヤーを調べ尽くします。
人の手と眼だと気が遠くなる上に見逃しもありえますが、機械に任せておけばその心配はありません。エラーも込みで、書かれたとおりに実行してくれます。


最後に、見つけたコンポ名、レイヤー名をメモしたデータを”dumpTxt”関数でテキストデータとして書き出します。
日本語エフェクトに含まれる空白を除去したり(46行目)、日本語ファイル名での文字化けを回避したり(49行目)しつつ、作業完了となります。
完了メッセージの顔文字にイラッとしたら、是非ともエディターを開いてソースを書き換えてしまいましょう。千里の道も一歩から。
* * *


◆post script
スクリプト習得の学習曲線がどのようなものか、まあ人によってそれぞれなのでしょうが、書いてみたら思いがけずいろいろな要素が混在していて、ちょっと学習ネタとしては不適切だったかもしれません。その場合は、遠慮せず職場に一人はいるはずの3度の飯よりスクリプトが好きな人や、勿論僕当てでも構いませんので、質問して頂ければと思います。
仕事中はたいていTwitter(@hachinogy)にいます。あそこの記述が変だ、解説が怪しい、などのツッコミもお待ちしております(どうぞお手柔らかに)。
検索対象を変更すれば、他所から来た巨大なプロジェクトファイルの何処かに、見たこともないフォントを使用した謎のテキストレイヤーが隠れている…なんて事態にも対応出来ますね。


さて、ツッコミが入る前に軽く自己弁護しておきますと、今回のスクリプト、ざっと見た人ならきっと誰もが「何故matchNameでエフェクトも検索しないのか」と疑問に思われたことでしょう。エフェクト名による検索は、エフェクトの名前を変更していた場合効果が半減します。
正確を期すならば、検索時には見慣れたname属性によるエフェクト名を入力してもらい、内部でそれをmatchNameに変換する関数を通すことで可能な限り、matchName検索をかける、というのが最善なのでしょう。
今回は、たまたまデフォルトのエフェクト名を変更していなかったパターンだったので、実装速度最優先ということで上記のような内容になったまでです。
ちょうど”hiroshisaito.net”の斉藤さん(After Effects Plugins matchNames)や”AfterEffects compZero”の吉岡さん(Plugin matchName)がステキなリストを上げてくださっているのを発見したので、自分でもバージョンアップを図りたいと思います。


あ、その1と言っておきながらその2を書くには長すぎた気がするので、分割して次回へ続く…。
次回、「コメントされたレイヤーを削除するスクリプト(”deleteCommentedLayer”)」




一応、ファイルもアップロード。



2009年10月25日日曜日

スクリプトの日々

裾野を広げつつ、フィードバックを得るため、ついでに自分もスクリプトに慣れるために会社の社内掲示板にAfterEffectsスクリプト目安箱みたいなスレを立ち上げてみた。

以前作った”CompBuilder”みたいな大掛かりなものでなくて、
「こんなことが出来たら、AEでの作業がちょっと便利に」程度のものをササっと書いてLAN上にアップする。

とにかく敷居を下げて「こんなこと、チャチャッと出来ない??」という発想を持って貰えれば嬉しい。
こっちはこっちで自由な視点から思い掛けない発想を得ることが出来るし、何より小ネタを速く書くことは良い練習になる。

「こないだのあれをちょっと弄ればこんなことできるんじゃないか?」
「このUI,ダサいから自分の好きなようにカスタマイズしちゃおう」
というところまで行けば布教成功。
新たな同志の誕生である。

今のところ出来たのが、
・「選択レイヤーの一つ上に調整レイヤーをつくるスクリプト」
・「シャイ/非シャイレイヤーを反転するスクリプト」
という、かゆいところに手の届くような小ネタばかり。

構想が決まれば30分ほどで完成するので、書いているほうもストレスが無く楽しい。

CS5の話もちらほらと聞こえてきて、OSの64bit化、扱う映像の高解像度化など、
いつまで映像制作をAE完結型で出来るのか、そもそもワークフロー自体も全然違うものが考え得るのではないか。
次を見据えた環境も作らないと、と悩みは尽きないけれど。

まずは、今ある環境を(ちょっとだけ)より良くすることもきっと無駄ではないはずだ。

2009年6月28日日曜日

ワレ、新システムに移行セリ



真夏の一大決戦に備えて春先からチマチマ武器を作ってきましたが、そのメインシステムの試作版がとりあえず完成、半月前から実戦投入を始めました。

その正体は、至る所のスタジオで独自実装されているであろう「AfterEffectsによるアニメコンポジット(撮影)」の作業支援スクリプト(.jsx)です。うちの奴はExcelによるカット管理表と連動して、各カット毎のセットアップを自動化します。(何を今更って?まあ、そこはそれ、いろんな事情があった訳で)


ちなみに、良くある30分のTVアニメでは大体1話300カット前後、といったところでしょうか。それぞれのカットの背景、キャラ、その他特殊素材といった「構成要素」を、AfterEffects(AE)上で合成、一つの「映像」に纏め上げる訳です。
そのファイル数は優に万を超え、さらに制作状況によってはリアルタイムで更新されていきます。素手で立ち向かうは余りに無謀というものです。

また、この工程で最終的に求められるのは上記の「映像構築能力」だと思いますが、前提としてその膨大な素材を取り扱う作業が各カット毎にルーチンワーク的に発生します。ここを如何に効率的に処理し、本来の映像制作作業に時間と脳みそを割り当てるか。この認識がある故に、おそらく各社各様の「作業支援システム」が作られているのではないでしょうか。(各社各様というところに、そも全体としてシステマチックになりきれていないアニメ制作工程の問題があるとも言える気もしますが)


閑話休題。
とりあえずうちの子は現在手がけている作品固定で組んであるのでなかなか融通の利かない頑固者ですが、限られた条件下では結構な働きをしてくれます。(一応機能別にパーツ分けしてあるので、他作品への転用も比較的簡単に対応できる予定、つまり未定)


流れとして、
1;カット毎の情報ファイル書き出し(これはカット表上のVBAマクロで)
2;AEで情報ファイルを解析、それに従って素材の読み込み、配置、シーン毎に設定された処理掛け、及び作業ファイル(aep)の名称や尺設定、指定場所への保存(こちらを今回のスクリプト(.jsx)で)
をほぼ全自動で処理します。

各コンポジット作業者の手元には、「担当カットが作業可能になった段階」で「仮組みされた作業データ」が提供される、ということになります。作業者の能力よりもスピードと正確さを要求される処理を自動化することで、作業の効率化と正確化、それにより期待される映像的表現の向上を目指そう、という狙いです。

時間的には、上記2の工程、AE上で情報ファイルを読み込んでから一連の処理をこなしてデータを保存するまで30秒は掛かりませんでした。「手作業で処理する場合との時間差」*「カット数分」の時間を人の手によるオペレーションに割り当てることが可能になる計算です。


半月ほど実践稼動してみて、いろいろと課題も見えてきました。作業の効率化、及び統一性の向上、という点は時間の無いTV制作の中では非常に大きい。(極端なケースでは作業量が倍になった、という例もあります。今までどうやってたんだ…)また、処理の統一性の向上はチェック担当者としてはありがたいものです。

が、問題点としては運用の機動性も指摘されました。一度動き出すと速いし効果も大きいのですが、データを収集、整理する段階でまだまだ効率化を追求する余地が多分にある。現場ではこのシステムをよく大型エネルギー砲(某巨大宇宙戦艦のアレとか、某八島作戦のアレとか)に例えてました。曰く、撃てれば圧倒的だが撃つまでが大変・・・」
むむむ…それは本意ではない。あくまで映像制作上のストレスを緩和する為のシステムが(規模は小さくとも)新たなストレスの温床となっては本末転倒です。

この解決策として、工程の見直しとスクリプト処理の高速化、そして(大型エネルギー砲に対して)小型携帯火器、つまり「全体として作動するシステムに連動して機能する個人レベルでのスクリプト群」を構築しているところです。


この、一度ではスパッと現状を打開できないあたりが僕の現在におけるシステム構築能力の限界、といったところでしょうか。傍から見れば亀の歩みにも見えそうですが、少しずつバージョンアップして「美しい=理に適った映像制作システム」を構築していきたいと思います。
(そして忘れてはいけないのが、このシステムがあくまで映像制作「支援」目的だということ。システムを構築しただけで出来上がる映像が良くなる訳ではない。本来の眼と腕も常に磨き続けなくては。)


そろそろ夏の最前線の地響きがしてきました。戦局はどうやらかなり厳しいようで、各地から厳しい情報が寄せられてきます。戦場の徒花にならないよう、戦術を磨き、兵を鍛え上げ、人事を尽くして天命を待ちたいと思います。死亡フラグなんてへし折ってやる!!

2009年5月27日水曜日

AEでの色空間(若干修正)

先日の内容に早速ミスを発見したので突っ込まれないうちに修正。現状特にレスは無いので実害は無いと信じたいですが、ご迷惑をお掛けした方がいらしたら御免なさい。m(_ _)m 以後ちゃんと検証します。まあ、ある程度の見切り発車は差し引いてごらん下さい(言い訳~)。

で、修正点ですが。
HSB⇒RGBでS(彩度)が0の時RGBが[0,0,0]となっていたのを[v,v,v](v=明度)にしました。計算式が良く分からなくても、彩度が0なら後は色を決めるのは明るさだけってのは明白でしたね。ちゃんと自分の書いていること読み返さないとなあ。

まだ問題点が残っておりまして、若干正確性に欠けるようです。8bit,16bit共に1%以下の誤差ですが、気になるものは気になる。恐らく小数点以下の処理あたりが原因ではないかと思うのですが。ど~~しようかしら。

そうこうしている内に、上記関数を内包する、「アニメ撮影下準備自動化スクリプト」がだいぶ形になってきました。ウチの作業環境に特化した非常にローカル色の強いものですが、その分はまった時の効果は大きいです。需要があるか分かりませんが、今後、現状思い描いている作業システムなぞご紹介出来れば、と考えています。
それでは。
(´・ω・`)ノシ

2009年5月23日土曜日

AfterEffectsでの色空間

コーディング中にちょっと躓いたのでメモ。[※修正版@090527]

AEではスクリプトによって平面を作る際に"addSolid"というメソッドを使いますが、ここで色を指定するやり方が良く分かっていませんでした。

スクリプトガイドによると、
”app.project.item( index).layers.addSolid(color, name, width, height, pixelAspect, duration)”
となっており、”color”に関しては、
”The color of the solid, an array of four floating-point values, [R, G, B, A], in the range [0.0..1.0].”
とされています。
つまり、RGBを各0~1で設定してやらんといけない訳ですね。

見慣れた0~255でないのは、プロジェクトの色深度が16bit,32bitの場合もあるから、というのは理解できます(実際、アニメ撮影業界はそろそろ16bitが標準となっているのではないでしょうか)。

が、通常のGUIで平面を作成する際のパラメータは、相変わらずHSBと各色深度分のRGB(8bitなら256階調)のままです。
ん~~、何か分かりにくい。

という訳で、色深度が幾つだろうがパラメータが変わらないHSBをベースに、0~1のRGBへコンバートする関数をチャラっと組んでみました。(参考:http://en.wikipedia.org/wiki/HSL_and_HSV)

//-----------------------------------
function convHsvToRgb(h,s,v){
s=s/100;
v=v/100;
var Hi=Math.floor((h/60))%6;
var f=(h/60)-Math.floor(h/60);
var p=v*(1-s);
var q=v*(1-f*s);
var t=v*(1-(1-f)*s);
var r;
var g;
var b;

if(s!=0){
switch(Hi){
case 0:r=v, g=t, b=p; break;
case 1:r=q, g=v, b=p; break;
case 2:r=p, g=v, b=t; break;
case 3:r=p, g=q, b=v; break;
case 4:r=t, g=p, b=v; break;
case 5:r=v, g=p, b=q; break;
default:r=v, g=v, b=v;
}
}else{r=v;g=v;b=v;
}
var result = [r, g, b];
return result;
}
//-----------------------------------
AEのGUIでの表示がSVとも0-100%なので、頭で除算してあります。
それ以外はほとんどWEB上の参考文献のまま・・・

この関数に平面設定時のHSB情報を渡してやると、そのままの色のRGB(0-1)値に変換できるはずです。
後は、
”app.project.item( index).layers.addSolid(convHsvToRgb(h,s,v), name, width, height, pixelAspect, duration)”
とでもしてやれば一件落着?

何でこんなことをやっているかというと、アニメ撮影時、シーン毎に設定された色平面を自動処理的に作成したいからです。
これが出来ないと、夏の決戦を生き残れない予感・・・

付け焼刃の対応ですのであちこち綻びがあるかと思います。
上記の関数に関しても、何かお気づきの点あればご指摘下さい。

2009年5月10日日曜日

びびった・・・

Terraon様、白石運送様にて先日のスクリプトを紹介して頂く。
( ゚д゚)

(つд⊂)ゴシゴシ

(;゚д゚)

このAAを我が身で味わうことになるとは思いませんでした。
いやあ、びっくり。
まだまだふつつつか者ですが、今後とも宜しくお願い致します。


さて本題。
Terraon様のツッコミにもありましたが、コンポジット作業時にAfterEffectsのプロジェクト作業内容を確認せずに監視先に回してしまうことは確かにリスキーです。
作業途中の非常に重いデータで監視用のマシンやレンダー先に無駄な負担をかける心配もあります。
うちはどうしているかというと・・・実は作業者の判断に任せているという・・・
安全を期するならばセーフティーネット込みのワークフローを構築すべきですね。

また、Terraon様が示唆されているように、プロジェクトの保存と同時に監視用のデータを作成する方が効率的かつ安全な場合が多いかと思われます。
僕が現在作成中のスクリプトでは、こちらの方式を取るつもりです。こちらも後々公開できれば。

WSH(Windows Scripting Host)自体はwindowsユーザーならすぐに使える上、VBScript,JScriptと言語も豊富、ネット上にも情報が満載なので、非常にお勧めです。あまりうちの業界で使われている例を見ませんが。(MacならAppleScriptに当たるのでしょうか)
OS標準なのでAE以外との橋渡しにも使えますし、使い方によっては化けるのではないでしょうか。そして誰か良いスクリプトを見つけた、書いたら是非教えて下さい。

ちなみに拙スクリプトですが、例えば"SendTo"に入れておくと、AEP(複数)選択→右クリックから「送る」で監視用データ作成へと持って行けたりします。地味に便利。


とにもかくにも。
ご紹介、ご指摘ありがとうございました。
またぼちぼち小ネタをご紹介していきたいと思います。
(´・ω・`)ノシ

2009年3月1日日曜日

ばーじょん

ほげほげ。
日々の雑務の波を乗り越えて、AfterEffectsのjsxコーディングに着手。
やはり休日(出勤)は集中出来てイイナ。

…なんだけど。
こんな簡単なことも出来ないのか、と自分に呆れっ放し。
ネット上の先達とはエライ差だなあ。
何はともあれ、自分のところで使えなければしょうがないのでガンバロウッと。

さて、目下悩みの種はAEのバージョン違い。
下位バージョンのプロジェクトは読み込むことは出来てもいちいちalertが出る。
全自動処理したいのにこれが邪魔で邪魔でしょうがない。
(けどまあ、alertがスクリプトで抑制出来ちゃったらそれはそれで問題よね)
走らせる前で分岐させるしかないかしらん。

スクリプトを使いこなしている皆々様方はどうしていらっしゃるのでしょうか。

それにしてもAdobeの、特に最近のバージョン攻勢はどうにかならんのか。
食っていくためにはしょうがないのかもしれないけれど、毎年毎年新バージョンでござい、
と出されてもねえ…
そのまえに、FIXされてない膨大なバグをどうにかせいっ!!
せめてバグフィックス版のマイナーチェンジで進めてくれないでしょうか。

アニメ業界御用達のAE6.5.1がサポート外となる(?)今年の年末にかけて、
いろいろと動きがありそうです。

でもきっと直前まで動かねえよな、この業界。
目先のことで精一杯だし。
とりあえず、うちも直近の問題を片付けないと。

というわけで監督、早くシナリオ上げて下さい。
OAまでもう2ヶ月チョイですよ~~~。