おもちゃラボ

Unityで遊びを作ってます

【Unityシェーダ入門】ポリゴンの表面と裏面に別テクスチャを貼る

UnityでPlaneにテクスチャを貼って普通に回転させると、裏面が透明になってしまいます。これを防ぐためにカリングをオフにしたシェーダを作りました。

nn-hokuson.hatenablog.com

このように、カリングをオフにすることで、両面ともテクスチャを表示することができます。この記事ではもう一歩すすめて、表面と裏面で違うテクスチャを貼る方法を紹介したいと思います。
f:id:nn_hokuson:20180220203042p:plain

ポリゴンが裏面か表面かを判定する

ポリゴンが表向きか裏向きかはポリゴンの頂点を指定する順番で決まります。詳しくは次の記事を参考にして下さい。

nn-hokuson.hatenablog.com

Unityのシェーダでポリゴンが表向きか裏向きかを判定するには、フラグメントシェーダにfacingという引数を追加します。facingはfixed型の値で0以上なら表面、0未満なら裏面を表します。
f:id:nn_hokuson:20180220200802p:plain:w550

このfacing変数を使ってポリゴンの向きに応じてテクスチャを割り当てます。

ポリゴンの向きを判定するシェーダを作る

まずはシェーダファイルを作成しましょう。プロジェクトウィンドウで右クリックし、Create→Shader→Unlit Shaderを選択して、reverseible.shaderという名前で保存してください。また、作成したreversible.shaderを右クリックしてCreate→MaterialでUnlit_reversible.matというマテリアルを作成しておきます。

f:id:nn_hokuson:20180220200817p:plain:w200

続いて作成したreversible.shaderに次のプログラムを入力してください。

Shader "Unlit/reversible"
{
    Properties
    {
        _MainTex ("Texture", 2D)    = "white" {}
        _MainTex2("Texture2", 2D) = "white"{}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
        Cull off

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 3.0

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            sampler2D _MainTex2;
            float4 _MainTex_ST;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos( v.vertex );
                o.uv = v.uv;
                return o;
            }
            
            fixed4 frag (v2f i, fixed facing : VFACE) : SV_Target
            {                
                return (facing > 0 ) ? tex2D(_MainTex, i.uv) : tex2D(_MainTex2, i.uv);
            }
            ENDCG
        }
    }
}

ポリゴンの両面を表示するため、今回も「Cull off」を指定してカリングをしないように設定しています。

頂点シェーダでは頂点座標とテクスチャのUV座標を受け取り、ワールド座標に変換して出力しています。UV座標はフラグメントシェーダに受け渡しています。

フラグメントシェーダでは引数に頂点シェーダからの構造体のほか、facing引数を追加しています。このfacing > 0の場合はポリゴンが表面、facing <= 0の場合はポリゴンが裏面を向いています。

そこで、facingの値をみて、ポリゴンが表向きであれば_MainTexを使用し、裏向きであれば_MainTex2を使用しています。

マテリアルとテクスチャを割り当てる

シェーダプログラムができたら、マテリアルをPlaneにドラッグ&ドロップして割り当ててください。

f:id:nn_hokuson:20180220201116j:plain

また、マテリアルには表面用のテクスチャを裏面用のテクスチャを指定する必要があります。ヒエラルキーウインドウでPlaneを選択した状態で、インスペクタの_MainTexと_MainTex2にテクスチャをドラッグ&ドロップしてください。

f:id:nn_hokuson:20180220201822j:plain

実行して、Planeを回してみるとポリゴンの表面と裏面で別々のテクスチャが表示されていることが確認できると思います。

f:id:nn_hokuson:20180220202752g:plain:w500