RTシェーダにおけるランバートシェーダのディフューズの輝度は、法線ベクトルとライトベクトルの内積によって求められます。
計算式だと
L・N=|N||L|cosα
とあらわされますが、今回は特にこれは重要ではなく、
L・N(エルドットエヌ)という計算が内積計算になるということです。
ドットというだけあって、ICEノードに実は Dot Product というものがあります。
たとえばCgシェーダでも内積は dot(NormalVector,LightVector); と表記しますように、Dot Productノードは2つの入力値間の内積を求めるためのノードです。
Math > Vector > Dot Product ・・・とたどります。
そして、これに法線ベクトルと、ライトベクトルを接続していきます。
法線ベクトルは要はPointNormalのことなので、GetDataを使用して、今までの要領でPointNormalを直に接続できます。
※前のページまでにあるように、GlobalSRTをかけてワールド化しておくのを忘れないでおきましょう~。
問題なのが、ライトベクトルです。
とりあえずシーンに最初から存在するInfiniteLightを使用しますが、このライトのRotationを取得してもそれはベクトルデータではありません。
※RTシェーダを書くときはLightからダイレクトにベクトルデータが取れるのに、ICEはここが少し不便です。
ここで、Conversion > 4x4 Matrix to Vector に注目しました。
マトリクスをベクトルに変換できるノードがあるのなら、とりあえずライトのRotationをマトリクスまで変換できれば良いかも!と。
少し特殊なやり方になりますが、ノードの逆算方です。
ここからしばらくConversionグループ続きです。
4x4 Matrix to Vector に Conversion > SRT to Matrix をつなぎます。
このノードがSRTをMatrixに変換してくれます。
次にRotationの値がほしいのですが、GetDataは素直にRotationを取得してくれませんので・・・(オイラーかクオータニオンのみ)
Quaternion to Rotation をRotationにつなぎます。(ScalingとTranslationは必要ないのでそのまま・・・)
これでやっと、GetDataをつなぐことが出来ます。
Get Dataノード > Explorerボタンをクリック。
Light > Kinematics > GlobalTransformation > Ori > Quat(クオータニオン回転)と選択すると、light.kine.global.quatとテキストボックスに入力されます。
※Euler to Rotationというノードもあるのですが、GetDataにEulerを設定しても Euler to Rotationにつなげないのは私の気のせいでしょうか・・・。
ここまででライトの回転をベクターに変換することが出来ました。
さて、今度は4x4 Matrix to Vectorから4つのポートが出力できることになっているのに気づいて、どうしたら良いかわからなくなります。
シェーダを普段から書いている人は4x4のマトリクスといえばおなじみですが、解説が長くなるのでマトリクスに関するリンクを以下にリストして置きます。
3D 基礎知識
変形を伴わない回転(東京工科大学 メディア学部 クリエイティブラボ サイトへ)
4x4 Matrix to Vectorは出力ベクトルを列で取るか行で取るかを決めれます。
今回は列(Row)で取得します。
概念で考えると結構混乱するものですので、ここは特殊な(でも案外なるほどな)選び方をして見ましょう。
Debugging > Log Value を呼び出し、Vector一つ一つに順番につないでログを見ていく方法です。
ここでLightの回転値を0にしておきます。ライトを作成した瞬間の向きになると思いますが、-Zの方向を向いています。
そして Log Valueをつなぐのですが、一旦 Dot Productノードのことは忘れて、適当にICETreeまで繋がる構成をします。
(例(下図):LogValueのOutを Conversionの 4D Vector to ScalarとRGBA to Colorを使ってSetDataに仮繋ぎをしています。)
※こうしないとログが表示されないのが不便です。
Script EditorをAlt+4で開き、ログをみながらVectorポートを一個ずつつないでいきましょう。
ログの4行目がそれぞれ以下のようになると思います。
Vector 1 = ' INFO : 4000 - elt 0: < 1.000000, 0.000000, 0.000000, 0.000000 >
Vector 2 = ' INFO : 4000 - elt 0: < 0.000000, 1.000000, 0.000000, 0.000000 >
Vector 3 = ' INFO : 4000 - elt 0: < 0.000000, 0.000000, 1.000000, 0.000000 >
Vector 4 = ' INFO : 4000 - elt 0: < 0.000000, 0.000000, 0.000000, 1.000000 > |
< > の中は左から順にX,Y,Z,Wとなっています。
そして今のLightの姿勢をベクトルで表現すると < 0,0,-1,0 > となるので、この中で正解は
Vector 3ということになります。
Infinite LightはZ基準なのですね。
おいおいちがうやろ!と突っ込まれた方は鋭いかもしれません。
Vector 3が表す数値はZが1で正の数なのに対し、Lightの姿勢はZが-1ということなのですが、ここでこの章の最初の画像に戻ります。
矢印が、ライト自身のベクトルと逆を向いているのに気づきましたでしょうか?
オブジェクト自体のシェーディングを計算するためですので、オブジェクトからみてライトはこっちの方向にあるよ!
という意味でライトベクトルというのは、XSI内のライトの矢印とは反対になるのです。
それでは Vector 3を Dot Productに繋ぐという段で、微妙にポートの黄色の色が違うことに注目します。
これはPointNormalは三次元(X,Y,Z)ベクトルを出力しているのに対し、Matrix to Vectorは四次元(X,Y,Z,W)ベクトルを出力しているためです。
ここはどうやら次元をあわせないと繋がらないようなので、Conversionから 4D Vector to Scalar で分割して、XYZのみ Scalar to 3DVector でまとめなおします。
これで難なく Dot Productに繋ぐことが出来ました。
ここまで出何が出来たかというと、ランバートの輝度値です。※RGBA to Color を使って Dot ProductのResultをRGBそれぞれに繋いで、SetDataにつないで見てください。
このままだとただの白黒シェーディングなので、普段のXSIのシェーディング表示時のようにディフューズカラーや、
アンビエントカラーを加味した色味に出来るように仕上げたいと思います。
まず、ディフューズ色は簡単で、Color > Multiply Color by Scalar を呼び出して、Factorポートに Dot ProductのResultを繋ぎます。
色の設定はこのノードが持っているのでそのまま使います。
クランプの設定は0~1の間にしておきます。
次はアンビエントカラーです。
アンビエントは加算なので、Color > Add Color を使います。
これでほぼランバートシェーダの完成です。
まだまだイケル!という方はシーンアンビエントの取得や、ライトカラーの乗算なども試してみてはいかがでしょうか?
最後にこれのコンパウンドの公開です。
上図のようなディフューズカラーと、アンビエントカラーを外部公開し、ライトはGetDataでオブジェクトを指定して繋ぐ
というコンパウンドノードをダウンロードできるようにしておきます。
ご自由にお使いください。
※外部公開入力へ出力した色のパラメータは、コンパウンドをダブルクリックするとPPGとして変更できます。
< fmt_LambertShader v0.5 ダウンロード >
このコンパウンドは下図(コンパウンド内部)のようにGetData内にはライト名ではなく、Kinematicsから設定されています。
そしてIn Nameに外部公開入力が入力されていますので、コンパウンドの外で(上図右の左下)GetDataからライトオブジェクトの名前のみを指定して接続。
といった方法でライトを設定できます。
|