«

[Unity] 2D Spriteにシェーダーをかける

今年の初めに、「Game a Week」という開発手法がすごい!っと書きました
とりあえず、週に一度は成果物を公開する、の部分を真似してみようかなと
(やってみて気が付きましたが、実は1週間って、結構長いです)

今をトキメクGame Engine: Unity について、去年から触る機会があり、ポチポチとやっております

そしてこれは既知の情報ですが、先週は2Dスプライトにシンプルなグラデーションのシェーダーを適用してみました

やってみると判るのですが、Unity ではスプライトにシンプルシェーダーだけを適用しようと思っても出来なくて、
先に結論を書いておくと、スプライトとして扱う場合は必ず何かしらのテクスチャアセットが必要でした
そのメモと感想文になります

2016年1月11日現在、Unityのバージョンは 5.3.1 です

Unity のシェーダー言語:ShaderLab

Unity のシェーダーは 「ShaderLab」 という Unity オリジナルのシェーダー言語で記載することになります
といっても HLSL のラッパーのような言語なので、Unity で使うときのお作法であり、Unity と シェーダーの仲介役の言語、と思って良いみたい

最小限の ShaderLab

最小限の ShaderLab の枠組みはこんな感じ
(これより削ると、エラーが出た)

// BG_shader.shader
// 最小限の ShaderLab
Shader "Custom/BG_shader" {
    SubShader
    {
        Pass {}
    }
}

実際に、このカスタムシェーダーをマテリアルに適用するとこんな感じ

何もしないマテリアルを作ることが出来ました

シンプルなグラデーション

今回、ゲーム背景を単純なカラーグラデーションにしようと思ったので、そういうシンプルシェーダーを書いていきます

// BG_shader.shader
// 黄色くグラデーションする
Shader "Custom/BG_shader" {
    SubShader
    {
        Pass{
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            // VS2015のグラフィックデバックON
            #pragma enable_d3d11_debug_symbols

            struct VertexInput {
                float4 pos:  POSITION;    // 3D空間座標
                float2 uv:   TEXCOORD0;   // テクスチャ座標
            };

            struct VertexOutput {
                float4 v:    SV_POSITION; // 2D座標
                float2 uv:   TEXCOORD0;   // テクスチャ座標
            };

            // 頂点 shader
            VertexOutput vert(VertexInput input)
            {
                VertexOutput output;
                output.v = mul(UNITY_MATRIX_MVP, input.pos);
                output.uv = input.uv;

                return output;
            }

            // ピクセル shader
            fixed4 frag( VertexOutput output) : SV_Target
            {
                float2 tex = output.uv;
                // 黄色→白色のグラデーション
                return fixed4( 1.0, 1.0, 1.0 - tex.y, 1.0);
            }

            ENDCG
        }
    }
}

ちょっとマテリアルではわかりにくいですけど、一応、線形にグラデーションされています

2D Sprite に適用する方法

シンプルなシェーダーとマテリアルが出来たので、実際に、Sprite に登録します

Sprite と Material だけでは足りない

ただし、ちょっとここでクセがあって、このマテリアルを Sprite にアタッチしても、何も起こりません
それどころか、ワーニングメッセージが…

Material does not have a _MainTex texture property. It is required for SpriteRenderer.

あら…
Sprite Renderer に登録するマテリアルには、テクスチャが必要ということみたいです
シェーダーに戻って、言われているとおり、 _MainTex にテクスチャを登録します

// BG_shader.shader の Properties を追加
    Properties
    {
        _MainTex( "2D Texture", 2D ) = "white" {}
    }

テクスチャを登録できるし、デフォルトでは white テクスチャを使いますよ。という意味になります
ちなみに、_MainTex() の内蔵テクスチャには

  • white
  • black
  • gray
  • bump

の4種類が用意されています
* ShaderLab: Properties - Unity Documentation
http://docs.unity3d.com/Manual/SL-Properties.html

マテリアルにテクスチャを持つ設定にしました

Sprite には、ベースとしてリアルな Texture が必要

Sprite のワーニングも消えたのですが、やはりシーンに Sprite object が表示されません

どうやら、Sprite はあくまで、テクスチャ画像を表示させるための機能に特化しており、マテリアルだけでは動作しない様です

仕方がないので、Sprite 用のテクスチャを用意します
サイズ感がよくわからなかったのですが、 white.jpg という 8*8 のテクスチャを Assets の下に入れました

Sprite の Inspector にて、Sprite Rendere > Sprite にて white テクスチャを選択します

あぁ…これ、デフォルトで白いテクスチャくらい、システムで用意してほしいなかと思いましたが、まぁしょーがないです

でたー

まとめ

シンプルな 3D model では

  • Mesh Renderer
    Material (たとえば Standard Shader)
     → Texture

という構造なので、

2D Sprite では

  • Sprite Renderer
    Material or Texture

なのかなーと思っていたのですが、実際には

  • Sprite Renderer
    Material
     → Texture (Shader の _MainTex() )
    Sprite
     → Texture (リアル画像)

という構造が必要でした

これを受けて、

「え、シンプルなシェーダーのみを適用したいなら、
Sprite でなくて 3D Plane Model にしたらいいんでない?」

という疑問が出てきましたが、
実際のゲーム制作においては、シチュエーション依存ですかね…
今回のわたしの場合は、Sprite を採用しました

この記事の Unity プロジェクト(ソース、アセット)を Github に置いておきます
https://github.com/h-sao/UnitySampleCode/tree/master/SpriteGradationalShader

何かの参考になれば幸いです

comments powered by Disqus