Unityを使ってシェーダーを作る方法を学ぶ連載。今回は、シェーダーによる色の変更、発光、光沢を持たせない設定について紹介する。
Unityを使ってシェーダーを作る方法を学ぶ連載「Unityで始めるシェーダー入門」。連載第1回ではシェーダーの概要と作り始めるまでの環境構築を紹介し、前回はシェーダーで黄金色に輝く3Dキャラクターを作成した(図1)。
今回は、図1とは全く逆で、光沢のない3Dキャラクター(図2)を作成したり、3Dキャラクターの色をInspectorの画面上で変更しり、発光させたりする処理を紹介する。基本的に、前回作成したシェーダーの一部をカスタマイズするだけで実現できる。各処理について1つずつシェーダーを作成するので、コードの違いなどを見比べながら理解していってほしい。
連載第1回で作成しておいたShadersフォルダ内に「Standard NonMetallic Shader」というシェーダーを作成する。Materialsフォルダ内には「Standard NonMetallic Materila」というマテリアルを作成する。
作成した「Standard NonMetallic Shader」をダブルクリックすると、コードエティタが起動しシェーダーのコードが表示される。これは前回、前々回のリスト1と全く同じ内容のコードになっているはずだ。
このコードをリスト1のように修正する。
Shader "Custom/Standard NonMetallic Sahder" { Properties { _Color ("Color", Color) = (1,1,1,1) _AmbientColor("Ambient Color", Color) = (1,1,1,1) //【1】 _MySliderValue("This is a Slider", Range(0,10)) = 2.5 //【2】 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM #pragma surface surf Standard fullforwardshadows #pragma target 3.0 sampler2D _MainTex; struct Input { float2 uv_MainTex; }; half _Glossiness; fixed4 _AmbientColor; //【3】 float _MySliderValue; //【4】 void surf (Input IN, inout SurfaceOutputStandard o) { o.Albedo = fixed3(1.0, 0.5, 0.4); //【5】 } ENDCG } FallBack "Diffuse" }
コメントで番号がある行が今回変更した箇所だ。順に説明する。
「Properties」内にある【1】は、「_AmbientColor」というプロパティの変数名で、Inspector内に「Ambient Color」という白い四角形が表示されてカラーピッカーで色の選択が可能になる(図3)。Ambient Colorは「環境光」のことだ。今回の内容には直接関係はないが、どのように表示されるかの参考にしてほしい。
【2】では、Inspector内に「This is a Slider」というプロパティの変数名で、0〜10までの範囲のスライダーを表示している。初期値は「2.5」としている(図3)。これも今回の内容には直接関係はないが、Inspector内でどのように表示されるかの参考にしてほしい。
【3】では、_AmbientColorプロパティを「fixed4」型として宣言している。RGBAの4原色が含まれるのでfixed4の型を使用している。
【4】では、「_MySliderValue」プロパティをfloat型として宣言している。今回はスライダーの数値のため、単にfloat型で宣言している。
ここまで書いてくるともうお分かりだろうが、Properties内で指定したプロパティ名を使用する場合は、再度、型として宣言しておく必要がある。この点を気にとめておいてほしい。
通常型を宣言したプロパティはsurf関数内で使用するのだが、今回はシェーダーの書き方と表示のされ方を基本的に解説している。よって、surf関数内では、単に緑色をo.Albedoに指定する処理だけしか行っていない。型宣言したプロパティも一切使用はしていない。
25〜27行目ではsurf関数を定義し、【5】ではsurf関数内のo.Albedoに直接色を指定している。「0,1.0,0」がRGBの値で緑色を表している。3原色のカラー値で、Albedoに代入するためfixed3型にしている。
色の指定についてはUnityのレファレンスを参照してほしい。
今回、一番重要な部分は、このsurf関数の箇所だけだ。他は、Inspector内でどのように表示されるかを確認するのに記述しているだけなので、非常に簡単で分かりやすいのではないだろうか。
このMaterialをInspectorで表示させると図3のように表示される。緑色が適用されて表示されている。
今回はAlbedoにコードで緑色を指定しているため、Colorで色を選択しても反映はされないので、注意してほしい。Inspectorから選択した色を反映させるには、前回のリスト1のような記述方法に従う必要がある。
また、Ambient Colorで色を選択しても、「This is a Slider」のスライダーを動かしても、特に何も変化は起きない。これらは、このように表示されるという見本だと思ってほしい。
このStandard NonMetallic MaterialをScene画面内の残りの3Dキャラクター(Ehtan)に適用すると、Game画面に図4のように表示される。単なるGreen表示で金属的な光沢が全くないのが分かるだろう。
次に、Inspectorから3Dキャラクターの色を変更するシェーダーを作成する。キャラクターの色を指定する方法はリスト1と似ているが、先ほどは、色はシェーダーのコードの中に直接書いていた。ここでは、カラーピッカーから選択できるようにしている。
結果を先に掲載しておこう。図5のような表示になるシェーダーを作成する。
Unityのメニューから「File」→「New Scene」と選択して、新しいScene画面を表示しよう。Shadersフォルダを選択して、マウスの右クリックで表示されるメニューから「Create」→「Shader」→「Standard Surface Shader」と選択する。新しく作成されたShaderには「AddColorShader」と名前を付けておこう。
次に、同じくMaterialsフォルダを選択して、マウスの右クリックで表示されるメニューから「Create」→「Material」と選択する。新しく作成されたマテリアルには「AddColorMaterial」と名付けておこう。
AddColorMaterialを選択して、Inspectorを表示させてみよう。「Shader」の位置に先ほど作成したAddColorShaderが「Custom/AddColorShader」として関連付けられている。通常は、Standard Surface Shaderとして作成したシェーダーは「Custom」というグループ名が付いて表示される。
AddColorShaderの中身は、リスト2のようになる。
Shader "Custom/AddColorShader" { Properties{ _Color("Diffuse Color", Color) = (1,1,1,1) //【1】 } SubShader{ Tags{ "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf Lambert //【2】 struct Input { //【3】 float4 Dummy; //【3】 }; //【3】 float4 _Color; void surf(Input IN, inout SurfaceOutput o) { o.Albedo = _Color.rgb; //【4】 } ENDCG } FallBack "Diffuse" }
コメントで番号がある行が前回、前々回のリスト1から変更した箇所だ。順に説明する。
【1】では、2〜4行目のPropertiesの中で「_Color」プロパティを定義して、Inspector内でカラーピッカーを表示させる白い四角形を表示させる。
【2】では、関数名「surf」で、ライティングモデルオプションを「Lambert」と指定している。Lambertは、「ランバート反射」のことで、拡散反射光で影によってオブジェクトが立体に見えるようにする表現方法だ。
【3】のInput構造体は、本来なら不要なのだが、この記述がないとエラーになるので、今回はダミーのデータを指定している。
14行目では「float4 _Color」と記述して、surf関数内で使用できるように、プロパティ名の_Colorをfloat4(RGBA)型で宣言している。
【4】では、プロパティ変数やInput構造体で定義された内容を入力として、サーフェースシェーダーの出力構造体SurfaceOutputの内容を出力する。
16行目のsurf関数内では、「inout SurfaceOutput o」と指定している。連載第2回やリスト1で出てきた「SurfaceOutputStandard」ではないことに注目してほしい。
SurfaceOutputは、基本的に、表面のプロパティ(アルベド、色、法線など)を記述する場合に使用する。Unityによって、あらかじめ下記のように定義されている。
struct SurfaceOutput { fixed3 Albedo; /* ベース(ディフューズまたはスペキュラ)カラー、デフォルトは黒*/ fixed3 Normal; /* 法線。デフォルトは設定なし*/ fixed3 Emission; /* 表面から放出される光の色と強度を制御する*/ half Specular; /* 0〜1の範囲の鏡面反射パワー*/ fixed Gloss; /* 鏡面強度*/ fixed Alpha; /* 不透明度(0〜1)、デフォルトは0*/ };
「法線」については、Unityにオンラインレファレンスを参考にしてほしい。
リスト1の【5】で、o.Albedoに代入する値を「_Color.rgb」に変更する。これで、カラーピッカーから選択した色が、「Diffuse Color」(拡散色)に反映されるようになる。
AddColorMaterialを選択してInspectorを表示させるとDiffuse Colorの四角い四角形が表示されるので、クリックしてカラーピッカーを表示させて緑色を選択する(図6)。今回は黄緑色を選択しているが、各自がいろいろな色を選択して表示を確認してほしい。
この黄緑色が反映されたマテリアルをScene上の3Dキャラクターにドラッグ&ドロップすると、図5のように表示される。
影が付いて立体感のある表示になっている。これは、9行目で「#pragma surface surf Lambert」と指定しているからだ。
最後に、3Dキャラクターを発光させるシェーダーを紹介する。最初に結果を掲載しておこう(図7)。
Unityのメニューから新しいSceneを作成する。いつものように、Shadersフォルダ内に「EmissionShader」という名前のシェーダーを、Materialsフォルダ内に「EmissionMaterial」という名前のマテリアルを作成する。
EmissionShaderの中身は、リスト3のようになる。
Shader "Custom/EmissionShader" { Properties{ _Color("Diffuse Color", Color) = (1,1,1,1) _MyEmissionColor("Emission Color",Color) = (0,0,0,0) //【1】 } SubShader{ Tags { "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf Lambert float4 _Color; float4 _MyEmissionColor; //【2】 struct Input { //【3】 float2 Dummy; //【3】 }; //【3】 void surf (Input IN, inout SurfaceOutput o) { o.Albedo = _Color; //【4】 o.Emission = _MyEmissionColor; //【5】 } ENDCG } FallBack "Diffuse" }
コメントで番号がある行が前回、前々回のリスト1から変更した箇所だ。順に説明する。
【1】は、表面から放出される光の色と強度を制御するプロパティの設定だ。初期値はBlackとなる。
【2】では、Emission(表面から放出される光の色と強度)は「RGBA」の4色になるので、float4型として宣言している。必ずプロパティで指定した同じ名前である必要がある。プロパティで受け取ったデータをsurf内で使うための定義だ。
【3】のInput構造体は、リスト2と同様、ダミーの値を指定している。
【4】では、ベースカラーの「o.Albedo」に「_Color」というプロパティ名を指定してInspectorから選択された色を指定している。
【5】では、「o.Emission」に「_MyEmissionColor」というプロパティ名を指定して、これもInspectorから選択された色を指定している。
Materialsフォルダ内の「EmissionMaterial」を見てみよう、既に「Custom/EmissionShader」がひも付けられていて図8のようなInspectorの表示になる。
カラーピッカーから図9のような色を選択してみた。
Scene画面上に3Dキャラクターを配置し、EmissionMaterialを適用すると図7のように表示される。周囲がEmission Colorで発光しているのが分かるだろう。
今回はこれで終わりだ。3通りのシェーダーの書き方を見てきたが、ここまでなら初心者でもそんなに難しくはないだろう。もともと基本のシェーダーは作成されているので、自分が実現したい処理を追加するだけでいい。しかし、その自分が実現したい処理を追加するにはどう書けばいいのかが初心者のうちは分からない。これは、シェーダーをいろいろ書いて、数をこなして経験を積んでいく以外にないだろう。本連載では、できるだけ多くのサンプルを紹介するので、参考にしていただきたい。
次回は、テクスチャを張り付けたり、透明度を変更したり、「法線マップ」を使ってオブジェクトに模様を表示させたりしてみるので、お楽しみに。
薬師寺 国安(やくしじ くにやす) / 薬師寺国安事務所
薬師寺国安事務所代表。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.