株式会社デジタル・フロンティア-Digital Frontier

Header

Main

  • TOP
  • DF TALK
  • ◆移植オペ(下巻)◆ ~ Softimage & Mentalray Shader ~

◆移植オペ(下巻)◆ ~ Softimage & Mentalray Shader ~

2011/7/19

Tag: ,,

皆さん夏バテしてませんか~?

このクソ暑さに毎日とけまくっている開発室ゴトー[@jackybian]です。
さて2回に分けてお送りしてきたこのネタ、ホントは2部構成で考えてたんですが。。。
まさかのトリロジーになっちゃいました(;´∀`)
この手の内容を分かり易く端的に伝えるのはなかなか難しいっす。
でもICEクンのおかげで説明ムービーとか作り易くかなり助かってますけどヽ(゚∀゚)ノワーイ

さてこのネタもいよいよ最終章!
という訳で今回は”latolong DE 拡張~チョットだけよっ♪~”篇です。
前回ネタはコチラからどうぞ。

前回お伝えしたようにlatlong_lensのオリジナルコードではカメラ空間をベースに三角関数を使ってレイの方向を
変位させています。したがってカメラの位置や向きによって当然結果が変わる訳ですが、
生成された環境マップは最終的にEnvironmentシェーダー(Sphericalモード)のテクスチャとして使われることが多く
このマップを指定するだけで(パラメータは弄らずとも)背景と同じ環境として使える方が楽です。
そのためGlobalZ(+)方向に環境マップのシームがくる状態、つまりカメラの向きはGlobalZ(-)方向で良いことになります。

それであれば最初からカメラの向きには依存せず、GlobalZ(-)方向を向いているものとして計算するモードがあった方が
いいだろうと思い、少し拡張してみようと考えた訳です。

ではこのモードを実装するためには、どうやって仮想球上へのレイベクトルを求めればいいのでしょう?

実際のレンダーカメラの向きとは関係なく、GlobalZ(-)方向を向いているものとして…という観点から
”グローバル空間でのベクトル:(0,0,-1)は使うんやろな~”
”あとはこのベクトルを対応するピクセルに応じて回転出来ればな~”

そんなことを考えながらMentalrayマニュアルのIndex頁で”rotate”を検索してみると…何とっ!!
その名もmi_matrix_rotate()なる関数がっ! (゚ー゚☆キラーン♪

void mi_matrix_rotate(
  miMatrix           a,
  const miScalar  xrot,
  const miScalar  yrot,
  const miScalar  zrot)
//Create a rotation matrix a rotating by xrot, then yrot, then zrot, in radians.

ツタナイ【関数の日本語訳】: x,y,z(ラジアン角)の順で回転したときの回転マトリックスを作るそーな♪
これでUV値をRadianに変換してこの関数に渡してやれば回転に必要なMatrixはゲットできるじゃん♪
でもってベクトル:(0,0,-1)とこのMatrixを掛けてやれば求める方向ベクトルになるや~ん。

という訳で今度は”matrix”, “vector”にて検索してみると…
mi_vector_transform()を発見!

void mi_vector_transform(
  miVector       *const r,
  miVector const *const v,
  miMatrix const  m)
//r = v * M : Only the upper left 3-by-3 submatrix is used since this is a vector transform.
//The translation row in the matrix is ignored as w is implicitly assumed to be 0.

ダサイ【関数の日本語訳】: ベクトルにマトリックスの3行3列部分を掛け、ベクトルをトランスフォームするなり♪
Σ(゚∀゚ノ)ノス☆テ☆キ!!
これで実装に必要な準備完~了!

では実際のコードを見てみましょう。 *今回の実装モード処理部のみ抜粋

//⓪
double uv2rad(double v, double oldmin, double oldmax, double newmin, double newmax)
{
  return newmin + ((v - oldmin) / (oldmax - oldmin)) * (newmax - newmin);
}
//============================================================================
//①
miBoolean vmirror;
miMatrix matrix;
miScalar uval;
miScalar vval;
miVector raydir = {0, 0, -1};
miVector raydir_new;
//②
vmirror = *mi_eval_boolean(&(params->m_vmirror));
//③
if (vmirror==miTRUE)
{
  uval = (state->camera->x_resolution - state->raster_x) / state->camera->x_resolution;
}else{
  uval = state->raster_x / state->camera->x_resolution;
}
vval = state->raster_y / state->camera->y_resolution;
//④
mi_matrix_rotate(
  matrix,
  uv2rad(vval, 0, 1, -M_PI/2, M_PI/2),
  uv2rad(uval, 0, 1, M_PI, -M_PI),
  0.0);
//⑤
mi_vector_transform(&raydir_new, &raydir, matrix);
//⑥
return mi_trace_eye(result, state, &state->org, &raydir_new);

⓪【レンジ変換用関数の定義】
UV値をRadian値にレンジ変換するための関数を定義しています。

図から、a2:a1 = b2:b1より
a1 * b2 = a2 * b1
b1 = (a1 / a2) * b2
  = ((vOldmin) / (OldmaxOldmin)) * (NewmaxNewmin)
X = Newmin + b1
 = Newmin + ((vOldmin) / (OldmaxOldmin)) * (NewmaxNewmin)

①【まず各変数を宣言】
シェーダーのUIパラメータ変数  : vmirror
回転マトリックス用変数       : matrix
UV座標への変換変数        : uval, vval
レイベクトル用の変数        : raydir = {0, 0, -1};
変換後のレイベクトル変数     : raydir_new
を宣言および定義しています。

②【シェーダーパラメータの取得】
mi_eval_boolean()関数によりシェーダーのUIパラメータを取得しvmirrorへ格納。
このパラメータはシェーダーにより生成されるlatlogマップを水平方向に反転するかどうかのbool値です。

③【サンプルポイントのUV座標化】
レンダリング解像度(x_resolution, y_resolution)とサンプリング位置(raster_x, raster_y)から
ラスタ空間座標(ピクセル値)からUV座標(0.0~1.0)へ変換を行っています。
座標中心は左下のコーナーになります。
if文でUIパラメータ(vmirror)による水平方向に反転する場合としない場合でuval値を分岐しています。

④【回転マトリックスの作成】

前述のレンジ変換用関数:uv2rad()にて(0.0~1.0)のU値(RotY)を(π)へ,V値(RotX)を(-π/2π/2)の
Radian値へ変換し、RotZ=0と共にmi_matrix_rotate()関数にて回転マトリックス(matrix)を作成しています。

⑤【適切なレイベクトルの算出】
mi_vector_transform()関数によりレイベクトル(raydir)に④で求めた回転マトリックス(matrix)を掛けることで
回転後のベクトル(raydir_new = raydir * matrix)を算出しています。

⑥【変換後のベクトル方向へレイをキャスト】

miBoolean mi_trace_eye(
   miColor         *result,
   miState         *state,
   miVector        *origin,
   miVector        *direction)
//casts an eye ray from origin in direction. Lens shaders that depend on modifying
//ray origin and direction should be declared with the trace on option.
//Origin and direction must be given in internal space.
//This function may be used only in lens shaders.

ナンチャッテ【関数の日本語訳】: originからdirectionへeyeレイをキャストします。レンズシェーダーはトレースオプションをOnにする必要があり、
そのOriginとdirectionはインターナル空間として与えなければいけませんよ。またこの関数はレンズシェーダーでのみ使用されますよ~♪。

最後にこのmi_trace_eye()関数を使ってベクトル方向へレイを飛ばし結果を取得します。
その結果をシェーダーのResult値としてリターンして終了となります。


さてさていかがだったでしょう?
Mentalrayの関数もいろいろあるんですね~
これを機に自分もよりShaderWriting掘り下げてみたくなりましたぁ。ってまだ全然なんですけど(・・*)ゞ

トリロジーにまで及んだこの『◆移植オペ(上・中・下巻)◆』もこれにて終~了!(∩´∀`)∩ワーイ

まず【上巻】では、”ShaderWizrdによるMentalrayシェーダー移植術”と題し
SourceファイルからVisualStudioとShaderWizardを使いオリジナルコードまま移植する方法をご紹介しました。

続く【中巻】では、”シェーダー内部でどんな計算をしているのか見ちゃえ作戦!”と銘打ち
コードの中でどのような考え方を基に計算が行われているのか数式や関数を解説しシェーダーの内部をご紹介しました。

そしてこの【下巻】では、”latolong DE 拡張~チョットだけよっ♪~”と称して
シェーダーをより使い易くする為、別の手法による拡張を通してMentalrayShaderについてもうちょっと言及しました。

今回の記事を通して少しでもShaderやShaderWrittingについて皆さんのお役に立てれば光栄です。
長丁場にも関わらずお付き合い頂いた方、本当にありがとうざいました!
次回は”砂箱”をお届けする予定です。それではまた~ (v^-゚)チャオ♪

Some images are taken from the following books and Web sites.
mental ray Handbook Vol.3:Writing mental ray® Shaders: A Perceptual Introduction
http://www.writingshaders.com/
Special Thanks Andy! 😀

Pocket

コメント

コメントはありません

コメントフォーム

コメントは承認制ですので、即時に反映されません。ご了承ください。

*