読者です 読者をやめる 読者になる 読者になる

お米 is ライス

C#やらUnityやらを勉強していて、これはメモっといたほうがええやろ、ということを書くつもりです

Unityでパーティクルをドット絵風にするShader

この記事はKMC Advent Calendar 2016の十一日目の記事です。
昨日はnona7さんのあたらしくrootになったみなさまへ - /dev/nona (いっと☆わーくす!)でした。

おはこんばんちは。私は京大マイコンクラブ(以下KMC)に所属するspi8823と申します。
今回は表題の通り、UnityのParticleSystemをドット絵風にする方法についてお話しします。

理由

あなたはUnityというものを使ったことがあるでしょうか?
Unityというのはゲームを作るための開発環境のことで、とても高機能ですがお金儲けをするのでなければ無料で使用することのできる素晴らしいサービスです。
このUnityを使用すれば3Dグラフィックスなゲームをとても簡単に作ることができます。もちろん、2Dのゲームも同じように簡単に開発することができます。
さて、このUnityではゲーム中に描画される様々なエフェクト(炎の燃え盛る様子や、剣が空を切る軌跡など)を作成する機能として「Particle System」というものが用意されています。
これを用いると例えばこのようなものが作成できます。
gyazo.com
UnityではこのParticle Systemに用いるための炎や煙の画像があらかじめ用意されています。
しかし、これらはもともと3Dグラフィックスのゲームで用いるために用意されたもので、画像のサイズは256*256ほどあります。これをドット絵を使用した2Dゲーム内で用いようと思っても、周りのドット絵とうまくなじまないため、少なからず不自然な印象を与えてしまいます。
そこで、3Dグラフィックスゲームのために用意されたParticle System用の画像を2Dドット絵ゲームで使用するために、高解像度の画像をドット絵風にしてしまう描画機能を作ってしまおうと思い至ったわけです。

Shader

さきほど「高解像度の画像をドット絵風にしてしまう描画機能」といいましたが、このように何かをスクリーン上に描画する処理を行っているものを「Shader」といい、プログラムを書いてこの処理を指定することのできる言語を「シェーディング言語」といいます。
今回は、このシェーディング言語のうち、「GLSL」というものを書いてドット絵風のパーティクルシステムを実現することにします。

用意するもの

Unityは各自でインストールしていただくとして、Unityで作成したプロジェクトの中に用意するものを列挙します。

Shaderスクリプト

Projectビューを右クリックし、「Create→Shader→Standard Surface Shader」を選択して新しいShaderスクリプトを作成しましょう。ファイル名はなんでもいいのでとりあえず「DotPaintingParticleShader」とでもしておきましょうか。

Material

Projecyビューを右クリックし、「Create→Material」を選択して新しいMaterialを作成しましょう。ファイル名はなんでもいいのでとりあえず「DotPaintingParticleMaterial」とでもしておきましょう。

適当なパーティクル用画像

使用したい画像を自分で用意するなり、UnityのStandardAssetsのParticle Systemをインポートしたりしましょう。

やること

UnityでGLSLを使用できるようにする

まず初めに、UnityでGLSLを使用できるようにしなければなりません。
そのため、どこかにUnityの実行ファイルのショートカットを作成し、そのショートカットファイルのプロパティからリンク先の末尾にスペースを入れてから「-force-glcore40」と追記してください。
このショートカットを使用してUnityを開けばUnityでGLSLを使用できます。

Shaderスクリプトをコピペする

先ほど用意した「DotPaintingParticleShader」をダブルクリックしてください。なんらかのテキストエディタが開かれるはずです。
その中のテキストをすべて削除し、代わりに以下のスクリプトを貼り付けてください。

Shader "Custom/DotPaintingParticleShader"
{
	Properties 
    {
        _TextureWidth ("TextureWidth", int) = 32
        _TextureHeight("TextureHeight", int) = 32
        _ColorResolution("ColorResolution", int) = 16
        _MainTexture("MainTexture", 2D) = "white"{}
	}
	SubShader 
    {
        Tags
        {
            "Queue" = "Transparent"
        }
        Pass
        {
            Cull Back
            ZWrite Off
            
            BlendOp Add
            Blend SrcAlpha OneMinusSrcAlpha
            
            GLSLPROGRAM
            uniform int _TextureWidth;
            uniform int _TextureHeight;
            uniform int _ColorResolution;
            uniform sampler2D _MainTexture;
            
            #ifdef VERTEX
            out vec4 textureCoordinates;
            void main()
            {
                gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
                textureCoordinates = gl_MultiTexCoord0;
            }
            #endif
            
            #ifdef FRAGMENT
            in vec4 textureCoordinates;
            void main()
            {
                float x = floor(textureCoordinates.x * _TextureWidth) / _TextureWidth;
                float y =  floor(textureCoordinates.y * _TextureHeight) / _TextureHeight;
                vec4 color = texture2D(_MainTexture, vec2(x, y));
                float r = floor(color.r * _ColorResolution) / _ColorResolution;
                float g = floor(color.g * _ColorResolution) / _ColorResolution;
                float b = floor(color.b * _ColorResolution) / _ColorResolution;
                float a = floor(color.a * _ColorResolution) / _ColorResolution;
                gl_FragColor = vec4(r, g, b, a);
            }
            #endif
            
            ENDGLSL
        }
	}
}

詳しいことは省きますが、このスクリプトでは画像内の座標や色の値の解像度を下げる、ということを行っています。

MaterialにShaderを適用

では次に、「DotPaintingParticleMaterial」をインスペクタで開いて、その上に先ほどの「DotPaintingParticleShader」をドラッグ&ドロップしてください。
そうするとこのような表示になると思います。
gyazo.com
そして、MainTextureという項目に、用意したパーティクル用の画像を適用してください。

適当なパーティクルを作成する

ヒエラルキビューを右クリックして「Particle System」を選択してください。
新しいパーティクルがゲーム上に出現したと思います。
このパーティクルの上に作成したMaterialをドラッグ&ドロップしてください。
そうするとどうでしょう、いい感じに粗くなったパーティクルが表示されたのではないでしょうか?

では、この方法を使わない場合と、この方法を使った場合のサンプルを以下に置いておきます。

  • 使用しない場合

gyazo.com

  • 使用した場合

gyazo.com

作成したMaterialの、TextureWidthやColorResolutionといった項目を編集することで、描画する際の「粗さ」を調節することができます。


ではみなさんも、このShaderを利用して快適なドット絵ライフを送りましょう!???
明日は、id:sorahさんの記事です。

KMCM

さて、今回使ったシェーディング言語というものですが、やはりこれもプログラミング言語ですのでいきなり初心者が使おうと思い立っても簡単に使えるものではありません。
私がこの記事のようなShaderを書くことができたのも、KMCにてGLSLの勉強会を行ったからです。
つまり、KMCに来ればこんなShaderが書けるようになるということです!!!
KMCは京都大学の学生だけでなく、すべての「コンピュータで何かをしたい人」に対して開かれています。
興味が沸いたという方はぜひ気軽にツイッター(京大マイコンクラブ(1日目西ほ40-b) (@KMC_JP) | Twitter)やメール(info@kmc.gr.jp)で連絡してみてください。
また、京大マイコンクラブ (KMC)から例会の日程などを確認することもできます。

最後に

パーティクル用にって思って書いたけど、よく考えたら(よく考えなくても)このShader、パーティクルに用途限ってないような気がする。。。。。。

おまけ

今回はUnityのバージョン5.3を使ったけど、最近バージョン5.5が正式にリリースされました。
バージョン5.5では今回使ったパーティクルシステムが結構アップグレードされたほか、「Collabolate」という機能が追加されたりもしました。
このCollabolateという機能を使えば、Gitなどのバージョン管理システムを使用せずともゲームプロジェクトのメンバー内での共有ができるようになります。
今までUnityプロジェクトの共有にGitを使ってきた人は知っていると思いますが、UnityとGitは相性があまりよくないことで知られていますが、Collabolateを使えばその不自由さから解放されるようです。
後日、別途このCollaborateに関する記事を書きたいと思います。