« 愛しの chm (;´Д`)ハァハァ | トップページ | ピックしたグループでポン。 »

2012年1月29日 (日)

マテリアルなグループでポン。

不真面目な元気な某氏はどうやら雪国で広い板の上に乗って斜面上を重力に引っ張ってもらう遊興に耽っているらしい。 真面目な不元気な俺は今日も仕事してるぜオルァ


そんな某氏をあざ笑うかのように、以前書いたスクリプトを投下してみるテスト。




JScript
---------------------------------------------------------------

var oGroups = XSIFactory.CreateObject( "XSI.Collection" );
for ( var i=0; i<Selection.count; i++ )
{
    if ( Selection(i).type == "material" )
    {
        var oMat = Selection(i);
        var oObjectsUsingTheMat = oMat.UsedBy;
        var oGroup = ActiveSceneRoot.AddGroup( oObjectsUsingTheMat, "Mat_" + oMat.name );
        oGroups.Add( oGroup );
    }
}


---------------------------------------------------------------


Explorer からマテリアルを選択して実行します。

すると、そのマテリアルを使っているオブジェクト&クラスタが入った Group ができます。 1マテリアルにつき、1グループですね。

以上。





俺もずっと前に書いていました。 誰でも考えることは同じというか、ええ、こういう需要ありますよね。 ならなぜ標準機能で搭載しないのだ嘔吐デスクゴルァ。




これだけではあまりにもアレなので、コメントを入れてみましょう。


JScript
---------------------------------------------------------------



//    選んでいるものをループするぜ
for ( var i=0; i<Selection.count; i++ )
{
   
//    もしタイプが Material だったら以下を実行するぜ
    if ( Selection(i).type == "material" )
    {
       
//    これは代入しただけだぜ。 別にしなくてもいいんだぜ。
        var oMat = Selection(i);
       
      
  //    Material.UsedBy で、そのマテリアルがアサインされているオブジェクト/クラスタがコレクションとしてゲットできるぜ
        var oObjectsUsingTheMat = oMat.UsedBy;
       
       
//    取得したコレクションをメンバにした Group をシーンルートに作るぜ
        var oGroup = ActiveSceneRoot.AddGroup( oObjectsUsingTheMat, "Mat_" + oMat.name );
       
      
//    作った Group は oGroups に追加しておくぜ
        oGroups.Add( oGroup );
    }
}

//    最後に選択しておしまいだぜ
SelectObj( oGroups );


---------------------------------------------------------------


ポイントは UsedBy でしょうかね。 これは Material オブジェクトに対して効くプロパティのひとつですね。 そのマテリアルを使っている全オブジェクトを返します。 

なので UsedBy を使うためにはまず Material オブジェクトが取得できてなくてはいけないのですが、この場合は、Selection から取得済みですね。 Selection(index) と書けばそれは既にオブジェクトになってますから。 でもそのオブジェクトが Material オブジェクトとは限らないので、if 分の中で type を調べて、 Material だった場合のみ処理をします。 なのでこの UsedBy を使う時点で既に Material オブジェクトを取得できているわけです。





UsedBy が返してくるオブジェクトは、3Dオブジェクトかもしれないし、グループかも知れないし、クラスタかもしれないですね。なんでもかんでも返します。 数は1つかも知れないし、10個かもしれない。 

返って来るのは Collection です。 UsedBy のヘルプを見れば、コレクションを返すと明記されています。 UsedBy の場合、正確には、ProjectItemCollection ですが、これはコレクションの中身の種類を表すものであり、今はどうでもいいです。  コレクションとは、「集合体」です。  この集合体ってのは、まあ、平屋1階建ての1人暮らし用アパートだと思えばいいと思います。 個室に分かれいていて、それぞれの部屋には1人しか入れません。 平屋と言ったのは、2階以上がないからです。水平に部屋の数が増えていく平屋アパートです。垂直には増えません。

コレクションとして返って来る場合は、1つしか見つからなくても、やはりコレクションとして返って来ます。


まあいいや、今回のスクリプトの中では、コレクションであるかどうかは、まあ、あまり本題とは関係ないですね。 ついでにコレクションの性質を述べてみただけです。





で、UsedBy を使って目的の人たちを取得できたら、そいつらを使って Group を作ります。これは AddGroup メソッドですね。 Model オブジェクトに対して効く呪文です。 なので AddGroup を使って Group を作ろうと思ったら、まずは Model オブジェクトを取得しなければいけません。 

でも今回の場合はシーンルートでいいので、ActiveSceneRoot.AddGroup としています。 ActiveSceneRoot ってのは、その中身にシーンルートがオブジェクトとして取得されているものです。 シーンルートってのは Model ですから、ActiveSceneRoot と書けばもうその中身は Model オブジェクトです。 なので、AddGroup の呪文が効きます。 

「AddGroup を使うために、俺は今、Model オブジェクトを取得しているんだぜ」 ということを明確に意識したい場合は、

 var oModel = ActiveSceneRoot;
 oModel.AddGroup( うんたらかんたら );


と書いてもいいですね。まあ、冗長ですけど。
冗長でも、初心者のうちは、このように書くほうを俺はオススメしたい気分。 自分が何をしているのか明確に意識できますからね。 理解への近道です。








上のスクリプトの場合、Material を選んでいることが前提になってます。 これを、他のものが選ばれていても動くようなスクリプトに改造します。



JScript
---------------------------------------------------------------

//    処理対象のマテリアルをまず全部引っかき集めるぜ。器はこれな。 
var oTargetMaterials = XSIFactory.CreateObject( "XSI.Collection" );


//    器に入る法則はこれな。
//        MatLib を選んでいた場合 → その MatLib 以下のマテリアル全部が対象
//        マテリアルを選んでいた場合 → そのまんま、そのマテリアルが対象
//        何も選んでなかった場合 → シーン全体のマテリアルが対象
//        MatLib か Material 以外のものが選ばれていたら → 何もしない

//    行くぜ

//    何も選んでなかったら

if ( Selection.count == 0 )
{

    //    シーンにある全部の MatLib をかき集めるぜ
    var oMatLibs = ActiveProject.ActiveScene.MaterialLibraries;
//コレクションとして帰ってくるから、変数名は複数形にしようぜ
   

    //    かき集めた MatLib をループして、そのLib以下にあるマテリアル全部 = Lib.Items を器に入れるぜ
    for ( var i=0; i<oMatLibs.count; i++ )
    {
        oTargetMaterials.AddItems( oMatLibs(i).Items );
    }
}


//    何も選んでない場合は上の if 以下が実行され、そしてここ以下の for ループは発生しないから、
//    ここで上の if に対して else はしないぜ。 で合ってますかどうですか。

//    選んでいるブツをループ

for ( var i=0; i<Selection.count; i++ )
{

    //    もし MatLib だったら、Lib 以下にあるマテリアル全部 = Lib.Items を器に入れるぜ
    if ( Selection(i).IsClassOf( siMaterialLibraryID ) )
    {
        oTargetMaterials.AddItems( Selection(i).Items );
    }
   

    //    もし Material そのものだったら、そのまま器に入れるぜ
    else if ( Selection(i).IsClassOf( siMaterialID ) )
    {
        oTargetMaterials.Add( Selection(i) );
    }
   

    //    上の2つに引っかからなかったら、違うものを選んでいるということなので、器に追加しない
}




//    後で Group を選択したいので、作った Group を入れる箱を用意しておくぜ
var oGroups = XSIFactory.CreateObject( "XSI.Collection" );

//    器に入ったマテリアルをループするぜ。 器が空っぽなら、このループは発生しないぜ

for ( var i=0; i<oTargetMaterials.count; i++ )
{
    var oMat = oTargetMaterials(i);
   

    //    Material.UsedBy で、そのマテリアルがアサインされているオブジェクト/クラスタがコレクションとしてゲットできるぜ
   var oObjectsUsingTheMat = oMat.UsedBy;
   

    //    取得したコレクションをメンバにした Group をシーンルートに作るぜ
    var oGroup = ActiveSceneRoot.AddGroup( oObjectsUsingTheMat, "Mat_" + oMat.name );
   

    //    作った Group は oGroups に追加しておくぜ
    oGroups.Add( oGroup );
}

//    最後に選択しておしまいだぜ
SelectObj( oGroups );


---------------------------------------------------------------



最初のスクリプトでは、選択中のブツをループして、1個1個 Material なのかどうかを調べてから処理をしてました。 

改造したスクリプトでは、ユーザの選択状態から判断して、まずは処理対象になるマテリアルを全部集めてしまっています。 そして、結果として集まったマテリアルをループして、実際の処理(Group 作成)を行っています。




MaterialLibraries は、Scene オブジェクトに対して効くプロパティです。 そのシーンに属する全ての Material Library を、コレクションとして返します。

なので MaterialLibraries を使いたければまずは Scene オブジェクトを取得せねばなりません。 現在開いているシーンのことです。 が、そんなもん、ActiveProject.ActiveScene と覚えてしまえばよろしい。



MaterialLibraries を取得したら、これはコレクションですから、中身=つまり個室に入っているひとりひとりの住人=この場合は Material Library ひとつひとつについて処理を施します。 なので MaterialLibraries をループするのです。

ループして、住人の1人= Material Library ひとつに目を付けたら、Items プロパティを使います。 これまた、コレクションを返すプロパティです。 結果は、Material コレクションです。 その MatLib に所属する全部のマテリアルが、それぞれ個室に入ったアパートを返してくるわけです。 



これを、自作アパートである oTargetMaterials の個室にブチ込んでいくのが AddAddItems です。 単数のブツを放り込むときは Add で、複数を放り込むのが AddItems ですが、よくわかんなかったら AddItems を使うのが良いでしょう。 AddItems は Add を兼ねていますから。  ちなみに AddItems を使って複数のブツをコレクションに放り込んだ時でも、1つの部屋に複数のものが入ったりはしません。2号室3号室4号室にひとりずつブチ込むという行為をいっぺんにやるというだけであり、2号室に3人入るわけではないです。


こうして、結果、選んでいた MatLib や、あるいはシーン全体の MatLib からかき集められた Material オブジェクトが個室に一人ずつ入った状態のアパート = oTargetMaterials コレクションが出来上がります。

あとは、このアパートの住人= Material それぞれについて、UsedBy を使って使用中の連中を Group にブチ込んでいくだけです。その辺の処理は、最初のスクリプトと全く同じなので解説は上記を参照。



あ、あと、この改造バージョンの方では、選んでいるブツが Material かどうかを調べるのに、type を使わずに ClassID を使っていますね。 xxx.IsClassOf( siMaterialID ) の部分です。 これは、最初のスクリプトの xxx.type == "material" って書いた部分と全く同じです。 どっちでもいい。



そのマテリアルを使っているブツが無かったらグループを作らない、という処理を入れてもいいかもしれません。 上のスクリプトだと、そのマテリアルを使っているブツが無かった場合は、空っぽのグループを作ります。  まあ、これはこれで、あ、このマテリアルは不要だな、とか判断できていいような気もする。








どうでしょうかね。
雪山から戻ってきたばかりだと、イミフでしょうかね。


っていうか俺も雪山に連れてって下さいよ。
2本の板に乗って重力に引っ張られる方は、好きなんです。
経験年数(30年以上)の割には上手くないけど、まあ、そこそこできますよ。
行きましょうよ。






.

|

« 愛しの chm (;´Д`)ハァハァ | トップページ | ピックしたグループでポン。 »

コメント

素敵な記事をありがとうございます!詳しい解説まで( ;∀;)

文章見た限りでは分かった気になれそうですが、おそらくちゃんと理解はできていませんorz
眠くない時に熟読させて頂きます!!

体調不良のようですのでお気をつけ下さい!インフル達が狙ってます!


自分のブログのコメントにも書きましたが、ぜひともCG屋スキーツアー行きましょう!

投稿: shockerNY | 2012年2月 2日 (木) 04時39分

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/217974/53852000

この記事へのトラックバック一覧です: マテリアルなグループでポン。:

« 愛しの chm (;´Д`)ハァハァ | トップページ | ピックしたグループでポン。 »