カテゴリー「XSI ICE」の62件の記事

2014年6月23日 (月)

ICETreeビューの取得。

書きかけで保存したまま放置されている記事もけっこうあるんですよね。 


さっきサッと見てみたらこんなものが出てきた。 2012年8月とからしい。 ICETree ビューを取得するスクリプトですね。 ドックされたもの、フローティングのもの、両方取得できるようです。 選択中のオブジェクトからたどるとかではなく、現在開いている ICETreeビューからたどるというアプローチをしようとしたのでしょう。  2年も前なので忘れちゃったけど。



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

var oViews = Desktop.ActiveLayout.Views;

// ドックICETreeビューを捜索
var oICETreeViews = oViews.Filter( "View Manager" )(0).Views.Filter( "ICE Tree" );

// なければ浮遊ICETreeビューを捜索
if ( oICETreeViews.Count == 0 ) oICETreeViews = oViews.Filter( "ICE Tree" );

Logmessage( "見つかった ICETree ビューの数 : " + oICETreeViews.count );

// 見つかったビューのうち、最初のビューから、container アトリビュートをゲット=これが ICETree オブジェクト
var oICETree = oICETreeViews(0).GetAttributeValue( "container" );

// 対象になる ICETree が特定できたので、あとは何をしようが自由
var oICENode = AddICENode("$XSI_DSPRESETS\\ICENodes\\GetDataNode.Preset", oICETree );

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


あ、これだとドックされたものが無ければフローティングを探すという風になってるのか・・・・・まあいいや。




今さら役に立つことも、まあ、なかろうて 。・゚・(ノД`)・゚・。

| | コメント (0) | トラックバック (0)

2013年10月26日 (土)

頂点N個おきに発生。

ポリゴンの頂点上にパーティクルを発生、ってのはよくやるわけですが、頂点全部に発生させたいわけじゃなくて、N個おきに発生させたかったりするわけですよ。


で、相変わらず ICE たんに愛されていない俺には、当てずっぽうで Modulo とかいじくって、さっぱり思った通りにならず、おとなりさんの家の庭に俺のモニタが堆積して行くわけです。数十万年後に EIZO 遺跡として発掘されることでしょう。


で、ひとりではどーにもならなくて教えを乞うと、親切に俺に知恵を授けてくれる賢者様たちがいるわけです。 俺は幸せ者です。 その幸せをおすそ分けします。


Addpointoneverynthvertex

クリックするとでかい画像が出ます。


うん、これで良い。スヴァらしい。




冗長だけどロジックをコトバで説明すると以下のようになると思います。



発生源としてポリゴングリッドがあります。

そのグリッドの PointPositon つまり頂点位置を Add Point に食わせてやって、頂点を発生させます。

しかしこのままでは全部の頂点に発生しやがります。 任意の個数おきに発生させたいのです。

そこでまず、グリッドの頂点番号を取得します。 VertexIndex です。

そいつを Modulo に食わせ、2個おき にするなら  を食わせます。 Modulo は、頂点番号それぞれを2で割ってその余りを吐き出します。

余りがゼロの時は、2で割り切れている時ということになります。 ってことは、頂点番号が2の倍数の時に割り切れることになります。

その結果を Filter に食わせます。 Filter は条件が一致した時のみ Keep します。 この場合、頂点番号が2で割り切れた時のみ(2の倍数の時のみ)、Keep つまり保持して次のノードに渡すわけです。

こうして2個おきにキープされた頂点番号の頂点位置に Add Point でパーティクルが出現します。

3個おきにしたかったら、Modulo に 3 を食わせます。 3の倍数の時のみ Keep され、パーティクルが出現します。

めでたいです。

男が白い歯を輝かせて笑います。




説明、これで合ってますか? 間違ってたら指摘して下さいね。




このシーンファイルのダウンロード JJJ_ICE_AddPointOnEveryNthPoints.zip (XSI 2012)






m4g さん、msk さん、いつもありがとう。 あなた達のおかげで仕事ができてます。





.

| | コメント (0) | トラックバック (0)

2013年6月 6日 (木)

N個おきに。

ひっさしぶりに ICE をいじってるのですが、相変わらず低レベルですよ、でもメモしとかないと忘れるじゃないですか。 ええ、すっかり忘れてましたよ。



ともかくですね、パーティクルのN個おきにどうこうする、ってのをやりたかったんですよ。 

色々方法はあるんでしょうがね、Modulo とかいうやつを使うのが分かりやすいかな、と今のところ思ってまして、そのメモです。

Everynth

クリックするとでかい画像が出ます。


普通にパーティクルを発生させているわけですが、パーティクルってのは生まれるたびにひとりずつ ID というアトリビュートが割り振られるんですね。出席番号みたいなやつですね。 Get Datathis.ID とやれば、取得できます。


で、N個おきになんかしたいのであれば、この ID の値を N で割って、余りがゼロであれば割り切れているということなので、つまり N の倍数であるということになるじゃないですか。  N の倍数であるということは、N 個おきの数値ということになりますよね。 ね? そうですよね? 合ってると言ってくれ。




ということで、ID を取得し、Modulo に突っ込んで、N の数値で割った余りを吐き出し(Modulo は割った余りを吐き出すノードです)、 If を使ってゼロとイコールかどうかを判断し、イコールなら N 個おきの ID にヒットしたということで、何かをセットするというツリーにしてみたつもりです。

N には 7 が入っているので7個おきです。 ヒットしたらパーティクルの色をに、ヒットしてなかったらにしています。 ビューポートの表示を見ると、7 の倍数のやつだけがになっているのがわかると思います。





・・・・・ってことでこれ、合ってますか? 合ってますよね? 合っていると言ってくれ。


上記サンプルシーンのダウンロード(2013)
JJJ_EveryNthParticle_XSI2013.zip



ひとつの PointCloud の中で色々な何かを混ぜたいとか、そういう時に使えそうですよね。 今回はパーティクルの ID に対してヒットかどうかの判断をしているので 「パーティクルN個おきに何かする」 ってことになりますが、例えば現在フレームに対してヒットかどうかの判断をすれば 「Nフレームおきに何かする」 ということもできると思います。




とかなんとか。 こんなのでも俺にとっちゃ大事な tips みたいなもんですよ。メモメモ。 将来のためにカンニングペーパーを作っているような気分ですね。 だって未だに何かするとき、自分のブログ検索しちゃうもんね。 すっかり忘れてるからね。 ええとこれ、やったことあったっけ? と検索すると自分のページが出て来ちゃって、でもさっぱり記憶にないのでつぶさにコピーして、わあできたできた昔の俺ありがとう、みたいな。 いつものパターンですよ。ええ。



しばらく ICE したいなあ。 でもまた中断期間が長くなるのは目に見えてます。 なんて効率の悪いアレなんでしょう。







.

| | コメント (0) | トラックバック (0)

2013年1月14日 (月)

Push on Torus タイムアタック。

Push on Torus のタイムアタックおよび冗長なツリー説明です。


どうしてもやってみたくなったという、そんだけであります。
全然大したアレではないです。ネタです。
ああ気が済んだ。
やっぱりトーラスはちゃんとやっておかないとね。



こちらが嘔吐デスク公式の Push on トーラスです↓
http://download.autodesk.com/largefiles/jp/softimage/training_video/ice/mypush/mypush_01.html


バージョン7のラウンチイベントのデモの様子は、ビデオに残されてないのかなあ。日本のユーザに初めて公式に披露された未知なる新機能ICE。旧姓 Moondust。プロシージャルそしてグラフィカルにオペレータを構築できる、恐るべきパワーを秘めた ICE の魅力を余すところなく伝えた伝説のあのデモ。 もういちど見たいなあ。





.

| | コメント (0) | トラックバック (0)

2013年1月 9日 (水)

こともあろうに Push on Torus をメモる。

いや、あの・・・。
すいません・・・。


ICE を本格的に使う仕事が連続しなくてですね。 いや、俺が ICE を全く使いこなせていないがために仕事のたびに活用する道を見つけられないでいると言いますか、納期を鑑みると ICE でトライしている時間がないと毎回判断してしまい、ICE を使わずにトラディショナルでレガシィな方法でやっつけてしまってばかりでしてね。



なので ICE のこと、せっかくいじったのに忘れてしまってばかりで、もったいないんです。毎回こんなこと言ってるなあ。 ともかく、忘れるのもったいないので、ちょっとしたことでもなるべくメモしようと常に思ってはいるんですけどね。


今も(俺のスキルでは) ICE を活用しにくい仕事をしてるんですけど、今日、なにげなく


 俺、あの Push on Torus がパパっとできるだろうか・・・?


と想像してみたら、できないかも(( ;゚Д゚)) と思ってgkbrしてしまいまして・・・。

で、やってみたら、できました。迷わなかった。良かった。ほんとにホッとしましたよ。





将来のためにメモしておきます。
こんな基本的なことでも、きっと、半年後くらいにはまたパパっとできなくなっていて、俺なんでこんなこともできねえんだよ ( ゚皿゚)キーッ と泣いたりわめいたり大騒ぎするのが目に見えてますから。





元の形状の各頂点の座標を、ある方向にオフセットさせる。

ある方向とは、法線方向。

元の頂点座標に、法線ベクタを足し算してやるだけ。

どんだけオフセットさせるかは、法線方向に数字を掛けることによって、強弱付けられるようにする。

Longlivepushdeformerontorus


ふう・・・。
こんなんでいいですよね・・・?


それにしても、この太っちょになったトーラスを見るとほんと安心しますよね。 なんつうか、Feel like home というか、俺の棲む水に帰って来た感じとでもいうか。




1ヶ月に1回くらい、この Push on Torus のタイムアタックをやろうと思います。新規シーンからいかに迷わず手早くこのツリーを構築できるか。 ボケ防止にもってこいじゃないですか。 ICE にはそういう機能もありますよね。


ツリーを組みながら、ブツブツとその解説をしゃべりながらやるのが良いようです。解説ビデオを作っているつもりでというか、自分自身に説明してるというか。 あるノードをつなぐときに、暗記だけでつなぐのではなく、その理由というかロジックの解説を自分に強要することによって理解を深めようというアレです。

まあ、丸暗記でやった方がいいこともいっぱいありますけどねー。 理由を考えてるから進まないんだよな俺は・・・・orz




毎度のことながら基礎的過ぎる ICE 話ですんません。
もうちょっと複雑なやつというか、おおーこりゃいいやー って思えるやつ組めるようになりたいですねえ

.

| | コメント (0) | トラックバック (0)

2012年7月 5日 (木)

クラスタから発射。

また ICE のメモ的なアレなんですがね。


オブジェクトをパーティクルのエミッタとした場合、オブジェクト全体ではなく、クラスタから発射させたい場合はどうしたらいいんだろう?  などという、ごく基本的なことを知らないことに気付きましてね、今日もいつものように唖然としたわけです。



で、ちょっと調べてみたら、その昔は、発射してから消すという方式もあったようです。 ICE ではいつも死ぬほどお世話になっている m4g さんのブログにも、昔の記事でこんなのがありました。 2008年ですって。 そんな昔から ICE ってあったんだね。ヤヴァいよ俺 orz





その後、SI-Support Blog にこんな記事があって、これが一番良さそうに見えました。

ただし、コンパウンドの中身に潜っていかなければならないんですね。 潜りさえすれば、そこに必要なパラメータがあってクラスタでフィルタリングできるのですが、じゃあなんでこのパラメータを表に出さないのか(Exposeしないのか)、謎だと思いました。




とか思いながら、何気なくいつもの Emit From Geometry コンパウンドの PPG を見てみると・・・・ 

あれ? 表に出ているじゃないか。 ちゃんとクラスタなどでフィルタするパラメータが、そこにあります。



正確に追いかけてないので想像ですが、昔はコンパウンドの中にあって表に出ていなかったパラメータを、ユーザの要望が強かったので、最近のバージョンになって表に出したとか、そんな感じなんじゃないでしょうかね?

っていうか、アレか、昔は Emit From Surface だったもんね。 いつの間にかそれが Emit From Geometry に変わってたんだよな。 その時にこうなったのかな。



Emitfromcluster

クリックするとでかい画像が出ます。

シーンファイル(2012)のダウンロード(ZIP)




目のところにポリゴンクラスタを作ってあります。 そのクラスタの IsElement アトリビュート、つまり 「そのポリゴンは、このクラスタに入ってますか?」 の属性を、フィルタのリファレンスとして指定してやるというものです。たぶん。 これに引っかかったポリゴンのみから、パーティクルが発射されます。 

この記事はその部分をメモしときたかっただけですんで、ICETree のそれ以外の部分は何がどうというものでもありません。 




ってことで、Emission Filter ParametersReference に、エミッタにしたいクラスタの IsElement アトリビュートを指定、ということでファイナルアンサーにしてしまって良いでしょうか? 落とし穴ありますかね? 他にもっと良い方法ありますかね? どうかご教示ください m(_ _)m








問題は、マニュアルに、このパラメータを使えばクラスタで発射位置をフィルタできるとは明記されてない点ですね。

  Emit From Geometry のヘルプ(2012)

このパラメータの説明は、「ウェイトマップ」が対象であるという意味のことが書かれています。 クラスタとは書かれていませんね。 これじゃクラスタにも使えるって、読んでもわからないでしょう。 そもそも、ウェイトマップでどういうことができるのかすら、この表記じゃ分かんないなあ。 まあ、所詮 XSI のマニュアルですからね、そんなに親切なわけないですよね。



ちなにみ、最新のマニュアルではどう書いてあるのか確かめようと思って 2013 のヘルプを見てみたら、 

  Emit From Geometry のヘルプ(2013)


ウェイトマップ「など」 に使えると書いてあります。

おおっ、「など」 が付いたぞ! 表記がバージョンアップしてる! (゚∀゚)


・・・・まあ、なんつうか、「など」 なんて付けても相変わらず意味不明、と言うか更にも増して意味不明ですねぇw  この 「など」 に Cluster.IsElement を含めているつもりなのかなあ・・・?w   クラスタから発射するなんて、いかにも需要ありそうなことなので、ズバリそう書くとか、サンプルとして出しておけばいいのになあ。  まあ、所詮プラグイン扱いのソフトウェアのマニュアルですからね、そんな親切なわけが





っていうか、上のリンクの 2013 の方、まさにその Reference パラメータの説明ですが、「属性はジオメトリ全体における放出の速度をコントロールするために使用されます」 って書いてありますね。  は? 速度?  量(程度)じゃなくて?  英語のマニュアルを確かめたら、Rate って書いてありますよ?  Rate って日本語にすると速度なんですか?  嘔吐デスク様?

まあ、所詮われわれ下層の者どもが使うソフトウェアのマニュア




お、とか言ってたらこんな親切なヘルプのページが・・・・

  ICE パーティクル放出をフィルタする

なるほど、ウェイトマップやテクスチャマップで発射場所をフィルタする例が挙げられていますね。 そう、こういうサンプルをまさに載せて欲しいんですよ。やればできるじゃないですか嘔吐デスク様。

でもこれだけ豊富にサンプルを載せておきながら、なぜそこにクラスタから発射という我々下層の者どもでも思いつきそうな基本的な例が無いのかw


まあ、所詮





.

| | コメント (2) | トラックバック (0)

2012年6月29日 (金)

ICE で複数メッシュのマッチング。

久しぶりに XSI Base をのぞいてみたらなにやら危険サイト指定を受けていて焦ったが、どうやらすでに対処は済んでいるように見えました。 ほんとに大丈夫なのかな。 いったいどうしたのだろう。 どっかの阿呆がスパム的な何かを仕込んだのかな。




そんなことはどうでもよくて、ええと、頂点数も頂点の順番も全く同じ2つのメッシュで、片方のオブジェクトの頂点をもう片方に完全にマッチさせる(同一座標にする)には、とかなんとかの話が出ていたので、仕事したくない気分なので練習というか研究というかサボりというか確認のために、真似してやってみました。 このスレッド。

エリックさんは Switch Context を使えという。
やってみたらできた。
うん、簡単だ。

もし Switch Context を使わなければどうなるか、
をやってみたら、こうなった。
というメモですこの記事は。

Array_vs_switchcontext

クリックすると別ウインドウにでかい画像が出ます。


男が2人います。
男1がご主人様です。
男2は奴隷です。
奴隷の頂点は、ご主人様の頂点にぴったり一致して着いて行かねばなりません。

ということにします。



よって、従わせたいのは奴隷である男2の方なので、男2に ICETree を作成します。 その ICETree の中で、


 Get 男1のPointPosition → SwitchContext → 男2に SetPointPosition


とやればできました。 画像の の流れですね。 男1の頂点をぐにぐにいじると、男2の頂点も同期して動きます。 完全に一致して動いているように見えます。 なるほど、これ便利かも。


考えてみれば、ICE を使わずにこれをやろうとすると、Clone ってことになりますかね? でも Clone は頂点を数式的に指定してオフセットさせるとか簡単にできるわけじゃないし、ICE でやるメリットは大きそうな気がしますね。






ここでちょっと話が逸れますが、ツリー中の、この記事の本題とは関係ない部分について先に説明を済ませてしまうと、


前にもやった例の 「オブジェクト自身のSRT にも追従する」 をやりたいので、前半で Matrix と掛け算しています。 これで、頂点でなくオブジェクトを SRT した場合でも完全に追従します。たぶん。

それと、途中 Add を挟んで結果の頂点位置をちょいわきにオフセットさせてます。 これは単に、頂点位置が一致しているとビューポート上で二人の男がぴったり重なって見づらいからというだけです(まさにその頂点位置の一致こそがこのツリーの目的なんですがね)

それと、Aの流れとBの流れを確認するためにいちいちつなぎ直しが発生するのは面倒なので、if ノードで分岐させてます。 true にしている時はこっちの流れのツリーから来たデータがセットされ、false のときはこっち、という、確認を楽にするためのアレです。






本題に戻りますが、SwitchContext というのは魔法のようなノードで、その名の通り Context 違いでつながらないポート同士を無理にでもつなごうとするノード、という認識で合ってますかね? なんとなくそんな風に思っているんですが・・・・・ツッコミお待ちしております。ツッコミ歓迎です。



今回の場合、男1の頂点情報を男2の ICETree に持ち込みたいわけです。 最終的にセットされるのは男2の頂点情報ですから、その情報は男2が所有するものでなくてはなりません。 しかしこの例だと参照する元のデータは男1のものです。 男1のデータはそのままでは男2に入ってくれません。 なのでここになんらかのコンバートが必要になります。 そこで SwitchContext の登場。 こいつが男1の情報を男2のものとして変換してくれるという。  ええと、こんな解釈で合ってますかね? 間違ってたらどうかツッコミお願いします。




ってことで、上手く行っているように見えます。簡単だし、ノードが少なくて良い。




でもまあ、不思議な魔法でつなげているようで気持ち悪いと言えなくもない。 なので違う方法でできねえかなーってちょっといじってみたらできちゃったような気がしたのが、上の画像の の流れです。 男1の頂点位置をいじると男2の頂点も追従します。Bの SwitchContext でやった場合と全く同一の結果を得られます。たぶん。


このAの方法では、上流から流れてきた男1の情報を、Build Array from Set でアレイにブチ込んでいます。このアレイは男2の ICETree 上で構築しているものですから、これは最初から男2が所有する情報ということになります(中身は男1から来ているけれども)。よって下流のノード(男2の情報を要求しているノード)につなぐことができるようになります。 この辺の説明アヤシイかな。。。。


で、そのアレイの中の何番目のものをセットするか、の部分で Get Data を使って男2自身のVertex Index を参照しています。 頂点の順番情報ですね。  「アレイの中の最初の情報は自分自身の最初の頂点にセットするぜ。 アレイの中の10番目の情報は自分自身の10番目の頂点にセットするぜ」 ということですね。 つまり、男1も2も同じ頂点数、同じ頂点番号を持つということが絶対条件になっている ICETree ですね。





ってな解釈で合ってますかね?
分かってないのを見透かされそうで、毎回ビクビクもんですよ。 
ツッコミお願いしますね。



ま、多少解説が怪しくても、結果的にやりたいことが出来ていれば、こうしてメモしておけば後でカンニングできます。

でも、なんにせよ解説を正しく出来ないってことは理解してないってことだ、逆に言えば人に正しく解説できるってことはちゃんと分かってるってことなんだ、という思いがいつもあるので、美しい解説とか厳密に正しい解説を追及すること自体は良いことのはずだ、などと戯言をタレているヒマがあったらこのリテイク修正早くやれよブログ書いてる場合かよ仕事サボんなよ俺。



とかなんとか。





.

| | コメント (0) | トラックバック (0)

2012年6月14日 (木)

Seed を変えると発射。

花火の記事にコメントを書いてくれたミツモトさんが教えてくれた、スヴァらしい tips をメモしておきます。


その花火の記事の中で俺が、


  「エミッションのモードが Total Number of Particles の時、複数回発射させることはできるのでしょか?」


と疑問を投げかけています。 ミツモトさんがコメント欄でそれを教えてくれたのです。


Total Number of Particles モードで発射すると、通常は最初の1回しか発射できないじゃないですか。 任意のタイミングで何回も発射できれば便利なのになーって思ってたんですよ。

いい方法を知らなかったのでこれまでは仕方なく、、Number of Particles Per Second モードを使い、あるタイミングでイッキに Rate を上げてすぐ次のフレームで下げる、とかやってました。  このモードだと 「1秒間に発生する数」 ですが、例えば 24fps で作業していた場合に1フレだけ発生させたら24分の1の量になるわけではないので、ズバリそのフレームのタイミングで何個発生するかは、運任せでした(たぶん)。 


ですが、ミツモトさんは、Total Number of Particles モードにおいて、Seed にキーを打って数値を変化させると、そのキーのタイミングでまた発射させることができるとおっしゃるのです。


  なんですと (゚∀゚)



さっそくやってみたら、そのまんまできました。

Emitparticlesonseedchanged




シーンファイル(ZIP)のダウンロード(XSI 2012)





複雑でも何でもないので、あんまり解説するほどでもないですけどね。
Seed にキーさえ打てば、何度でも発射できました。


Aで、モードをそれにしています。

Bにキーを打ちます。

何もしないと、シーンの最初のフレームが1発目の発射になってしまいますが、Cをオフにしておいて、任意のフレームでオンにするキーを打ってあげれば、そこが1発目の発射になります。 画像の下の方、FカーブのCがこのキーです。

Fカーブのキーフレーム間の補完モードは、基本は Stepped で良いでしょう。値がいくつなのかは全く重要ではありません。 値が変わりさえすれば、発射されます。

FカーブのEの部分、ここは値が変わってないキーを打った部分です。値が変わってないため、発射されませんでした。 つまり、キーがあることが重要なのではなくて、Seed の値が変化することが重要だということになります。

Dの部分は補完を Linear にしました。つまり、次のキーフレームまで毎フレ値が変わります。 この部分では、毎フレ発射され続けました。




  いやあ、便利じゃないですかこれ ヽ(゚∀゚)ノ



これだけで、どれだけエミッションタイミングの自由度が広がるか。大違いですよ奥さん。

まだ仕事でバリバリ使ってないので、どこかに落とし穴があるかも知れませんが、それにしてもお手軽にエミッションタイミングをいじれるのは大きいです。


そのフレーム上における発生数(Rate)は、Rate というパラメータでズバリ指定しているわけだから、数に関しては最初から正確にコントロールできるモードですよね。 そして今回の方法で、タイミングも正確にコントロールできるわけです。 値を変え続けることによる毎フレ連続発射も可能ですね。  あとは、発生場所さえ自由にコントロールできれば、もう、かなり神に近づいたと言えるのではないでしょうか。そんなことないですか。そうですか。


Add Point やらなんやらで全く独自のエミッションをゼロから構築できる人はそうすればいいと思うんですが、俺などはもちろんそんなことできず、いつも Emit from XXX コンパウンドを使います。 この仕組みがわかっておられるお方、その仕組みを元にもっと良い方法を知っておられるお方は、是非教えて下さいませんか。



いやあ、早くこの手法を仕事で試してみたいですね。 仕事で使わないと検証にならないですからね。 楽しみですね。

ミツモトさん、ありがとうございました (゚∀゚)












それはそうとミツモトさんのブログを見てみると・・・・・



あーーー! ぱひゅーむのやつじゃないですかこれ。
すげえ、良く出来てますね!
XSI ですかこれは?
俺もやってみたかったんですよこのパヒューム踊り。
モーキャプデータと音はダウンロードしてあるんだけど、
俺、モーキャプデータを XSI でどう扱うかとか恥ずかしながら知らなくて、
そのうち調べながらやってみようかな、くらいで放置していたんです。

ううん、これ見て、やりたくなっちゃったなあ。
凝ったもの作る気はないけど、やはり、男を踊らせてみたいじゃないですか。

コンポでもけっこう手を入れてそう。
残像感のあるブラーかエコーみたいなやつは、後処理かなあ?
後半のスタジオっぽくなってるところの発光系も後処理?
天井ライトのレンズフレアは3Dからトラッキング情報とか出して2Dで?
それともICE制御だったりして?




それこそメイキング記事書いて下さいよミツモトさん



.

| | コメント (2) | トラックバック (0)

2012年6月12日 (火)

取得 その1001。 全ICETree/RenderTreeビューの取得。

選択中の ICETree ノードに対してごにょごにょするスクリプト、というのが最終的には目的なんですが、今回はその前提の段階となる、選択中のノードの取得について最近やったことを書きます。 あ、違った、更にもう一段階前の話です。 「選択中」のノードと言うけれど、じゃあ、いったいどこで選択中なのですか? という話です。


どこで選択中なのか? って、ICETree で選択中に決まってるじゃないですか。でも、ICETree って言うけれど、ICETree にはフローティングウインドウもあれば、ドックされた状態(レイアウトに埋め込んだ状態)もあるじゃないですか。それらを網羅して全部取得できないかしら、という実験の途中経過という感じです。




実はですね、この SI-Support の記事です。 いつもお世話になっているこのブログの、選択中の ICEノードをゲットするという記事を見て、やってみたんですよ。 そしたら、フローティングウインドウは問題ないけれど、ドックされたビューの中にある ICETree ビューには、その記事のスクリプトが効かないんですよ。 ドック状態のICETree ビューは無視されちゃうんです。 あ、ここで言うドック状態とは、フローティングではないという意味で言っています。 例えばビューポートの4つのビューのうち、ビューポートCを横に広げてビュー2つ分を占拠して使ったりするじゃないですか。そういう状態のことです。



その記事の中では、フローティングの ICETree ビューは、ビューの名前が ICE Tree だからいいけど、フローティングじゃないと名前が違ってしまうために、名前で選り分けることができない。 だから Type でフィルタしなさいという意味のことが書かれています。

しかしですよ、この記事のスクリプトを試してみると、選り分け対象にするために最初に全部取得するビューの中に、ドックされたビューが入っていないんです。 フローティングしか取得されないんです。 だから、Type でフィルタするとか以前の問題です。 ドックされた ICETree ビューは取得できておらず、取得できてない中から探しても当然見つからないわけです。意味ないです。


ですよね?

この記事の方法、フローティングウインドウにしか効きませんよね?

俺だけ?

誰かやった人は、教えてください。







そこで、こんなスクリプトを書いてみました。





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


//    どちらかをコメントアウト
TargetType = "ICE Tree";

//TargetType = "Render Tree";


Logmessage( "----------------------" );



//    ファンクションに飛ばして目的のビュー(ICETree か RenderTree)を全部引っかき集める
var oMyFuckinViews = GetFuckinViewsByFuckinType( TargetType );


Logmessage( "ヒットしたView の数 :" + oMyFuckinViews.count + " (" + TargetType + ")" );
Logmessage( "----------------------" );

//選択されていたノードの格納容器
var oNodes = XSIFactory.CreateObject( "XSI.Collection" );
oNodes.Unique = true;   
//これがないと、1つのICETreeを複数ウインドウで開いてた場合、ノードがダブる

//親オブジェクトの格納容器
var oNodeParents = XSIFactory.CreateObject( "XSI.Collection" );
oNodeParents.Unique = true;
//これがないと、選んでいたノードの数だけ親がいることになってしまう

//    ファンクションに飛ばして引っかき集めた View 全部をループ
for ( var i=0; i<oMyFuckinViews.count; i++ )
{
    var oMyFuckinView = oMyFuckinViews(i);
    Logmessage( "ヒットしたView(" + (i+1) + ") - " + oMyFuckinView );
   
   
//    選択中のノードをカンマ区切りの文字列として取得
    StringSelected = oMyFuckinView.GetAttributeValue( "selection" );
    var aSelected = StringSelected.split( "," );//    それをアレイに変換
   
    for ( var j=0; j<aSelected.length; j++ )
//    アレイをループ
    {
        if ( aSelected[j] != "" )
//    何もノードを選択してない場合、なぜか無文字の部屋ができてしまうので除外
        {
            var oNode = Dictionary.GetObject( aSelected[j], false );
//    文字からオブジェクトとして取得
            if ( oNode )
            {
                oNodes.Add( oNode );
//    オブジェクトとしてノードを取得できたら、格納
                Logmessage( "   そのViewで選択中のノード(" + (j+1) + ") - " + oNode.Name );
                if ( TargetType == "ICE Tree" )/
/    親も格納  ICETree の場合はその親である3Dオブジェクト
                {
                    var oParent = oNode.Parent3DObject;
                }
                else if (  TargetType == "Render Tree"
)//    親も格納  RenderTree の場合は単純にノードの Parent
                {
                    var oParent = oNode.Parent;
                }
                oNodeParents.Add( oParent );
                Logmessage( "      そのノードの親 : " + oParent.Name );
            }
        }
    }
}

Logmessage( "----------------------" );
Logmessage( "選択されていたノードの数 : " + oNodes.count );
Logmessage( "選択されていたノードの親オブジェクトの数 : " + oNodeParents.count );




//    View のタイプを文字列で渡すと View が格納されたコレクションを返すファンクション
function GetFuckinViewsByFuckinType( TargetViewType )
{
   
//    格納容器
    var oTargetViews = XSIFactory.CreateObject( "XSI.Collection" );

   
//    フローティングかどうかを問わず全View を ViewCollection として取得
    var oViews =  Application.Desktop.ActiveLayout.Views;
    Logmessage( "全ビューの数 :" + oViews.count );

   
//    取得した全View をループ
    for ( var i=0; i<oViews.count; i++ )
    {
        var oView = oViews(i);

  Logmessage( oView + " : " + oView.type );//これを非コメント化で詳細ログ
       
       
//    Type が指定のものと一致したら、格納(ここでヒットするのは、フローティングのもの)
        if ( oView.type == TargetViewType )    oTargetViews.Add( oView );
       

        //    View.Views プロパティは、効かない View オブジェクトにはエラーが出るので、仕方なく try catch
        //    なんかいい方法ないですかね

        try{
            var oViewViews = oView.Views;
            for ( var j=0; j<oViewViews.count; j++ )
            {
                var oViewView = oViewViews(j);
               
//Logmessage( "   ---- " + oViewViews(j).type );//これを非コメント化で詳細ログ
               
               
//    Type が指定のものと一致したら、格納(ここでヒットするのは、ドックされたもの)
                if ( oViewView.type == TargetViewType )    oTargetViews.Add( oViewView );
            }
        }
        catch(e){}
    }
   
    return oTargetViews;
}

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

このスクリプトのダウンロード(右クリックで保存)




実行すると、このようにスクリプトエディタの中に結果がログされます。

Geticetreeview

このスクリーンショットでは、ドックされた ICETreeビュー(ビューポートC)と、フローティングの ICETree ビューの2つがありますが、ログを見るとその両方がヒットしています。


どうでしょか。フローティングウインドウも、ドックされたビューも、全部取得して、ICETree だけ抽出できているように見えるんですがね。 どうですか。

ちなみに RenderTree にも効くようです。スクリプト冒頭で、TargetType という変数の中身を "Render Tree" にするだけです。






大事なのはサブルーチン(ファンクション)の中身の方なので、そちらだけ重点的に書いておきます。 スクリプト後半にあるファンクション GetFuckinViewsByFuckinType の中身です。



マニュアルを調べたり、過去によくわからないまま書いた自作スクリプトの残骸の調査から、フローティングかドックされているかに関係なく現在作業中の XSI 上で開かれている全部の View を取得するには、以下のように書けばいいらしいと判りました。


   
//    フローティングかどうかを問わず全View を ViewCollection として取得
    var oViews =  Application.Desktop.ActiveLayout.Views;
    Logmessage( "全ビューの数 :" + oViews.count );



これで oViews にビューがコレクションとして入りました。例えば自前のカスタムシェルフなどを開いていた場合、それもここで取得できています。 その他、インターフェース上に見えている全てのものが取得できているように見えます。


で、フローティングウインドウの ICETree の場合は、ここで取得できた View オブジェクトというオブジェクトの Type を調べると、もう ICE Tree になっているんですよ。 なので、取得できた全ビューをループして、ひとつずつ Type を調べます。


 //    取得した全View をループ
    for ( var i=0; i<oViews.count; i++ )
    {
        var oView = oViews(i);
      
//Logmessage( oView + " : " + oView.type );//これを非コメント化で詳細ログ

    //    Type が指定のものと一致したら、格納(ここでヒットするのは、フローティングのもの)
        if ( oView.type == TargetViewType )    oTargetViews.Add( oView );



Logmessage の行は、表示が長くなるのでコメントアウトしてますが、頭の // を削除して非コメント化すれば詳細がログされるので何が取得できているのかよくわかると思います。

上の SI-Support の記事のように Filter を使っても良かったんですが、なんとなくこちらの方が分かりやすかろうと思って、ループして Type をひとつずつ調べる方式にしています。

で、ここまでは本質的には SI-Support の記事と全く同じです。 違うのはここ以降です。







例えば、上に書いたようにビューポートCを ICETree にしていた場合にどうなるか。


4つのビューポート A,B,C,D って、実は View Manager(内部的な名前は vm ) というものの下に階層化されているんですよね。

なので、上記の  Application.Desktop.ActiveLayout.Views で取得できるのは、この vm までなんです。 取得できた View の Type を調べると、"View Manager" って出てきます。Logmessage を非コメント化して詳細ログを見るとわかります。

Viewviews

Type を調べたら View Manager であって ICE Tree ではないのだから、当然上の Type 判定には引っかかりません。 よって、ビューポートCは ICETree にしてあるにもかかわらずスルーされてしまうのです。 これが、SI-Support のスクリプトの問題なような気がしたのです。



なので、取得できた View オブジェクトに対しもう1回 Views プロパティを使ってその下層にある View を取得します。


        //    View.Views プロパティは、効かない View オブジェクトにはエラーが出るので、仕方なく try catch
        //    なんかいい方法ないですかね

        try{
            var oViewViews = oView.Views;
            for ( var j=0; j<oViewViews.count; j++ )
            {
                var oViewView = oViewViews(j);
               
//Logmessage( "   ---- " + oViewViews(j).type );//これを非コメント化で詳細ログ

 //    Type が指定のものと一致したら、格納(ここでヒットするのは、ドックされたもの)
                if ( oViewView.type == TargetViewType )    oTargetViews.Add( oViewView );
            }
        }
        catch(e){}


これです。


ここでわかりにくいのは、Views プロパティって言っても実は2つあることなんですよね。 

ひとつは、上の


  var oViews =  Application.Desktop.ActiveLayout.Views;


これですね。 Layout オブジェクトの Views プロパティです。 これで取得できるのは View オブジェクトコレクションです。 ひとつひとつを取り出せば、それは View オブジェクトです。

でも、そうやってひとつひとつ取り出された View オブジェクトにも、さらに Views プロパティがあるんですね。 今度は View オブジェクトの Views プロパティです。 これで取得できるのはやはり、View オブジェクトコレクションです。ひとつひとつを取り出せば、それは View オブジェクトです。


このように、View オブジェクトは Layout オブジェクトのすぐ下層にある場合もあるし、Layoutオブジェクトのすぐ下層にある View の更に下層にある場合もあるという、全くもって腹の立つ分かり難さです。このために  Layout.ViewsView.Views を両方試してあげないと、全部の View が取得できないことになります。



もっと厳密に言うと、View.Views で得られた View それぞれにも Views プロパティがあるわけで、これは再帰的無限地獄に突入する気がします。 なのでこのスクリプトでは1階層しか潜っていません。




とまあそんなわけで、Layout.Views から取れた View そのものの Type が ICE Tree ならそれはフローティングのはずだし、ドックされていれば vm などの子供になってるはずなので一階層潜って( vm の Views を調べて)更に Viewオブジェクトを取得し、そちらに対しても Type のテストをしてあげるということをやっているのが、このファンクションです。

ちなみに、vm 以外で同じ状態になる例を挙げると、自作のカスタムシェルフ、リレーショナルビュー等だと思います。 あと、XSI Explorer なんかもビューの子供にビューがあるタイプのビューなので、フローティングの XSI Explorer の中に ICETree が含まれる場合などは、同様に View.Views を調べてあげる(=フローティングの XSI Explorer (Viewオブジェクト)に対してさらに Views を調べてあげる) 必要があるかも知れません。







それともうひとつ、Layout.Views で取得できた View オブジェクトのうち、全ての View オブジェクトが、Views プロパティを持っているわけではない、という点も重要です。 上の vm の例のように、1階層潜ったところに ICE Tree が存在してないか調べようとして、取得できた全 View に対し Views プロパティをチェックしようとすると、エラーで止まってしまうのです。 

vm やカスタムシェルフやリレーショナルビューや XSI Explorer など、下層に何かのビューを所有している View オブジェクトに対しては効くのですが、Desktop.Views で得られる全 View のうち下層に何も持たないやつも多いので、そいつらに対して Views プロパティの呪文を唱えると、エラーで止まってしまうんですよね。



これを回避する方法がわからず、仕方なく try catch を使っています。 try catch ってのは全てのエラーに対して効いてしまうので、例えばただのタイプミスで動かないスクリプトでも、そこで止めずに実行を続けてしまいます。なのでメンテナンス上非常に都合悪い。問題箇所の特定が難しくなりがちです。 なのでなるべく使いたくないのですが、他に方法が見つからない時はこうして仕方なく使ってます。 なんか方法ないでしょうかね?








ともかく、これでドックされたビューの中にある ICE Tree ビューもちゃんと取得できるようになったように見えるのですが、どうでしょうかね。落とし穴ありますかね。 どなたか、もし試してみたら、教えて下さいませ。

っていうかそもそも、もっと簡単に全 ICETree ビューを取得する方法、あるのでしょか?  あったら知りたいです。







.

| | コメント (0) | トラックバック (0)

2012年6月 8日 (金)

頂点上にパーティクルを発生させる。 その4。

さらに続き。


m4g さんにはいつもお世話になっております。


パーティクルをブツの頂点上に発生させて、そして法線方向に向ける、というものですが、m4g さんに御教示頂いたツリーを載せておきます。 この方法の方が良い気がする。


この記事では、法線方向に向けるということのみに注目していますので、それ以外の要素のことは敢えて省いてあります。

Pointatnormal_m4g

クリックするとでかい画像。


このツリーで、パーティクルの Orientation を決定する(法線方向に向ける)ために使っているのは、Increment Rotation with 2 Vectors という標準コンパウンドです。 画像の中のEです。 (ちなみに、俺が前回使ったのは Rotate Vector でした)

この Increment Rotation with 2 Vectors ってのは、ある回転値(Rotation)をベースにして、ローカルのこのベクタ(Local Vector)を、ワールド座標のこの位置(To Vector)に向けるために必要なだけの回転値をベース回転値に加算するぜ、というコンパウンドだと思います。マニュアルにそう書いてあるように見えます。 しかし、例によってマニュアルの表現って不思議ちゃんな感じですね。


今は cone をパーティクルの形状に使っていて、とんがった方向をパーティクル発生源メッシュの法線ベクタに向けたいので、これはパーティクルのローカルY方向ですね。

ということで、Increment Rotation with 2 Vectors に食わせる情報は、以下のようになります。

  Rotation = パーティクル自分自身の元の回転値(現時点でゼロですが)。

  Local Vector = 0, 1, 0 (パーティクルのY方向)

  To Vector = パーティクルを発生させたメッシュの法線ベクタ



Rotation は、自分自身のローテーションですから、self.Orientation をゲットすればいいだけなので問題なし。今回は Get Particle Orientation コンパウンドを使っています。


Local Vector はそのまんま、0, 1, 0 を入力します。



問題は To Vector です。 というのは、こいつは発生源メッシュから法線情報をもわらねばなりません。 

俺ごときは画像内のDのように普通に発生源メッシュの PointNormal を突っ込めばいいやと考えてしまいがちなのですが、これはコンテクスト違いでつながってくれません。
 
Pointatnormal_m4g_unabletoconnect

なぜつながってくれないのか。 

それは、Increment Rotation with 2 Vectors は自分自身(PointCloud)の情報を欲しがっているのに、他人(発生源メッシュ)の情報を突っ込もうとしているから、だと解釈しましたが、合ってますかね。



つまりですね、そもそもこの ICETree が与えられているオブジェクトは発生源メッシュではなく PointCloud なのであり、その PointCloud に属するパーティクルの向きを決めるために Increment Rotation with 2 Vectors を使っているんだから、こいつは自分自身の情報(PointCloud が所有する情報)しか食ってくれない、という意味だと思うんですよね。


そこで、発生源メッシュが持っている情報を PointCloud 自身の情報にコンバートしてやらねばならない。 そのために、Get Closest Location ノードを使っていると考えられます。 画像内のBです。

Pointatnormal_m4g_2
クリックするとでかい画像。

発生源メッシュから Geometry ポートに情報を渡してます。 次にAではパーティクル自身のポイント位置を拾ってきています。 そして先ほどの Geometry とAを比較して一番近い場所(Location)を吐き出しています。 「A(自分自身の情報)のうち、メッシュに最も近いところを吐き出す」ですから、吐き出すものは自分自身の情報であるという部分が重要です。 そしてこのとき、パーティクルはもともと発生源メッシュの頂点位置に発生させているわけですから、「一番近い位置」 は頂点とズバリ 「同じ位置」 であると保証されています。 

そしてその位置を、Cの Get .PointNormal に食わせているので、CはBからもらった位置における法線方向を吐き出すということになります。 Bからもらった位置とは、自分自身の情報であるという部分が重要です。 

結果、パーティクルが発生しているズバリ同じ位置における、発生源メッシュの法線方向(他人様の情報)を、自分自身(PointCloud自身)の情報としてゲット出来たのがCだということになります。 よね? 合ってますよね?  で、もう自分自身の情報なんだから、自分自身のローテーションを決めるためのEに食わせることが可能になった、という解釈です。 


別の言い方で言うと、Get Closest Location の Position ポートに入っているのはAで取得した自分自身のパーティクル位置ですから、Bが吐き出すのはあくまでも自分自身が持つ情報だということです。

その自分自身が持つ位置情報のうち、発生源メッシュに一番近い場所=実はズバリ同じ場所をBは吐き出しているわけで、実質的には発生源メッシュの情報を100%コピーしたことになりますね。 コピー元は他人様で、コピー先は自分自身。 以降はコピー先(自分自身の情報)を利用する。 という感じ。 




ということだと思っています。
冗長ですみません。
しっかり説明できるくらい理解したい。
ちゃんと理解できたら、もっと簡潔に書けるかな。。。。
間違いあればどうか指摘お願いします。


ええと、前回までのツリーでは Build Array from Set を使っていたのですが、なぜアレイが必要なのかよくわかってませんでした。 他人様から情報を頂く時はアレイが必要なのかな? なぜ? みたいに思っていました。

でも、もし今回と同じ考え方ができるとすれば、アレイを介すことによって他人様の情報が自分の情報になる、と解釈できる気がしました。 アレイの入力は他人様からもらってるけど、アレイそのものはPointCloud 自身の ICETree 内に発生させているものなので、アレイが吐き出す結果はもう自分自身が所有する情報である。自分自身の情報になったのであれば、自分自身の情報を要求する下流ノードにそのまま接続することができる。 ということなのではないか。

どうですか。間違ってますか。どうか指摘して下さい。







もうひとつ重要な発見、というか新たな謎が・・・。


前々回の記事の後半で、ベースメッシュを変形させると、ビューポートが表示する法線=青い線と ICETree が返す法線が一致しないと書きました(GIFアニメーションになってます)。

しかし、今回 m4g さんに教えてもらった Get Closest Location 方式で取得した法線は、変形後も、ビューポートが表示する青い法線と完璧に一致するのです。

Pointatnormal_m4g_matchnormal

前回のツリー、Rotate Vector 方式では一致せず、今回の方式で一致するのは、うーむ、なぜなのでしょう。


一致したからどうだというものでもないのですが、その仕組みを説明できるほどは、俺はまだ理解できていません。 どなたか説明してくれませんか。 そこらへんが解ると、さらに理解が進みそうな悪寒がします。







.

| | コメント (2) | トラックバック (0)

より以前の記事一覧