[Unity] マテリアルとシェーダーについて/裏面も表示する

  • Unityでのマテリアルとシェーダーについて
  • Unityでシェーダーを拡張する (カリングをオフにする、法線マップの反映)

今回はUnityでの説明となります。
Unityでのマテリアル(Material)とシェーダー(Shader)について。

Shade3Dでは「表面材質」または「マスターサーフェス」に相当するものが「マテリアル」になります。
形状に割り当てる、色や模様(テクスチャ)などの材質情報ですね。
マテリアルを作成した直後では「Standard」というシェーダーが割り当てられています。

マテリアルに割り当てるパラメータを定義し、入力値に対する出力値をプログラムで与えるものを「シェーダー」と呼びます。
ここでの入力値は、形状の表面上の位置やテクスチャ、材質を調整するパラメータなどを指します。
プログラムで計算した最終的な色情報を出力値とし、シェーダーの最後で渡します。
この一連の流れを与えるプログラムは、GPU上で実行されることになります。
ハードウェアで計算して並列実行するために、リアルタイムですごい表現ができるわけですね。
マテリアルをカスタマイズする手段がシェーダー、と言ってもいいかもしれません。
形状の表面だけでなく、スクリーン全体にシェーダーをかけることも可能です。

「Standard」というシェーダーは、PBR(Physically Based Rendering、物理ベースレンダリング)という物理的により厳密になるように計算する手法を使用しています。
大部分はStandardシェーダーでマテリアルを表現できますが、用途によっては別のシェーダーを使用しないと表現できない場合があります。

裏面も描画するには ?

さて、前回のリンゴを葉の裏から見ると葉が消えてしまいます。

これは、UnityのStandardシェーダーは裏面を表示する際に「カリング」するためです。
「カリング」とは、裏面と判明した場合はレンダリングしないという工程です。
リアルタイムでは速度を稼ぐために、デフォルトでは裏面を描画しない場合が多いです。

裏面を描画したい場合は、シェーダーを別のものにする必要があります。

「Nature/Tree Soft Occlusion Leaves」のシェーダーを使用

Unityには標準で、「Nature」という木や幹などを表現するためのシェーダーがあらかじめ用意されています。
まずはこれを使用してみましょう。
マテリアルの「Apple_leaf」をProjectウィンドウで選択し、Inspectorウィンドウを表示します。
「Shader」からポップアップメニューを出し、「Nature」-「Tree Soft Occlusion Leaves」を選択します。
これでシェーダーが切り替わりました。

「Main Texture」に葉のテクスチャを指定します。これは、Standardシェーダーでの指定がそのまま継承されています。

これで以下のように裏面も表示されました。

ただ、このシェーダーは法線マップがなかったりPBRではないため、Standardシェーダーをベースとして新たにシェーダーを作ってみることにします。

Standardシェーダーを派生させたシェーダーを作る

シェーダーはテキストエディタでプログラムを書くことになります。
Projectウィンドウで「Shaders」フォルダを作成し、その中にシェーダーファイルを置くことにします。
Projectウィンドウを右クリックし、ポップアップメニューから「Create」-「Shader」-「Standard Surface Shader」を選択します。
「standard_cullOff」と名前変更しました。

この「standard_cullOff」のアイコンをダブルクリックすると、テキストエディタが起動します。

内容は以下のようになっています。

Shader "Custom/standard_cullOff" {
  Properties {
    _Color ("Color", Color) = (1,1,1,1)
    _MainTex ("Albedo (RGB)", 2D) = "white" {}
    _Glossiness ("Smoothness", Range(0,1)) = 0.5
    _Metallic ("Metallic", Range(0,1)) = 0.0
  }
  SubShader {
    Tags { "RenderType"="Opaque" }
    LOD 200
    
    CGPROGRAM
    // Physically based Standard lighting model, and enable shadows on all light types
    #pragma surface surf Standard fullforwardshadows

    // Use shader model 3.0 target, to get nicer looking lighting
    #pragma target 3.0

    sampler2D _MainTex;

    struct Input {
      float2 uv_MainTex;
    };

    half _Glossiness;
    half _Metallic;
    fixed4 _Color;

    void surf (Input IN, inout SurfaceOutputStandard o) {
      // Albedo comes from a texture tinted by color
      fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
      o.Albedo = c.rgb;
      // Metallic and smoothness come from slider variables
      o.Metallic = _Metallic;
      o.Smoothness = _Glossiness;
      o.Alpha = c.a;
    }
    ENDCG
  }
  FallBack "Diffuse"
}

先頭の「Properties」という箇所が入力パラメータです。
色、ベースのテクスチャ(Albedo)、スムーズ、メタリックが用意されてます。
SubShader内の「LOD 200」の次の行に「Cull Off」を追加します。

  SubShader {
    Tags { "RenderType"="Opaque" }
    LOD 200
    Cull Off   // <== 追加.

これでUnity Editorに戻ると、シェーダーは自動で「コンパイル」されます。
「コンパイル」とは、テキストとして記述したプログラムをGPUが理解しやすい形に変換する処理です。
記述に間違いがある場合は、Consoleウィンドウにエラー内容が表示されます。

作成したシェーダーをマテリアルに割り当て

Projectウィンドウで「apple_leaf」を選択し、Inspectorウィンドウの「Shader」でシェーダーを指定します。
「Custom」-「standard_cullOff」が選択できるようになってますので選択します。

これで葉の裏面も表示されるようになりました。

法線マップをシェーダーに追加

葉のマテリアルとしては、Shade3D側で法線マップも渡してますのでこれも反映しましょう。
「standard_cullOff」シェーダーをテキストエディタで開き、拡張していきます。

以下は全ソースコードです。「追加」とコメントしている箇所が追加した部分です。

Shader "Custom/standard_cullOff" {
  Properties {
    _Color ("Color", Color) = (1,1,1,1)
    _MainTex ("Albedo (RGB)", 2D) = "white" {}
    _NormalMapIntensity ("Normal Intensity", Float) = 1    // <== 追加.
    _NormalMap("Normal Map", 2D) = "bump" {}        // <== 追加.
    _Glossiness ("Smoothness", Range(0,1)) = 0.5
    _Metallic ("Metallic", Range(0,1)) = 0.0
  }
  SubShader {
    Tags { "RenderType"="Opaque" }
    LOD 200
    Cull Off
    
    CGPROGRAM
    // Physically based Standard lighting model, and enable shadows on all light types
    #pragma surface surf Standard fullforwardshadows

    // Use shader model 3.0 target, to get nicer looking lighting
    #pragma target 3.0

    sampler2D _MainTex;
    sampler2D _NormalMap;    // <== 追加.

    struct Input {
      float2 uv_MainTex;
    };

    half _Glossiness;
    half _Metallic;
    fixed4 _Color;
    half _NormalMapIntensity;    // <== 追加.

    void surf (Input IN, inout SurfaceOutputStandard o) {
      // Albedo comes from a texture tinted by color
      fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
      o.Albedo = c.rgb;
      // Metallic and smoothness come from slider variables
      o.Metallic = _Metallic;
      o.Smoothness = _Glossiness;
      o.Alpha = c.a;

      // 追加.
      o.Normal = lerp( float3(0,0,1), UnpackNormal(tex2D(_NormalMap, IN.uv_MainTex)), _NormalMapIntensity);
    }
    ENDCG
  }
  FallBack "Diffuse"
}

Propertiesに以下の2つを追加しました。

    _NormalMapIntensity ("Normal Intensity", Float) = 1    // <== 追加.
    _NormalMap("Normal Map", 2D) = "bump" {}        // <== 追加.

これは、法線の強さを_NormalMapIntensityとして指定、法線マップを_NormalMapとして指定する入力パラメータになります。

SubShader内で「sampler2D _NormalMap;」「half _NormalMapIntensity;」を記述することで、入力パラメータをシェーダー内で参照できるようにします。

o.Normal = lerp( float3(0,0,1), UnpackNormal(tex2D(_NormalMap, IN.uv_MainTex)), _NormalMapIntensity);

「o.Normal」に法線情報を渡すことで、凸凹を表現できるようになります。

Unity Editorに戻ると、「standard_cullOff」を指定したマテリアルのパラメータとして、法線の強さと法線マップテクスチャを指定できるようになりました。

凸凹も反映されています。

このような感じで、Standardシェーダーで物足りない点がある場合はシェーダーのプログラムを書いて拡張していくことが可能です。

今回は、Unityにおけるマテリアルとシェーダーについての説明でした。
Unityについてのシェーダーの書き方の詳細については、Unity公式の「シェーダーリファレンス」をご参照くださいませ。

次回は最適化について書いていきます。

カテゴリー: Unityに形状を渡す