見出し画像

【MMEの作り方】シェーダーエフェクト編03/テクスチャの呼び出し方

▼今回の記事ページで使うサンプルファイル

 今回の記事ぺージの解説で使うサンプルとなるfxファイルは以下のリンクからダウンロードできます。
 ただし、ファイルをDL・使用した際にトラブル・不利益が生じたとしても筆者は責任を負わないものとします。自己責任で御利用ください。

▼これまでのコードを更に改良する

 これまでの記事ではシンプルな単色だったり、それに対して明暗を付けるコードを解説してきました。
 しかし、現実で使う3Dモデルの大半にはテクスチャが設定されていて単色のオブジェクトというのは少数派です。
 というわけで、この記事ではMME用のfxファイルでのテクスチャの取り扱いについて解説していきます。

▼元の材質に使われているテクスチャを呼び出す

■テクスチャを呼び出すための設定について

まず、オブジェクトの材質に元々テクスチャが設定されている場合にそのテクスチャを呼び出せるシェーダーエフェクトのコードを見てみましょう。
 サンプルファイルの『1-3-0_SampleCube.pmx』をMMD内にインポートして、『1-3-1_Texture_Mate.fx』を割り当ててみてください。

材質のテクスチャを使うシェーダー

 今回は元々のテクスチャを使いつつ、オブジェクトに青みを足す設定をしているのでオブジェクトがより深い青になりました。

 では、コードの中身を見ていきましょう。
 テクスチャの呼び出し関する処理は以下の箇所になります。

テクスチャの呼び出しに関する処理
texture = <MaterialTexture>;

 の部分で、元々の材質に設定されているテクスチャを呼び出しを行っています。
 その他の部分に関しても図に書き込んである通りです。
 とはいえ、上記の箇所については実は省略表現している部分があります。それはコード下段の、

MINFILTER = LINEAR;
MAGFILTER = LINEAR;

 の部分です。
 この部分、更に下の行に書き足せるものがありまして、省略せずに全体を書くと、

MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = CLAMP;
AddressV = CLAMP;

 となります。

 まず上3行について。

◎MinFilter
 テクスチャを縮小するときに使われる設定です。
 たとえば、遠くにある物体のテクスチャは画面上で小さく表示され、1ピクセルに複数のテクセル(テクスチャ上の画素)が対応します。
 そのときに「どのように平均化するか(ぼかすか)」を決めます。
 イコールで結ぶ先に設定できるものは以下の通り。
・LINEAR⇒周囲のテクセルを線形補間して平均化(なめらか)
・POINT⇒最近傍の1テクセルだけ使う(ぼやけない、カクカク)
・ANISOTROPIC⇒異方性フィルタリングを使い、斜めの角度でも高品質表示

◎MagFilter
 テクスチャを拡大するときに使われるフィルタ設定です。
 近くに寄ったときにテクスチャがぼやけたり、ギザギザしたりするのをどう処理するかを決めます。
 イコールで結ぶ先に設定できるものは以下の通り。
・LINEAR ⇒ 近くのテクセルを線形補間して拡大(なめらか)
・POINT ⇒ 最近傍の1テクセルをそのまま拡大(ドット絵風)

◎MipFilter
 どのミップマップレベルを使うかを補間する設定です。
 テクスチャには「ミップマップ」という解像度違いの画像が複数階層で格納されています。
 距離によって適切な解像度のレベルを選ぶと効率的で綺麗な描画ができます。
『MipFilter』はそのミップマップレベル間をどう補間するかを決めます。
 イコールで結ぶ先に設定できるものは以下の通り。
・LINEAR ⇒ 2つのミップマップレベルの間を線形補間して滑らかにする
・POINT ⇒ 最も近いミップマップレベルを選ぶ(補間なし)
・NONE ⇒ ミップマップを使わない

次に下2行について。

『AddressU』と『AddressV』は、UVマップの範囲外(0〜1の範囲外)になったときに、どう処理するかを指定する設定項目です。
 つまり「テクスチャの端を超えたときの描き方」を決める指定です。

 通常、テクスチャ設定に使うUV座標は、
・U方向(横) → 0.0~1.0
・V方向(縦) → 0.0~1.0
 の値を取ります。
 しかし、シェーダーや頂点計算の結果で、『UV = 1.2』や『UV = -0.3』 のように、1を超えたり0未満になったりすることがあります。
 このとき、テクスチャのサンプリングをどうするかを決めるのが『AddressU』と『AddressV』です。

『AddressU』と『AddressV』のそれぞれでイコールで結ぶ先に指定できるものは以下の通りです。

・CLAMP ⇒ 1以上や0未満は端のピクセルをそのまま伸ばす
・WRAP ⇒ 端を超えると最初に戻って、タイルのように繰り返す
・MIRROR ⇒ 反転して繰り返す 1を超えるたびに左右反転してタイル状に並べる
・BORDER ⇒ 範囲外は固定のボーダーカラー(BorderColor)で塗る

■テクスチャ使用に必要なUV座標をオブジェクトに指定する

 テクスチャを呼び出しただけではオブジェクトにテクスチャを張り付けることはできません。
 オブジェクト内でテクスチャを使うためには、オブジェクトがどのようなUVマップを持っているか指定する必要があります。
 それが頂点シェーダーの以下の部分です。

頂点シェーダーでのUV座標の指定

■テクスチャを実際に使用するための設定

 これまでの処理でテクスチャの呼び出しと、それを張り付けるためのUVマップの指定が完了しました。
 つまり準備完了です。
 最後にピクセルシェーダー内でオブジェクトにテクスチャの色を反映させます。

ピクセルシェーダーでのテクスチャの使用

▼フォルダ内のテクスチャ画像ファイルを呼び出す

 上述のfxファイルでは、オブジェクトに元々設定されているテクスチャを呼び出して使う処理をしました。
 次に、元々設定されているテクスチャではなく、fxファイルと同じフォルダ内に保存されている別のテクスチャを呼び出す方法を解説します。
「わざわざオブジェクトに設定されているのとは違うテクスチャを呼び出すの?」いう疑問が湧くかもしれませんが、これはこれで使い道があります。

 というのも、MMDモデルの材質でメインカラーを設定するテクスチャは1つしか指定できません。
 なので複数枚のテクスチャを使ったシェーダーエフェクトが作りたい場合は別枠で保存しておいたテクスチャを都度呼び出す必要があります。

 今回はfxファイルと同じフォルダ内の画像をテクスチャとして呼び出す処理を見てみましょう。
 サンプルファイルの『1-3-2_Texture_ExternalFile.fx』をご覧ください。
 ここでは同フォルダ内の『Tex_Sample01.jpg』という画像をテクスチャとしてオブジェクトに再設定します。

外部の画像をテクスチャを使った例
外部の画像をテクスチャとして呼び出す

 呼び出したテクスチャは、ピクセルシェーダーで先ほどの材質に元々設定されていたテクスチャを使う場合と同じような処理で使用することができます。

外部の画像をテクスチャとして使用

▼ノーマルマップを実装する

■ノーマルマップを実際に見てみる
 では次に、材質の元々のテクスチャと外部から呼び出したテクスチャを同時使用した例を見てみましょう。
 ここでノーマルマップという技法を紹介します。
 ノーマルマップ(法線マップ)とは、オブジェクトに疑似的な凹凸を設定するテクスチャを設定して少ないポリゴン数で起伏に富んだオブジェクトであるかのように見せる技法です。
 以下のgifアニメを見てください。

凹凸がある風の立方体

 ライトの向きを変えると立方体の各面の模様の様子が変わっているので一見すると凹凸があるようにも見えます。
 しかし、この立方体に近づいてみるとポリゴンとしては凹凸がありません。

本当は各面が平らな立方体

 このように疑似的な凹凸、そしてそれに伴い疑似的な明暗を表現できるのがノーマルマップです。
 主に少ないポリゴン数でリアリティがある見た目にするのに使用されます。

 では、コード内のノーマルマップの実装を実現する処理を見てみましょう。

ノーマルマップを実装するコード

 ノーマルマップのRGB値はタンジェント空間(Tangent Space)という特殊な座標系で表されます。
 タンジェント空間は、
・Normal(N) ⇒ 法線ベクトル:表面から垂直方向
・Tangent(T) ⇒ 接ベクトル:UV座標の「U方向」
・Binormal / Bitangent(B) ⇒ 従法線ベクトル:UV座標の「V方向」
 で作られています。

『Tangent』がないと、ノーマルマップの「U方向」「V方向」が実際のモデル上でどちらを向いているのか分からなくなります。
 つまり、ノーマルマップを正しく回転・変換できません。
 結果として光の当たり方がバラバラになり、法線が正しい方向を向かなくなります。

▼経過時間を変数に使ってUVスクロールを実装する

 本記事の最初の方で、ふわっとUV座標について解説しました。
 もう一度書いておくとUV座標とは、
・U方向(横) → 0.0~1.0
・V方向(縦) → 0.0~1.0
 の値を取るけれど、シェーダーや頂点計算の結果で、『UV = 1.2』や『UV = -0.3』のように、1を超えたり0未満になったりすることもある。

 というものでした。
 
 更に、テクスチャのサンプリングをどうするかを決めるのが『AddressU』と『AddressV』であり、これらをイコールで結ぶ指定の中には、

・WRAP ⇒ 端を超えると最初に戻ってタイルのように繰り返す

 という処理もありました。
 
 ということは、シームレスなテクスチャであるならばタイル状にリピートさせて無限にスライドさせ続けることが出来そうですよね。
 はい、出来ます。
 そういった技法をUVスクロールと言います。

 サンプルファイルの『1-3-0_SamplePlate.pmx』をMMDに呼び出し、それに『1-3-4_uvScroll.fx』をMMEで割り当ててみてください。
 実際にやってみたのが以下のgifアニメになります。

UVスクロールの例

 このように、タイルを永遠に指定した方向に流し続ける技法がUVスクロールです。
 ここではチェック柄のテクスチャを使っていますが、例えば水面を表現したテクスチャならポリゴンモデルを固定したまま流れる川を表現できたりします。

 fxファイル内のUVスクロールに関する処理は以下の通りです。

UVスクロールのための処理

▼画面に映っているものをテクスチャとして使う

 最後に画面に映っているものをテクスチャとして使う手法について紹介して、テクスチャ関連の解説を締めとします。

 これまでの解説では材質に設定されているか否かに関わらず、何かのpngファイルのような画像ファイルをテクスチャとして呼び出しオブジェクトに設定してきました。
 しかし、実はリアルタイムで画面に映っている画像自体をテクスチャであるかのように扱い、オブジェクトに張り付ける機能がMMEには存在します。
 サンプルファイルの『1-3-5_OffRenderTarget.fx』をご覧ください。

 このファイルでは、これまでテクスチャ設定に使っていた箇所が以下のようになっています。

OffRenderTarget

 これがリアルタイムで画面に映っている画像自体をテクスチャとして呼び出す設定です。

 しかし疑似的なテクスチャとして呼び出しただけではまだ使い物になりません。
 通常のテクスチャと同じようにUV座標を設定する必要があります。
 しかし、あくまで『疑似的な』テクスチャであるため、これまでのようなUV座標の指定ではちゃんと機能しません。
 そのためにカスタマイズされてたUV座標の指定方法が以下の図で示した通りの頂点シェーダーの処理になります。

OffRenderTarget用の頂点シェーダー

 で、ここまで来れば後はこれまでのテクスチャと同様にピクセルシェーダーの『Tex2D』で呼び出すだけとなります。

OffRenderTargetを使ったピクセルシェーダーの例

 今回は割り当てたオブジェクトの向こう側が白黒になって映る設定になるコードをピクセルシェーダーに書いています。
 なので、以下のような画像になります。

OffRenderTargetを使ったシェーダーエフェクトの例

目次ぺージに戻る


いいなと思ったら応援しよう!