![]() |
プロローグ これも、CEDEC2011にて公開したICE機能の1つです。 ![]() ゲーム用のデータ作成に使える機能かな、という感じです。 ついでにRaycastノードの使い方習得というかたちでまとめてみました。 表題にはAmbientOcclusionと書いていますが、 それらしい結果が得られた、くらいの認識でお願いします。 各自が欲しい効果になるようにカスタマズする際の参考になればと考えます。 公開にあたり、関係各者のご理解、誠にありがとうございます。感謝です。 > NodeLocation > 頂点色設定の鍵 > Raycast > 基本設定 > 値の改善 > コンパウンド化 > インフィニット・ライトを使う > Ambient Occlusion > 3DVectorのArray対応 > Fill Interpolated Array > 法線とインフィニットライト情報の追加 > Array(配列)を0~1値にする > コンパウンド化 > グループ対応のコンパウンド化 > グループ対応のスクリプト パソコンのスペックWindowsXP SP3、Intel Core2Duo 3G、 RAM; 3G、NVIDIA Quadro FX1700 |
Raycast
基本設定まずはRaycastノードの使い方を身に付けちゃいましょう。 ![]() 実は大きさは関係ないのですが、スケール値は厄介なことにならないように1にしておいてください。 これをPolyLightと名前を変更しておいて、ここからレイが発せされる仮のライトとして扱います。 Raycastノードを取り出し、GeometryとしてGet Desk1を接続します。 Positionとしてself.PointPosition、 DirectionとしてPolyLightの位置データから己のPointPositionをSubtract(減算)した値を接続します。 その結果のLocationをSetDataのself.tmpと仮のデータに差し込んでICETreeに接続します。 これが最も基本的な接続例です。 Raycast の左側PositionとDirectionを視覚化して、何やってるのか見て理解を深めましょう。 ![]() ![]() ![]() 机の頂点の位置から発してポリゴンライト位置の方向に到達しているっていうベクトルが得られます。 いつもこうして検証して見れるのがICEの有効利用ポイントですね。 さて、この真ん中のGetPointPositionなのですが、まさにポリゴンの頂点と同じ位置なので、 影の影響を出すには、頂点位置から法線方向に少し浮かした位置から発した方が良い結果を得られます。 それを以下のように設定して実現します。 ![]() その値をPoinPositionにAdd(加算)してあげればほんの少し浮かすことが出来ます。 これで己のポリゴン表面にレイが当たりやすくなり、影が出やすいようになります。 ![]() LocationとHitしかありません。 前述では、Locationを仮のtmp値に接続したのですが、 これでは個々のレイが当たった位置情報を表示してしまいます。(0,0.0とは当たらなかったという意味) そうではなくて、Hitの方を仮のtmp値につなげてあげると、レイが何かに当たると1をかえしてきます。 つまり、この1になった部分が影になれば、陰影が作成できます。 ![]() もし当たったら0をそうじゃなたら1をというResult(結果)を、最初に作ったGradiantに接続すれば、 おう!!頂点色がPolygonLightの位置によって変化するが実現できました。 値の改善 仕組みはもう大体見えて来ました。後はより良い結果を得る工夫次第です。 ヒントは、たくさんのRaycast事例がありますので、そこから面白そうな仕組みを取り入れてみましょう。 ![]() Subtract(減算)から出ている値はRaycastのDirectionに接続しているベクトルでした。 その値と法線データGet PointNormalをGetAngleBetweenにつないで角度を求め、 Rescaleノードを使って0~1の間の値に範囲を変換しています。 さらにFCurveを使って値変化に強弱を増し、Ifにつながる1を求める部分につなぎ変えます。 この結果に違いは以下図↓のようになります。 ![]() 結果として、平行投影っぽい色合いから、ポイントライトっぽい距離による減衰効果が得られています。 ![]() Ifから出る結果を一旦tmpという値に集め、Get Neighborsから各頂点の近隣の値をtmpから取得し、 Get Array Averageで平均値を取ってGradientにつなげると、上図の絵上と絵下の違いになりました。 更に、レイ角度にランダムのノードを差し入れて、それを何回がリピートした平均値を作り出す、ってのも試したはみたものの、 あまり綺麗な結果を得られなかったので、それは見送りました。 コンパウンド化 では、一旦ここまでのものをコンパウンド化して、簡単に使えるようにしておきます。 ![]() 頂点色を設定するポリゴンのジオメトリーとライトの位置のポイントを作成します。 一番下のGradientはReferanceとしてつないでおいて、 コンパウンドのノードをダブルクリックした時の表示画面から頂点色が変更できるようにしておきます。 右側はExecuteを1つにまとめておくと見た目良くつなげられるようになります。 ![]() コンパウンドの書き出しをすれば記入したカテゴリに書き出されます。 インフィニット・ライトを使う 光の方向と色を、通常良く使っているインフィニット(平行投影)のライトの設定画面から変更できるようする、 という風に改造してみます。 ![]() ライトの回転に従ってベクトルも回転するようにするには、Rotate Vectorを使って、 3DVectorにZ値-1のベクトルを用意して、ライトの回転値をRotationにつなげれば、 同じ方向を追従する、と解ります。便利!! Raycastに使う時はライトの方向に向くベクトルが欲しいので、3DVectorのZ値は逆方向の1になります。 このようなつながりになりました。 色は、各R・G・B色に分けてからMultiplyで掛け合わせます。 これで、ライトの回転で明るさの方向が変わり、ライトの色で頂点色も変化します。 コンパウンドにまとめると、こんな風になりました。 ![]() |
Ambient Occlusion
3DVectorのArray対応さて、ここからは、少し今までの方法と違う事を考えます。 前述の通り、少しランダムな値を入れたベクトルを作り出して、それをリピート処理して平均値を求める方法では綺麗な結果を得られませんでした。 そこで、複数のベクトルをArray(配列)処理できる仕組みに変えてみたいと思います。 Gradientにつながる所は大幅に変更が必要ですが、その仕組みを一旦理解できたら、それを利用すれば良いだけです。 まずは、複数ベクトルの対応からで、つないだ結果を先に見せます。 一番左下はコンパウンドになっていてFill Interpolated Arrayって書かれています。 ここに今、4というカウント数(レイ数になる)を入れていると、次のノードがPop From Attayなので、1つArray(配列)が削除されて3となり、 その数のベクトルが各頂点位置から出ている、っていう図になっています。(ここのカウント数は最終的には10とか16とかなります) これを、もう少し詳しく説明します。 Fill Interpolated Array 最初のコンパウンドが何やってるの?ですね。 ![]() 黄色の接続点、上(ValueA)がY=390、下(ValueB)がY=30、つまり、360度で1回転に30度足した数字にあえて入っています。 つまり、目的としてはY軸360度を、入って来た数字で割った回転値分のArray(配列)を作り出している代物です。 4の次のMaxmumには3が入っていて、3より下の数値にならないようになってます。 Build Array from ConstantにはSizeもValueにも最大値が入るので4で、4つの4のArray(配列)を作ります。 Get Array Sub IndicesはArray(配列)の順番数を列に入れるので、0,1,2,3となります。 下に行って、Subtract(減算)は1が入っていて最大値から1減った数3になります。 上も下もInteger to Scalarはスカラー数字に変換し、そのままの数字が移行して、 Divide by Scalarは0,1,2,3を3で割った数のArray(配列)、0、0.333、0.667、1となります。 ・・・つまり、どんな数字が入って来ても、その数字から1引いた数で割った0~1の数値のArray(配列)を作り出します。 最後のLinear Interpolateはその割った数に相当する角度を出すので、Y=30、150、270、390というArray(配列)を作り出します。 この部分のコンパウンドが作製できたら、Fill Interpolated Arrayという名前でコンパウンドを書き出しておいてください。 で、次も説明してしまうと、30と390って同じベクトルのことなので、Pop From Attayで一番下の列が削除され、 Y=150、270、390というArray(配列)を出します。 ![]() 法線とインフィニットライト情報の追加 次は、Rotate Vectorノードを使い、各頂点の法線情報で求めたArray(配列)ベクトルを配置します。 ![]() ![]() Array(配列)を0~1値にする Array(配列)を使った数値(マルチのデータ)が入って来るので、このようにしないとつながりません。 意味が解ってくれれば、後は使うだけなので・・・・。 では、RaycastのHIT出力から出る値の意味を説明します。 GetArraySizeは必ず0以上になるはずなので、=0に絶対ならないので、 Rescaleの前のIfはいつも下のif Falseの値が使われます。 GetArraySumはHitした総数を計算しているので、直前のIfがHitしたら1を足していって0~2の値を作り出します。 そのArrayをDived by scalarでいつも1少ない数値(ここでは2)で割るので、 かならず0~1の値を作り出します。 GradientにつながるRescaleはグラデーションの0が黒なので、 逆になるようにしていて、Clamp にチェックを入れて負数にならないようにしています。 ここも前のところと同じで、ある値に1少ない数値で割ると0~1の範囲の値を得られる っていうのを使うのがミソのようです。 ![]() 一旦tmpデータとしてSetDataしてGet Averageで平均した値をGradientにつなぎます。 コンパウンド化 そしたら、ここまでのノードのつながりを、たった1つのコンパウンドにまとめてしまいます。 Rayの数、表面からの距離、減衰を考慮する距離、 インフィニットのライトを使用するかどうか(色も含む)グラデーションの色、ライトの選択、 はコンパウンドをダブルクリックして表示される設定画面で見えるように設定します。 ![]() インフィニットのライトを使うかどうかはIfによって選べるようになっています。 GradientやGetLightにはReferenceで接続して変更できるようにしておきます。 Ambient Occlusion with Lightという名前でカテコリColorとして書き出せば、皆で使えるコンパウンドになります。 ![]() ![]() グループ対応のコンパウンド化 さて、背景とかに使用するとしたら、複数オブジェクト対応も必要なんだろうなと考えました。 まずは、複数のポリゴンオブジェクトをマージした場合は簡単ですよね。 ![]() Geometryとして左側の紫色の接続点がつなぐと増えるタイプにしました。 Geometry を複数接続する時は、Group Geometryノードを使用します。 グループノードを追加したり複数接続したりすることができるようにです。 ![]() プロパティーにて[マルチ-新規のポートを既存のノードに接続]とすると 接続すると、どんどん増えるタイプになりまうす。Geometry接続点がどんどん増やすことが出来ます↓。 ![]() それがコンパウンドから操作出来るようにしました。 ![]() グループ対応のスクリプト 最後は、1つのコンパウンドにまとまったら、 スクリプトを使って、Group登録されているオブジェクトに ICETreeノードの設定、コンパウンドノードの接続まで、一気にしてしまいます。 Groupに入れた複数のポリゴンオブジェクトに、まずは頂点カラーの設定だけはしておきます。 そして、Group >メンバの選択をしておいて、以下のスクリプトを走らせます。
このスクリプトのダウンロード>>ApplyAO.txt(本当の拡張子はvbsで) 良く使うスクリプトなどはこのようにボタン形式にすることもできますね。↓ ![]() このスクリプトもあらかじめ接続するノードが同じである範囲を考慮してスクリプトを改良し、 一気に設定してしまえば作業がどんどん楽になることでしょう。 PS, Groupを使った複数オブジェクトの状態での頂点色設定は、1つのオブジェクトにマージしたオブジェクトに設定した場合に比べて 結果がはっきりしない、というかあまいというか、差がある場合がありました。特に真平らな面など。 マージしたポリゴンに一旦頂点色を設定して、個別へはGATORなどを使って色を移し変える、 なんてことも考えられると思います。 ![]() |
という訳で、次もICEですかね。 乞う、ご期待!!
|