« 取得 その2。 | トップページ | 群集じかけのオレンジ。 »

2010年10月17日 (日)

取得 その3。

今日も取得します。


前回シーンルートを取得したので、それに続く形で何か書けないかなーと思っていた矢先、何やら前の書き込みに質問があったので、しかたなくそれに呼応する形で取得してみましょう。

しかし、どうやら質問者の野郎は根本的に何かわかっていないようで、そして何がわかっていないのか、どこを勘違いしてるのかをこっちが理解できないくらい理解してないようなので、必ずしも質問にズバリ答える形ではありません。無理です。なので関連があると思われることを勝手に書くだけです。贅沢言うんじゃねえぞドルァ





では、ユーザが現在選択しているシーンオブジェクトの直近の子供を選択するスクリプトを書きます。

   var oSel = Selection(0);
   var oChildren = oSel.Children;
   SelectObj( oChildren );



はい、完成。 こんだけ。 以上です。

こんな状態から実行してみましょう。
Shutoku301

cone を選択してこれを実行してみると、 cone の直近の子供である cube1, cube2, cube3 が選択されます。
Shutoku301b
cube1 と cube2 にもそれぞれ子供がいますが、cone から見ると直近の子供ではないので、選択されません。 以上。完成。終わりです。


もしこれをもっと短く書こうと思ったら、

  SelectObj( Selection(0).Children );


でもいいです。 この1行だけで、上の3行と全く同じ働きをします。 でもまあそれは後の話。



3行バージョンについて解説します。

まず1行目。 現在ユーザが選んでいるものを取得する。 それが Selection です。 もう、そういうもんだと覚えちゃいましょう。

厳密には XSIApplication の Selection プロパティを使って Selection オブジェクトを取得する、書き方は Application.Selection である、とかいうことになるみたいなんですが、まあどうでもいいでしょう。今は忘れましょう。 Selection とだけ書きゃいいんです。 でももしかして Python だと Application を省略出来ないかな? どうなんでしょう。 JScript の場合は Selection とだけ書けばOKです。


で、ユーザは複数のものを選んでいるかも知れません。Selection と言った場合には1つかも知れないし、100個かも知れないわけです。なので、ユーザがいくつ選んでいようと関係なく、「最初に選んだもの」 を表すために、 Selection(0) と書きます。 Selection の中身は Collection つまり「複数あるかもしれない集合体」なわけですが、その集合体の中の何番目のものを取得するのかでカッコの中の数値を変えます。Collection のスタート番号はゼロです。1ではありません。 なので最初に選んだものは Selection(0) になり、2番目に選んだものは Selection(1) になり、10番目に選んだものは Selection(9) になります。 今回の場合、「ユーザが最初に選んだものの子供をゲットする」という仕様ですので、 Selection(0) にしています。 ちなみに、ユーザが1つしかモノを選んでいない場合はカッコを省略して Selection という言い方をすれば最初に選んだものを取得できるかというと、そうは行きません。Selection は、たとえユーザがひとつのモノしか選んでいなくても常に集合体として返すので、たとえ集合体の中に1つしか入っていないことがわかっていても、やはりカッコで番号を特定してやる必要があります。


はい、ということで oSel という変数の中にユーザが最初に選んでいるものが取得できました。 そして、取得できた cone とはどういうものなのか? を考えます。

今回取得した cone は、 X3DObject です。 SDK Explorer で確認してもわかります。 では、X3DObject とは何か? これは、「ビューポート上に目に見える実体があるオブジェクト」です。

例えば Polygon Mesh の cone。 例えば Light。 例えば Camera。 例えば Null 。例えば Curve。 例えば Point Cloud。

これらみんな、目に見える実体として存在しますよね。 実体があるということは、どの位置に存在しているのかという座標の情報、そして向いている方向や大きさの情報、つまり SRT の値を持ちますね。 なので、SRT の値を持つことができるものを X3DObject と考えても差し支えないと思います。 ちなみに SRT は Kinematics オブジェクト以下にあるんですがまあ細かい話は今はどうでもよい。 ジオメトリがあるかどうかは問いません。 例えば Null は1点の SRT を持つだけであり、レンダリングできるジオメトリを持ちませんが、でもビューポート上には厳然として実体があります。 SRT も持てます。だから X3DObject です。 カメラもライトもジオメトリを持ちませんが、実体があり SRT があるので、X3DObject です。

これに対し、例えば Group というものは実体を持ちません。 Group には SRT もありません。 だから Group は X3DObject ではないです。

同様に、Material も、Partition も、Visibility という名のプロパティも、 Geometry Approximation という名のプロパティも、Image Clip も、Action Source も、Mixer も、目に見える実体はありません。従って SRT 情報も持っていません。 結果、これらは全て X3DObject ではありません。

とまあ、X3DObject の解説になってしまいましたが、大事なのはそこではなく、X3DObject という種類のものを取得できたということです。つまり以降は X3DObject に対する操作は何でもできるようになった、ということです。ここが重要です。もうあなたは自由です。さあ身を震わせて大河を遡上して下さい。


あー、余談ですが、前回の説明で、SDK Explorer で ClassName をチェックして、X3DObject と出ているから X3DObject に対するメソッドもプロパティも全部効くぜ、という言い方をしましたが、ClassName よりもどちらかというと Supported Object Model Interfaces を見た方がいいかもしれません。
Shutoku302
ここに出ているように、cone は X3DObject であると同時に、SIOject でもあり、ProjectItem でもあり、SceneItem でもあるわけです。 なので、X3DObject だけでなく、これらに対するメソッドやプロパティも基本的には効く、と考えてもいいかと思います。たぶん。 構造をもうちっと厳密に言うと、SIObject と呼ばれる範囲のものの中に ProjectItem があり、ProjectItem の中のひとつとして SceneItem があり、そのうちのひとつが X3DObject だ、ということになると思います。階層構造です。 でもまあいいや、忘れましょう。 俺もそんなにわかっていません。大事なのは自由だということです。X3DObject どころか、SIObject や ProjectIem に使える各種の呪文も効くということです。


すっかり余談になりました。さあ大河を遡上しましょう。

X3DObject で使えるプロパティのひとつ、Children を使います。 まずX3DObject のヘルプページを見ましょう。 Children プロパティがありますね。 

ではそこをクリックして飛びます。すると、
Shutoku303
Children のページには、「このオブジェクトの子である、すべてのX3DObjectを含むX3DObjectCollectionを戻します。再帰的検索は行われません。言い換えれば、直接の子のみ戻され、子の子は戻されません。」 とあります。 これを読むと、直近の子供が X3DObjectCollection として返されるということがわかります。 イエイ。子供が取得できそうだ。

でも X3DObjectCollection とはなんだ? X3DObjectCollection の文字の部分がリンクになっているのでクリックして飛びます。 すると、
Shutoku304
X3DObjectCollection のページには、「X3DObjectオブジェクトのコレクションです。このコレクションは0から開始されます」とあります。 そしてまた、X3DObject の文字がリンクになっているので飛びます。 すると元の X3DObject のページに戻ります。戻っちゃった。戻っちゃったよ?

・・・・もともとは X3DObject の Children から始めて、最終的に取得できたものは再び X3DObject。 戻っちまった。 いいの? いいんです。

子供を集合体として取得して(X3DObjectCollection)、集合体の中からひとつを取得すると、それはまた X3DObject になるってことは、取得できた子供に対してまたもや Children とかその他のプロパティ、メソッドを使えるということです。 ここでまた自由になります。 取得した子供に対してもさらに、 X3DObject に有効な全ての自由を享受できるということです。 イエイ。


そして上記のヘルプページのリンクのたどり方が、SDK ガイド(ヘルプ)の使い方そのものです。 これを芋づると呼んでいます。

X3DObject から始めて、Children に行き、またもや X3DObject に戻ってきたり、戻ってきた後に今度は Children 以外のプロパティにアクセスしたりして別のものを取得する。 この取得の連鎖芋づるです。 スクリプティングは、芋づるです。


で、Childrenプロパティで取得できた芋たち= cone の子供は、oChildren という変数に格納されます。 さっき見たように Children プロパティは X3DObject を Collection として返すのだから、oChildren の中身は複数の芋です。 そして最後の行、SelectObj コマンドでその複数の芋を選択して終わりです。 イエイ。 できました。 終了。



とりあえずできちゃったのでここで解説を止めてもいいんですが、上でSDKガイドの芋づるを例示するために X3DObjectCollection の話を出しちゃったのでこれをネタにして、取得しているものは何なのかを常に把握していることが大事だという話をちょっと追記します。

上で、「子供を取得した。取得した子供は再び X3DObject なので、また X3DObject に対するメソッドやプロパティが使える」 という話をしました。 これを例にとって、よくやる間違いをやってみます。 こんな風に書いてみます。

   var oSel = Selection(0);    //    最初に選んでいるものを取得
   var oNull = oSel.AddNull( "hoge" ); //    oSel に Null をゲット

   var oChildren = oSel.Children;    // oSel の子供たちを取得
   var oNullNull = oChildren.AddNull( "hage" );    //    子供たちに Null をゲット(エラー出る)



各行にコメントした通りですが、まず1行目で「ユーザが最初に選んだもの」を取得します。oSel に格納されるのは X3DObject でした。 なので2行目で、X3DObject に使えるメソッドである AddNull メソッドを使って、1個 Null を出してやります。名前は hoge です。
次に3行目、oSel の子供たちを取得します。 結果は oChildren に入りました。 さあ、今度は、その子供たちに対して Null を出してやりましょう。名前は hage です。

実行すると、
Shutoku320
エラーで止まってしまいます。
よく見ると、最初の Null はちゃんと出ています。 Explorer を見ると、cone の子供に hoge ができているのがわかります。
しかし2回目の Null は出ていません。その前にエラーで止まったからです。ではなぜエラーで止まってしまうのでしょう?

答えは、「 Add Null メソッドは X3DObect には効く。 oSel の中身は X3DObject だったから、ちゃんと効いた。 しかし、oChildren は X3DObject ではない。 X3DObect ではないものに対して、AddNull メソッドは効かない」 ということになります。

1行目の oSel に入ったものは、Selection(0) と指定しているので、「最初に選んだ一人」と言っています。つまり特定の一人のことを表します。そしてその一人は Polygon Mesh の cone だったので、こいつは X3DObject なわけです。  それに対し3行目の oChildren に入ったものは「子供たち」なので、一人かも知れないし、100人かも知れません。なのでたとえ一人だろうが1000人だろうが、常に Collection として返します。上の例の場合はX3DObjectCollection でしたよね。これは X3DObject の集合体であり、X3DObject そのものではありません。 X3DObjectCollection に所属するひとりひとりは X3DObject ですが、Collection 自体は集合体を入れるためのただの器であり、所属している個々のメンバーに対する操作を引き受けてくれるわけではないのです。

それを見るために、上記のスクリプトに追記してみます。


   var oSel = Selection(0);    //    最初に選んでいるものを取得
   Logmessage( "oSel は " + ClassName( oSel ) + " だぜ"); 
   var oNull = oSel.AddNull( "hoge" ); //    oSel に Null をゲット
   
   var oChildren = oSel.Children;    // oSel の子供たちを取得
   Logmessage( "oChildren は " + ClassName( oChildren ) + " だぜ");
   var oNullNull = oChildren.AddNull( "hage" );    //    子供たちに Null をゲット(エラー出る)



赤字が追加した部分です。 Logmessage を使って、取得したモノの ClassName を表示させています。 

結果は、
Shutoku305
こうです。 ログされたところを見てください。 「 oSel は X3DObject だぜ 」 「 oChildren は XSI)bjectCollection だぜ 」 と言っています。 こうして、oChildren に格納されたものは X3DObject ではなく、X3DObjectCollection だということがわかります。 前述のX3DObjectCollection のヘルプページ画像を見てみましょう。 AddNull メソッドなんてどこにも載っていません。 X3DObjectCollection には AddNull メソッドが効かないからです。

ということで、取得したものが Collection だった場合、、そこに所属するひとりひとりに対して何かをしたいのであれば Collection の中身をひとつひとつ取り出して何かをやるという書き方をせねばなりません。ま、ただのループ処理なので簡単です。これについてはまたそのうち書きます。 今回はループの書き方を説明したいんじゃなくて、「取得できたものが○○ならコレコレができる、逆にアレソレはできない」 という話をしたいのです俺は。


このように、oSel に取得できたものは X3DObject だぜ、 oChildren に取得できたのは X3DObjectCollection だぜ、という風に、「何を取得できたのか」をちゃんと把握さえできていれば、その後の処理がすんげー楽です。エラーが出た時に、「 あ、俺は○○をしたいんだから××を取得しなければいけなかったのに、△△を取得しちまってたんだ。そりゃ動くわけねーよな 」 とすぐにわかるからです。 あるいは××を取得すればいいとすぐにはわからなかったとしても、少なくとも取得したモノの種類が違うんではないかと疑うことができます。 これは問題解決への近道です。

よくあるんですよね。 ちゃんと書いてるのに、文法的には何も間違ってないのに、なんで動かないんだ? バグか? とかね。 間違ったものを取得してるくせに、そこに気づかず、ソフトウェアのせいにするんです。 俺も毎日これです。 ま、 XSI 様の場合はそれももっともなんですが。 
また、オブジェクトとして取得したと思い込んでいて、実はただの文字列だけを取得していたということもよくあります。 これについてもまた後日書きますたぶん。

ともかくですね、エラーで止まってしまった時は、文法などをチェックするのと同時に、「俺は正しいものを取得できているのか? コレをしたいんなら、アレを取得するべきなのに、もしかしてナニを取得しちまっているんじゃないのか?」 と疑うことを激しくおすすめします。


上手く言えたかどうかはわからないけど、もともと「取得」云々と言い出したのは、要するにこれを言いたかったのですよ。 正しく取得できていれば正しく動く。 正しく動かないときは正しく取得できていなかったのではないかと疑え。 これです。 ここさえおさえていれば、スクリプティングなんてチョロいもんです。ウソです。チョロくありません。俺は表層しかわかっていません。すいjません。




もうひとつ、本題からは外れますが、今回の例では最後に SelectObj コマンドを使っています。 オブジェクトモデルで書くんじゃなかったのかよゴルァ と怒られそうですが、SelectObj のような単純なものは、むしろコマンドで書くべきではないのか、と思っています。 なんとなくですが。 オブジェクトモデルで書くと長くなるんだもん。解説する上でも本題とは関係のないところで煩雑な話をしなければいけなくなるし。 ということで SelectObj はコマンドです。コマンドで行きましょう。



とまあ、またしくみの説明をいっぱいしてしまった気がする。
もうちっとカンニングのサンプルを書かないとなあ。
しくみの前にカンニングだよやっぱり。
カンニング繰り返しているうちにしくみなんて勝手にわかってくるからなあ。

前にも書いたように、俺はしくみをわかっているからスクリプトが書けたわけではありません。 カンニングしながらわけわからんまま書いているうちに、結果からしくみが想像できてきて、その時点でマニュアル読んだらどうやらその解釈は正しいらしいということがわかってきた、という感じです。 スクリプティングなんてそんなもんです。 たぶん。



酔っているのにずいぶん書いたなあ。疲れた。
たぶん続く。 たぶん。




.

|

« 取得 その2。 | トップページ | 群集じかけのオレンジ。 »

コメント

hello!This was a really fabulous post!
I come from milan, I was fortunate to approach your theme in wordpress
Also I learn a lot in your blog really thanks very much i will come daily

投稿: bet365 italia | 2010年10月18日 (月) 18時57分

いつも拝見させていただいております。
おかげで、ずっと謎だったスクリプトのマニュアルの意味がなんとなく分かり始めてきました。
しかし、どうしても分からないことがあるので質問させてください。
オブジェクトの取得は出来るようになったのですが、Texture_Projectionの取得が出来ません。
複数オブジェクトのTexture_Projection名を一括して変更するスクリプトを作りたいのですが…
どうかお力をお貸し下さい。
よろしくお願いいたします。


投稿: ポチ男 | 2010年11月14日 (日) 12時21分

ポチ男さんこんにちは。
Texture_Projection ですか。 では、そのうち本記事にしましょうかね。

取り急ぎヒントというか答えというか、簡単に。

UV を持つ(Texture_Projectionを持つ)オブジェクトを Explorer で開いてみてください。オブジェクトの中の、Clusters の中に、Texture_Coordinates_AUTO などという名前のクラスタがあり、その子供として Texture_Projection がありますよね。こういう階層構造で UV を保持しているのだと理解するのが、はじめの一歩です。

あとは Texture_Coordinates_AUTO や Texture_Projection などを、SDK Explorer で開いてみて、Classname や Type を調べます。Texture_Coordinates_AUTO は sample という type のクラスタであり、UV(Texture Projection) はそのクラスタの子供として存在する uvspace という type のプロパティである、という情報が SDK Explorer から得られます。

ここまでくればこっちのもん。

まずは選択中のオブジェクトを取得し、ループして1つ取り出し、その中のクラスタを全部取得し、そのクラスタの中から Sample というタイプのクラスタだけ抽出し(これが Texture_Coordinates_AUTO とかいう名前が付くクラスタ)、その中からプロパティを全部取得し、そのプロパティの中から uvspace というタイプのものだけ取り出すと、それが Texture_Projection だということになります。

UV を持ったオブジェクトを選択し(複数可)、以下を走らせてみて下さい。
for ( var i=0; i {
var oObj = Selection(i);
var oSampleClusters = oObj.ActivePrimitive.Geometry.Clusters.Filter( "sample" );
for ( var j=0; j {
var oSampleCluster = oSampleClusters(j);
logmessage( "Sample Cluster = " + oSampleCluster );

var oTextureProjections = oSampleCluster.Properties.Filter( "uvspace" );
for ( var k=0; k {
var oTextureProjection = oTextureProjections(k);
Logmessage( " TextureProjection = " + oTextureProjection );
}
}
}
UV(Texture_Projection) がログされますよね? 取得できているということです。このスクリプトではログしただけですが、oTextureProjection の中に取得できているので、こいつをどうしようと後は自由です。

ちなみにこのスクリプトはエラーチェックとか全くしてないので、変なもの選んで実行させるとエラーで動かないはずです。でもそのエラーチェックはまた別の話なのでここではスルーしてます。

詳しくはそのうち本記事で。
とか言って書かないかも。
わかりません。

投稿: junki | 2010年11月14日 (日) 18時09分

ありゃ、スクリプトのコードの文字がダメっすね。コメント欄には書けないのかしら。

ってことで、上記のスクリプトは以下からダウンロードして下さい。

ダウンロード GetTextureProjection.js (0.6K)

投稿: junki | 2010年11月14日 (日) 18時13分

junkiさん、ありがとうございます!
ずっと分からなかった記述がようやく分かりました。
何回も何回もマニュアル見たのですが、clustersで調べても、そこからFilterってのにたどり着けませんでした。
その次もどうやってPropertiesという記述にたどり着けるのか、未だに分かりません。多分教えていただけなければ、SDK ExplorerのClusterPropertyの検索して、GetClassIDってのが似てるなぁ、とか思ってまたエラー吐きまくるスクリプトを作って悩んでいたことでしょう。
まだまだ自分にはマニュアルで調べていく手順が分かってないようです…
今後この辺りの僕みたいな馬鹿な思考回路でも、ちゃんと調べられる手順みたいなスクリプト記事を書いていただければ、非常に助かりますm(. ̄  ̄.)m

投稿: ポチ男 | 2010年11月15日 (月) 01時30分

Filter は Collection にかますものであり、Cluster など個々のオブジェクトにかますものではありません。集合体(Collection)にフィルタかけて特定のタイプのものだけ残す、ということなのですが。 

今回の場合、ActivePrimitive.Geometry.Clusters によって ClusterCollection を取得し(これが Cluster ではなく ClusterCollection であることが重要)、それに "sample" でフィルタかけてます。 次に Properties を使って PropertyCollection を取得し( Property ではなく PropertyCollection であることが重要)、それに "uvspace" でフィルタかけてます。 

ポチ男さんが Filter にたどり着けなかったのは、おそらく Cluster のメソッドで探したからではないでしょうか。 ClusterCollection のメソッドを探さないといけないのです。 ごっちゃになった集合体から個々の要素に分解していくための途中の濾過の方法として Filter があるわけですが、Cluster オブジェクトなどという既に個々になってしまっているものに対してはもはや Filter する意味は無い、と考えてもいいかもしれません。

しかしフィルタは必須というわけではなく、楽なので使っただけで、ClusterCollection を1個1個ループしてタイプを調べ、"sample" のものだけ処理する、という書き方にしても結果は全く同じです。

Cluster にぶら下がる ClusterProperty の取得方法としては、マニュアルに SceneItem.LocalProperties を使えと書いてあります。なので Cluster.LocalProperties で ClusterPropertyCollection を取得できます。 でも上のサンプルスクリプトの場合、LocalProperties じゃなくて Properties を使っちゃってますね。失礼。でも結果は同じなんです。

Texture_Projection は Explorer 上で見ると白黒のグラデーションアイコンですよね。このアイコンのものは、全て Property です。だから、Texture_Projection を取得しようと思ったら、何かの Property を取得すればいいんだな、と想像することが重要です。Property は独立した存在ではなく、必ず何かにぶら下がるものです。だから xxx.Property という形になります。 そして xxx が持つプロパティは1つとは限らないから、PropertyCollection という形で取得し、その後個々に分解していくというプロセスになります。結果、PropertyCollection を取得するためには、xxx.Properties と書けばいいことになります。

Texture_Projection は白黒アイコンだぞ → じゃあ Property なんだな → であれば、xxx.Properties でプロパティコレクションとして取得できるな → コレクションなら、Filter で特定のタイプだけ取り出せるんじゃないの

こんな思考過程をたどると、答えが見つかりやすいかと思います。

たぶん。

投稿: junki | 2010年11月16日 (火) 02時05分

あ、ありがとうございます!!
凄くわかりやすいご説明で、SDK Explorerの内容とマニュアルの記述が徐々にリンクしてきて、何か僕にも出来そうな気がしてきました。
最後の5行は本当にわかりやすい!junkiさん、ほんと上手いですよね説明が。
感謝感謝です。

投稿: ポチ男 | 2010年11月16日 (火) 15時13分

お役に立ちましたか。
ちなみに俺はクラシックラガーが好きなんです。
けけけけけけけけ。

投稿: junki | 2010年11月17日 (水) 01時21分

junkiさんはクラシックラガーなんですか。
僕は一番絞りです!
一番でなきゃ駄目なんです!!
フフフ。

投稿: ポチ男 | 2010年11月17日 (水) 12時46分

コメントを書く



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




トラックバック


この記事へのトラックバック一覧です: 取得 その3。:

« 取得 その2。 | トップページ | 群集じかけのオレンジ。 »