« クラスタ名はグループ名からポン。 | トップページ | ICE の PC にラティスでポン。 »

2012年3月21日 (水)

親だけ残ってくれ。

複数のオブジェクトを選択している時、その中で、最も親になるオブジェクトだけに何か処理を施したいということがありましてね。



 A - B - C


という親子関係があったとして、A が一番親なんですが、 この3つを選択していたとしたら、一番親である A だけが残って欲しい。

B と C の2つを選択していた場合、その中で一番親になるのは B ですから、B だけが残って欲しい。

A と C の2つを選択していた場合、同じ理由で A だけ残って欲しい。

B のみを選択していたら当然 B が残って欲しいし、C のみなら C が残って欲しい



これを、上の例の A-B-C のような1つの階層だけでなく、任意の数の階層でやりたい。 つまり、シーンの中で任意に選択している複数のオブジェクトのうち、同じ階層にいる場合は親だけが代表で残って、最終的に親だけの集団が欲しいのです。


ということをやるスクリプトをババっとやってみたらこうなったんですが、どうでしょうか。

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

//    選択中のブツを、oSelectedObjects に退避
var oSelectedObjects = XSIFactory.CreateObject( "XSI.Collection" );
oSelectedObjects.items = Selection;
OriginalCount = oSelectedObjects.count;

//    ガキどもを入れる箱
var oChildren = XSIFactory.CreateObject( "XSI.Collection" );

//    選択中のブツのガキどもを全部ひっかき集める
for ( var i=0; i<oSelectedObjects.count; i++ )
{
 
//    FildChildren = ガキどもをコレクションとして取得
    oChildren.AddItems( oSelectedObjects(i).FindChildren() );   
}


//    ##### ここまでで準備完了




//    今度は、FindChildren で引っかき集められたガキどもの方をループし、選択していたブツ(oSelectedObjects)全部と一致するかどうかを、総当りでチェック

for ( var i=0; i<oChildren.count; i++ )
{
    for ( var j=0; j<oSelectedObjects.count; j++ )
    {

 //    ↓ ガキが親と一致した = FindChildren によって取得できたガキは、実は最初に選ばれていたブツのひとつだった
        if ( oChildren(i).fullname == oSelectedObjects(j).fullname )
        {
            oSelectedObjects.Remove( oChildren(i) );   
//    ならば、 oSelectedObjects から追放
        }
    }
}
FinalCount = oSelectedObjects.count;

//    ##### 結果
Logmessage( "最初に選んでいたノード数 = " + OriginalCount );
Logmessage( "最終的に残ったノード数 = " + FinalCount );
for ( var i=0; i<FinalCount; i++ )
{
    Logmessage( "   残ったやつ -- " + oSelectedObjects(i) );
}

SelectObj( oSelectedObjects );

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



なんかこう、もっとスマートに、簡単にできないものでしょうか。
最も泥臭くやっている気がします。 総当りなので効率悪そうな。
まあ、これでちゃんと機能はしているように見えるのでいいのですが、
もっといい方法があれば、是非教えて欲しいのです。
お願いします。










こんなの書いている場合じゃないような。

こんなの書かないと手作業でやってられないような。

まったくもっていつも通りの状況です。



差し替えとかって、面倒ですね。
全てが理想通りに進めば、差し替えって発生しないんですよね。
最初から完成版モデルで、完成版マテリアルで、完成版のモーションを作り、そのままレンダする。
リニアですよ。
リニアワークフロー。
色の話じゃありませんこの場合。
一直線に、後戻りせず、順番に、進めるってことです。
昔は割とそうだったよね。

でも今どきそんな上手く行かない。
っていうか全然上手く行かず、ひどい状況になることの方が多い。
仮のモデルでモーション作業とか。
マテリアルは後で決まるとか。
このパーツだけ後でこうなるから、先にモーションはやっといて、あとで移植とか。


まあ、日常的ですよね。こっちの方が普通ですよね。
複数の作業を同時に進めている、とかいうキレイ事ではなく、
体制やスケジュールの状況が悪くてこうなることが実に多いというか、ほぼ100%。
もちろん自分の手が遅いためにそうなって行くのも、ほぼ100%。


XSI はそんなひどいCG業界の状況を念頭に置いたソフトウェアなので、非破壊だとか何だとか言って、後戻りしたりしやすいように出来ているように思えます。
つまり、ダミー作業、差し替え作業が多発するような、体制やスケジュールの状況が悪い仕事ほど、本領を発揮するソフトウェアなのかも知れません。

いいんだか悪いんだか。



で、差し替える段階になって、もうこういう風にシーンを整理しちゃったから、もう一度同じ整理するのは嫌だ、とか。

ここはモーション都合でアップデートしちゃったけど、マテリアルが最新になったモデルが来たら、そちらは当然モーション都合のアップデートはされてない。  さあ、どっちをどっちに移植する方が工数が少ない? とか。

Pass 分けもう一回やり直せっていうの? とか。



こうして、しかたなく、スクリプトを書き始めるという感じですね。 まさに。


より綺麗に表現するためにポリゴンが多くなり手作業でやってられないとか、ディテールアップしてリッチな絵にするために部品点数が多くなり手作業でやってられなくなってスクリプト書くとかなら、まあ前向きなんですがね。でもそんな場合は、少ないですよね。

ものごとが、予定通りに、スケジュール通りに進めば、きっと多くのスクリプトは不要になるだろうなあ。 スクリプトを書く頻度の高さは、状況の悪さに比例しています。







まあそんなことはどうでもいいや。

親だけ残す。

なんかいい方法ありますかね。





.

|

« クラスタ名はグループ名からポン。 | トップページ | ICE の PC にラティスでポン。 »

コメント

こんにちは、自分はFindParentsみたいな親取得ファンクションを作って、違うアプローチを試してみたんですけど、結構ややこしくなってきたので途中でやめました。潤樹さんのスクリプトはそのままで良いじゃないですか。

僕にアドバイスが出来るのは1つだけです。

oSelectedObjects.Unique = true;
oChildren.Unique = true;

を入れた方が速度があがります。

投稿: myara | 2012年3月21日 (水) 19時40分

なんか忘れていると思っていたんだ。
そう。ゆにーくですね。
俺も、この手のやつは基本は入れているんだけど、今回忘れたというか、気にしてなかった。

速度上がるっていうと、どれくらい上がるんだろう。まあ、小さいシーンならミリセカンドも変わるかどうかだろうけど、でかいシーンになると、ねえ。

でも、oSelectedObjects の方は、Unique フラグの有無が関係あるんだろうか。 こいつの中身がダブっているかどうかが問題になる部分が、上のスクリプトには無いような気もするんだよね。

なぜならば、oSelectedObjects にアイテムが追加されるのは、Selection を退避させた時の1回のみで、しかも Selection だからダブっている可能性はゼロのはず。 なので、その後 oSelectedObjects をループさせても、同じオブジェクトを2回評価することはないはずで、そうなると Unique 入れて強制的にダブりを排除したのと同じ状態に、既に最初からなってるんじゃないの? なら Unique 入れても速度変わらないんじゃないの? という気がするんだけど、まあ、これは頭で考えただけであって、やってみたらどうなんでしょう。やってみますそのうち。

ありがとう網ー誤

投稿: 潤樹 | 2012年3月21日 (水) 20時14分

お久しぶりです。
こんばんは。

頭の体操に良いと思って、別アプローチを考えてみました。
Junkiさんのは子供を比較するものだったので、逆に親を辿って調べるようにしてみました。
連想配列やら自作オブジェクトやら使ってみました。
同じようにログ出力や検出結果を最後に選択するようにしてあります。

//////////////////////////////////////////////////////////////////////
var ListArray = new Array();//集計用連想配列
var oSelectedObjects = Selection;//選択オブジェクト

for ( var i=0; i

var oChkObj = oSelectedObjects(i); //チェックを回すためのもの
var count = 0; //オブジェクトの階層カウント
var FirstObj = 0; //階層のトップノード

//Scene_Rootに達するまで調べる
while(oChkObj.name != "Scene_Root"){
count++;
FirstObj = oChkObj;
oChkObj = oChkObj.Parent;
}

//オブジェクトの情報を自作オブジェクトに入れ込む
var ObjData = { "count": count, "name": Array(oSelectedObjects(i)) }

//連想配列名に.は使えないので変換しとく
var ArrayName = FirstObj.fullname.replace(/\./g, "-----");

//保持しているデータと比較
if(ListArray[ArrayName] == null){
//連想配列にまだ同じ親が登録されていない場合は新規追加
ListArray[ArrayName] = ObjData;
}else{
if(ListArray[ArrayName].count > count){
//今回のオブジェクトの方が親に近かった場合は情報の上書き
ListArray[ArrayName] = ObjData;
}else if(ListArray[ArrayName].count == count){
//同じ階層のものが重複していた場合は情報を追加
ListArray[ArrayName].name.push(oSelectedObjects(i));
}
}

}

//調査結果
var FinalCount = 0;
var FinalObjects = new Array()
for(i in ListArray){
for ( var j=0; j < ListArray[i].name.length; j++ ){
logmessage(" 残ったやつ -- " + ListArray[i].name[j]);
FinalCount++;
FinalObjects.push(ListArray[i].name[j])
}
}
Logmessage( "最初に選んでいたノード数 = " + oSelectedObjects.count );
Logmessage( "最終的に残ったノード数 = " + FinalCount );

SelectObj( FinalObjects );
//////////////////////////////////////////////////////////////////////

速度的にjunkiさんのと比較して、
子供の量が膨大になった際はちょっとだけ早いかもしれませんし、
逆に階層深くの物ばかりを選択していたら遅くなるかもしれません。
実際のところは検証してないのでなんともいえません、スイマセン。

※スクリプトはタブで整列させてるんですが、コメントでは見づらくなってしまうようで、申し訳ないです。

投稿: モチオ | 2012年3月23日 (金) 03時47分

スクリプト内の4行目がなぜか切れてますね…。

for ( var i=0; i

↓↓↓↓

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

が正しい記述です。
何度もすいません。

投稿: モチオ | 2012年3月23日 (金) 03時53分

モチオさん御無沙汰ですね。すいません放置してて。今ちょっとアレなんですが余裕ができたら検証してみます。連想配列ってなんですかそれ。食えるんですか。

投稿: 潤樹 | 2012年3月26日 (月) 21時29分

コメントを書く



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




トラックバック


この記事へのトラックバック一覧です: 親だけ残ってくれ。:

« クラスタ名はグループ名からポン。 | トップページ | ICE の PC にラティスでポン。 »