連載
» 2018年04月12日 05時00分 公開

Unityで始めるシェーダー入門(4):シェーダーによるテクスチャ設定、透明度変更、法線マップでオブジェクトに凸凹模様を付ける

Unityを使ってシェーダーを作る方法を学ぶ連載。今回は、シェーダーによるテクスチャ設定、透明度変更、法線マップでオブジェクトに凸凹模様を付ける設定について紹介する。

[薬師寺国安,PROJECT KySS]

 Unityを使ってシェーダーを作る方法を学ぶ連載「Unityで始めるシェーダー入門」。連載第1回ではシェーダーの概要と作り始めるまでの環境構築を紹介した。今回はテクスチャを貼り付けたり、透明度を変更したり、「法線マップ」を使ってオブジェクト(3Dキャラクター)に凸凹模様を表示させたりしてみる。

 先に、法線マップを使ってどんなシェーダーを作成するかの見本を掲載しておこう(図1)。

図1 今回最後に作成する表面に凸凹模様を伴った3Dキャラクター

 シェーダーの作成の前に、連載第1回でインポートしておいた、「Ethan」という3DキャラクターをScene画面上に1体配置しておこう。カメラの位置やEthanの位置を調整して図2のような表示にしておく。

図2 Scene画面上にEthanを1体配置した。Game画面の確認もできる

テクスチャを指定するシェーダー

 まずは、Inspectorからテクスチャを指定するシェーダーを作成してみよう。結果を先に掲載しておく(図3)。

図3 テクスチャを適用した3Dキャラクター

 これまでの連載と同様に、「Shaders」フォルダに「TextureShader」という名前のシェーダーを作成し、「Materials」フォルダ内に「TextureMaterial」というマテリアルを作成する。

テクスチャを表示するシェーダーのコード

 TextureShaderをダブルクリックしてコードエディターを起動しシェーダーのコードを表示させる。これは前回、前々回のリスト1と全く同じ内容のコードになっているはずだ。

 コードをリスト1のように書き換える。

Shader "Custom/TextureShader" {
    Properties {
        _MyTexture("Select Texture",2D) = "White"{} //【1】
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        CGPROGRAM
        #pragma surface surf Lambert
 
        sampler2D _MyTexture; //【2】
 
        struct Input { //【3】
            float2 uv_MyTexture; //【3】
        }; //【3】
 
        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = tex2D(_MyTexture,IN.uv_MyTexture).rgb; //【4】
        }
        ENDCG
    }
    FallBack "Diffuse"
}
リスト1 TextureShaderのコード

 コードの中身については、今回もコメントで番号がある行だけ説明する。これまでの連載で取り上げたものは省略する。

 【1】は変数の型を2D(テクスチャ表示)として、Inspector内に「Select Texture」と表示させる設定だ。

 【2】は、プロパティで受け取ったデータをsurf関数内で使うための定義だ。2Dテクスチャの場合は「sampler2D」で定義する。以前のコードでは、ここのプロパティ名を「_MainText」としていた。プロパティ名は変えられるので、今回は「_MyTexture」としてみた。

 【3】ではInput構造体を宣言している。プロパティ名の前に「uv」と付けることで、自動的にマテリアルのテクスチャ座標設定(TilingとOffset)が適用されたUV座標が入ってくる。

 UV座標は「テクスチャ座標」ともいう。モデルの頂点座標にテクスチャのどの部分を描画するかを0〜1の値(UV座標)で表したものだ。

 【4】では、tex2D関数を使ってテクスチャを貼り付けている。UV座標(uv_MyTexture)からテクスチャ(_MyTexture)上のピクセルの色を計算し、o.Albedoに渡している。

実行結果

 Materials内のTextureMaterialを見てみよう。既にCustom/TextureShaderがひも付けられていて図4のようなInspectorの表示になる。

図4 TextureMaterialのInspector

 今の状態では、選択すべきテクスチャがないので、Asset Storeから無料の適当な「Materials and Texture」をインポートしておこう。筆者は、「Yughues Free Metal Materials」をインポートしておいた。

 すると、今インポートした各種テクスチャ(名前は全てdiffuse)が表示されるので、適当なものを選択する。筆者は図5の赤の四角形で囲ったものを選択した。

図5 テクスチャを選択した

 図2で配置した3DキャラクターにTextureMaterialをドラッグ&ドロップすると、図3のように表示される。

透明度を変更するシェーダー

 次は、透明度を変更するシェーダーを作成する。これも、先に結果を掲載しておこう(図6)。

図6 透明度の適用された3Dキャラクター

 Unityで新しいScene画面を開く。Shadersフォルダ内に「TransparentShader」という名前のシェーダーを作成し、Materialsフォルダ内に「TransparentMaterial」という名前のマテリアルを作成する。

透明度を変更するシェーダーのコード

 これまでと同様、Shadersフォルダ内のTransparentShaderをダブルクリックしてコードエディタを起動してコードをリスト2のように書き換える。

Shader "Custom/TransparentShader" {
    Properties {
        _MyTexture ("Select Texture", 2D) = "white" {}
        _MyAlpha("Alpha",Range(0,1))=1 //【1】
    }
    SubShader {
        Tags {"Queue"="Transparent" "RenderType"="Opaque" } //【2】
                
        CGPROGRAM
        #pragma surface surf Lambert alpha //【3】
 
        sampler2D _MyTexture;
        float _MyAlpha; //【4】
        struct Input {
            float2 uv_MyTexture;
        };
 
        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = tex2D(_MyTexture,IN.uv_MyTexture).rgb*_MyAlpha; //【5】
            o.Alpha = _MyAlpha; //【6】
        }
        ENDCG
    }
    FallBack "Diffuse"
}
リスト2 透明度を設定するTransparentShaderのコード

 コードの中身については、今回もコメントで番号がある行だけ説明する。これまでの連載で取り上げたものは省略する。

 Properties内の【1】では、型はRangeなので、0〜1の値を指定できるスライダーが表示される。Alphaの値をスライダーから選択することが可能になるのだ。

 【2】の透明度の設定をする場合のTagsは、このように書くものだと覚えておくだけでいい。

 【3】の#pragmaディレクティブの記述で透明化を設定するには、Lambertの後ろにalphaを付ける。

 【4】では、float型の変数名を宣言している。変数名はプロパティで定義した名前にする必要があるので気を付けてほしい。プロパティで受け取ったデータをsurf関数内で使うための定義だ。

 【5】のテクスチャの色は、透明度が上がるほど不透明になるように、選択されたテクスチャを「_MyAlpha」の値で乗算している。透明度を出力する【6】の「o.Alpha」には「_MyAlpha」(スライダーから指定したAlphaの値)を指定している。

実行結果

 Materials内のTransparentMaterialを見てみよう、既に「Custom/TransparentShader」がひも付けられていて図7のようなInspectorの表示になる。

図7 TransparentMaterialのInspector

 Selectボタンで適当なテクスチャを選択して、Scene画面上に3Dキャラクターを配置し、TransparentMaterialを適用させる。適用させた後図8のAlphaのスライダーを移動させると透明度を調節でき、図6のような表示になる。

法線マップでオブジェクトに凸凹模様を付けるシェーダー

 最後に、法線マップでオブジェクトに凸凹模様を付ける図1のようなシェーダーを作成する。

 これまで同様、「NormalMapShader」と「NormalMapMaterial」という名前のシェーダー、マテリアルを作成しておこう。

法線マップでオブジェクトに凸凹模様を付けるシェーダーのコード

 NormalMapShaderのコードをリスト3のように変更する。

Shader "Custom/NormalMapShader" {
    Properties{
        _MainTex("Bump", 2D) = "White"{} //【1】
    }
    SubShader{
        Tags{ "RenderType" = "Opaque" }
        CGPROGRAM
 
        #pragma surface surf Lambert //【2】
 
        struct Input { //【3】
            float2 uv_MainTex; //【3】
        }; //【3】
 
        sampler2D _MainTex; //【4】
 
        void surf(Input IN, inout SurfaceOutput o) {
            o.Albedo = fixed3(1.0, 0.1, 1.0); //【5】
            o.Normal = UnpackNormal(tex2D(_MainTex, IN.uv_MainTex)); //【6】
        }
        ENDCG
    }
    FallBack "Diffuse"
}
リスト3 NormalMapShaderのコード

 コードの中身については、今回もコメントで番号がある行だけ説明する。これまでの連載で取り上げたものは省略する。

 【1】では、Propertiesの中で、Inspector内で「Bump」と表示させて、変数の型を2Dとしてテクスチャを選択できるようにする。

 【2】で、関数名がsurfでライティングモデルオプションにLambertを指定している。Lambertは「ランバート反射」のことで、拡散反射光で影によってオブジェクトが立体に見えるようにする表現方法だ。Lambertを指定しているので、surf関数ではSurfaceOutput構造体を引数に指定している。

 【3】のInput構造体の中では、テクスチャの座標を表すfloat2で定義している。

 【4】のsampler2Dは、テクスチャの型(2D)を意味する。よって、プロパティ_MainTexはテクスチャ型であると宣言していることになる。プロパティで受け取ったデータをsurf関数内で使うための定義だ。

 【5】のAlbedoはInspector内で設定できるようにはしていない、ここでは固定でマゼンタ色を指定している。RGBの3原色なのでfixed3型で指定している。

【6】では、テクスチャを使用するために、tex2D関数を呼び出してUV座標(uv_MainTex)からテクスチャ(_MainTex)上のピクセルの色を計算し、組み込みのUnpackNormal()関数を使用してテクスチャをマップしている。

 UnpackNormal()関数を使うと、法線情報を正確に取得できる。これを用いて、ディフューズ(拡散)やスペキュラー(鏡面)を計算すれば、凸凹模様の表現が可能になるのだ。o.NormalはSurfaceOutputで定義されている法線を表すため、UnpackNormal関数で取得した法線情報を指定しているのだ。

実行結果

 NomarMapMaterialのInspectorを見ると、既にCustom/NormalMapShaderがひも付けられてテクスチャを選択する欄が表示される。色自体は固定でマジェンタを指定していたので、マジェンタの色で表示されている(図8)。

図8 NomalMapMaterialのInspector

 今回はテクスチャも自作してみよう。Photoshopなどで図9のような画像を作る。サイズは普通サイズ(筆者は300×300で作成)でいい。BMPファイルとして作成する。

図9 テクスチャに使用する画像

 筆者は名前「zu_03.bmp」とした。このファイルをAssetsフォルダにドラッグ&ドロップする。

 Assetsフォルダに取り込まれた、zu_03.bmpのInspectorを表示させ、TextureTypeに「Normal Map」を指定する。次に、「Create from Grayscale」にチェックを入れる。ここのチェックを忘れると凸凹にはならないので注意が必要だ(図10)。

図10 TextureTypeを選択し、「Create from Grayscale」にチェックを入れた

 図9の右隅下の「Apply」ボタンをクリックする。図10では既に「Apply」なのでグレー表示になっている。

 では、これで再度、NormalMapMaterialのInspectorを開いてテクスチャを選択してみよう。TilingのXに「20」、Yに「15」と指定する。ここの値を規定値のままにしていると、うまく柄が表示されないので注意してほしい(図11)。

図11 NormalMapMaterialのInspectorからテクスチャを選択する

 先ほどPhotoshopで作成したBMP画像がテクスチャとして選択できたはずだ。

 では、このマテリアルをScene上の3Dキャラクターに適用してみよう。図12のように表示される。

図12 3Dキャラクターの表面に凸凹のテクスチャが貼り付いた

次回は「頂点・フラグメントシェーダーで3Dキャラクターの一部の色を変える」

 今回もシェーダーのプログラムの中身を解説してみた。このように、シェーダーが書けるようになると、自分の好きなテクスチャを作成して、オブジェクトに適用できるようになる。コンテンツの表現力の幅が広がるだろう。

 初心者には、一度見ただけでは理解しにくいかもしれない。しかし、何度も読んでいくと自然と分かってくるものだ。とにかく自分で手を動かして、見よう見まねでいいからシェーダーのプログラムを書くことが大切だと思う。「こう書けばInspector内でこのように表示できるのだ」ということを確認しながら書いていくと、結構面白く新しい発見もあるはずだ。

 Unityを使用すると、シェーダーの基本的なコードは自動的に作成されるのでユーザーの負担は非常に軽くて済むメリットがある。ただし、これは「あくまでも基本的なコードである」ということを忘れてはならない。

 またWeb上にはUnityのシェーダーに関する情報はたくさんあるので、もっと高度な処理を希望される方は、Webの情報を参考にするのもいいかもしれない。本連載は、Unityでシェーダーを使ったさまざまな表現を行うための手順を覚えるものだと思って読んでほしい。

 次回は「頂点・フラグメントシェーダーで3Dキャラクターの一部の色を変える」方法について解説する。お楽しみに。

参考書籍

著者プロフィール

薬師寺 国安(やくしじ くにやす) / 薬師寺国安事務所

薬師寺国安事務所代表。Visual Basicプログラミングと、マイクロソフト系の技術をテーマとした、書籍や記事の執筆を行う。

1950年生まれ。事務系のサラリーマンだった40歳から趣味でプログラミングを始め、1996年より独学でActiveXに取り組む。

1997年に薬師寺聖とコラボレーション・ユニット「PROJECT KySS」を結成。

2003年よりフリーになり、PROJECT KySSの活動に本格的に参加。.NETやRIAに関する書籍や記事を多数執筆する傍ら、受託案件のプログラミングも手掛ける。

Windows Phoneアプリ開発を経て、現在はWindowsストアアプリを多数公開中。

Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。

Microsoft MVP for Development Platforms - Windows Phone Development(Oct 2012-Sep 2013)。

Microsoft MVP for Development Platforms - Client Development(Oct 2013-Sep 2014)。

Microsoft MVP for Development Platforms-Windows Platform Development(Oct 2014-Sep 2015)。


Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。