お米 is ライス

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

ASP.NET Core 3.0+Blazorで詰まったとこ

この記事の目的

ASP.NET Core 3.0とBlazorを使っていい感じのサーバーを作ろうとしているので気づいたことを適宜メモしていくための記事

コントローラークラスの作成

    [Route("api/[controller]")]
    [ApiController]
    public class HogeController : ControllerBase
    {
        private FugaContext Context { get; }
        public HogeController(FugaContext context)
        {
            Context = context;
        }

        [HttpGet]
        public async Task<ActionResult<IEnumerable<Hoge>>> GetHoge()
        {
            return await Context.Hoges.ToListAsync();
        }
    }

コントローラークラスはこんな感じのやつ

Startup.csに

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

これが書いてあればhttps://localhost:99999/api/HogeとかでAPIにアクセスできる

選択したコードジェネレータを実行中にエラーが発生しました

Scaffolding failed to edit Startup class to register the new Context using Dependency Injection.
Make sure there is a Startup class and a ConfigureServices method and Configuration property in it.

Blazor(ASP.NET Core hosted)のプロジェクトを作ってサーバー側のプロジェクトに適当なコントローラーをスキャフォールディングしようとしたら怒られたエラー。

これはStartup.csクラスにConfigurationというプロパティが無いので怒られている。
どうやらこのへんのスキャフォールディングはパターンマッチ的なことがされていて、Startupクラスとかが正しい形でないと怒られるみたいだ。
幸い、Blazor(サーバーサイド)のプロジェクトを作るとConfigurationとかがちゃんと書かれたStartupクラスが吐かれるのでそれを参考にするとちゃんとスキャフォールディング(いちいち書くのめんどくさい……)できた。

Blazor(ASP.NET Core hosted)のこういうコードを

public class Startup
{
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().AddNewtonsoftJson();
        services.AddResponseCompression(opts =>
        {
            opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "application/octet-stream" });
        });
    }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseResponseCompression();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseBlazorDebugging();
        }

        app.UseClientSideBlazorFiles<Client.Startup>();

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapDefaultControllerRoute();
            endpoints.MapFallbackToClientSideBlazor<Client.Startup>("index.html");
        });
    }
}

下記のように書き直してやろう(ダジャレじゃないよ)

public class Startup
{
    public IConfiguration Configuration { get; }

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().AddNewtonsoftJson();
        services.AddResponseCompression(opts =>
        {
            opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "application/octet-stream" });
        });
    }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseResponseCompression();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseBlazorDebugging();
        }

        app.UseClientSideBlazorFiles<Client.Startup>();

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapDefaultControllerRoute();
            endpoints.MapFallbackToClientSideBlazor<Client.Startup>("index.html");
        });
    }
}

あくまで個人的な感想だが、最近のC#(というかASP.NETってそういうもんなのか?)はパターンマッチに傾倒しすぎてて、「型安全!」「安心!!」みたいなプログラマに優しい言語からだんだんと離れて行ってしまってるような気がしてう~~ん……。

データベースへのアクセス

何も考えずにコントローラーをスキャフォールディングすると、ついでに作るDbContextへのConnectionStringがappsettings.jsonに追加される。
このConnectionStringはいい感じのローカルSQLサーバーへの接続を表している。が、このままだとコントローラーへAPIで問い合わせてもSQLサーバーに入れませんでしたというエラーが出る。
なので初めにまずマイグレーションというやつをして、次にそのマイグレーションを使ってデータベースを初期化しないといけない。
それをするにはプロジェクトのディレクトリへ行き、Power shellとかで次のようなコマンドを打つ。

dotnet-ef migrations add initial-migration //多分、いい感じのマイグレーションをいい感じに生成する魔法の言葉
dotnet-ef database update          //多分、マイグレーションを使ったデータベースの初期化

ところでマイグレーションってなんだ……?

injection

テンプレートで生成されたrazorページの中を見ている「@injection hogehoge」というのがあった。
調べてみるとこれを使うことでStartup.csの中で登録したシングルトンにアクセスできるらしい。
詳しくは
ASP.NET Core でのビューへの依存関係の挿入 | Microsoft Docs
とか
ASP.NET Core MVC を使ってドロップダウンリストをいい感じに実装する - しばやん雑記
とか。

とにかく
Startup.csに

public void ConfigureServices(IServiceCollection services)
{
    ~~
    services.AddSingleton<HogeSingleton>();
    ~~
}

と書いておけば

@injection HogeSingleton hogeSingleton

みたいにしてrazorファイルからアクセスできる。

Html.DisplayFor、Html.EditorFor

あるインスタンスをいい感じに編集できるような機能はないかなあと思っていたところ、これまたテンプレートで「Entity Frameworkを使用するRazorページ(CRUD)」を作ってみたらIndex.cshtmlの中に書いてあった。
DisplayForはその名の通りそのインスタンスをいい感じに表示する関数で、EditorForはそれが編集できるようになってるもの。
クラスのプロパティとかにアトリビュートで[DisplayName("hogehoge")]とか書けばある程度は指定もできるみたいだ。
このページが詳しい。
第6回 テンプレート機能でビュー開発を効率化(1/3) - @IT


ASP.NET Core 3.0のプレビュー版でmigrationしようとしたらうまくいかなかったときの対処法

現象

dotnet-ef migrations add initial-migration

このmigration用のコマンドを実行しようとするとこんなことを言われる

The application to execute does not exist: 'hogehoge\.dotnet\tools\.store\dotnet-ef\2.2.4-servicing-10062\dotnet-ef\2.2.4-servicing-10062\tools\netcoreapp2.2\any\dotnet-ef.dll'.

原因はCore 3.0で実行してるのにEntityFrameworkのCore 2.2のほうを実行しようとしてるから(だと思う)

対処法

古いほうをアンインストールしてからCore3.0版をインストールする

dotnet tool uninstall dotnet-ef --global
dotnet tool install --global dotnet-ef --version 3.0.0-*


今年の目標

  • 神社へいっぱい行く
  • SRPGをいいとこまで持っていく
  • 曲をいっぱい作る
  • 今まで作った曲に歌詞をつけてあげてちゃんと公開する
  • 女性に慣れる
  • お絵かきの練習をする
  • 小説を書く
  • ゲームをいっぱいする
  • アニメをちょっとでも見る
  • 早起きをして普通の生活をする
  • 美味しいものをいっぱい食べる
  • 楽しいことをいっぱいする

UnityのCoroutine的なものを自前で実装する

Coroutine

コルーチンはこんな感じで使えるやつだ

void Awake()
{
    StartCoroutine(Test());
}

IEnumerator Test1()
{
    DoSomething();
    yield return null;
    Hoge();
    yield break;
}

コルーチンのネストもできて

void Awake()
{
    StartCoroutine(Test2())
}

IEnumerator Test2()
{
    Debug.Log("1");
    yield return null; 
    Debug.Log("2");
    yield return StartCoroutine(Test3())
    Debug.Log("3");
    yield break;
}

IEnumerator Test3()
{
    Debug.Log("A");
    yield return null;
    Debug.Log("B");
    yield break;
}

こんな感じにすると1, 2, A, B, 3の順で出力される(たぶん)。

Coroutineの問題点

この記事の目的はあくまで「実装してみよう!!」というものであり問題点を指摘することが目的ではないが、実装への動機づけのために言及しておく。

イテレータから何が返ってくるかわからな

イテレータをネストしているとき、つまりTest2関数の中でTest3関数を呼んでいるようなことをしているときの話である。
例えばTest3の中でのある処理が成功したか失敗したかをTest2で知る必要があったとしよう。
それを知るにはTest3の最後にyield return falseなどとしてやればよい。
しかしさらにTest3の中からさらにTest4へとネストしたい場合、yield return StartCoroutine(Test4())ともしてやらなければならない。
こうなった場合、関数の返り値の型をIEnumerator<bool>などと指定することは不可能となり、単にIEnumeratorと書かなければならなくなる。
そうするともはやイテレータから何が返ってくるのかがわからなくなり、あるいは無法地帯のような状況になってしまうかもしれない。
そうならないためにも、UnityにおけるCoroutineのようなものを自前で用意しようということなのである。

実装

というわけで、自前で実装してみたのがこちらになります。 gist.github.com

こうしておくとイテレータが何返してくるのかわかって安心だよねーという話でした。
意外と簡単に実装できますね。

使い方

こんな感じで使うよー\(^o^)/

private Iterator iterator;
private bool flag = false;

void Awake()
{
    iterator = new Iterator();
}

void Update()
{
    iterator.Progress();
}

IEnumerator<IteratorResult> Hoge()
{
    yield return IteratorResult.Continue;
    yield return IteratorResult.Nest(Fuga());
    yield return IteratorResult.Completed;
}

IEnumerator<IteratorResult> Fuga()
{
    yield return IteratorResult.Continue;
    if(!flag)
    {
        yield return IteratorResult.Canceled;
        yield break;
    }
    
    yield return IteratorResult.Completed;
}

まとめ

UnityのCoroutineを自前で実装してみたよ! 他にいい方法があったら教えてくり!!

鵜飼さんをたどって

ここで一句

このブログ、ソースはほとんどウィキペディア

鵜飼さんとは

これまで記紀に関する調べ物をしていて気になっていたことがあります。
それは、何らかの(戦闘と関係があるとは思えない)職掌を持っている人たちがやたらと出てきて活躍することです。
その中でも顕著だと思ったのが、神武東征神話の中に登場する"久米歌"といわれる何編かの長歌です。
この歌は第二次世界大戦の折に戦意高揚のため使われた「撃ちてしやまむ」という言葉のもととなっている歌であり、「敵を打ち負かしてやろう!!」という心意気のこもった歌となっています。
しかし、山椒の実で口をヒリヒリさせたり、韮の芽を根っこから引き抜いていたりと、およそ戦っているとは思えないような比喩が頻繁に使われています。
というのも、昔は戦闘を生業にする人々などほとんど存在せず、普段は農業や漁業によって生計を立てていた人々がいざというときに戦っていたからで、そういった人々の活躍を表現するためにこのような比喩が使われたのでしょう。
したがって、この比喩の部分を注意深く見てやることでどこの誰がその時に活躍したのかということが見えてきそうです。

さて、そこで久米歌の一つ、

楯並めて 伊那佐の山のこの間よも い行きまもらひ戦へば
吾はや飢ぬ 島つ鳥鵜養が伴 今助けに来ね
<現代語訳>
楯を並べて伊那佐の山の木の間を通って行きながら、敵の様子を見守って戦ったので、
我々は腹がへった。鵜養部の者どもよ、今すぐ助けに来てくれ。

http://amanokuni.blue.coocan.jp/kumeuta.htmより)

という歌に注目してみます。
この歌では伊那佐という山で戦っているときに鵜飼部という人たちに助けを求めています。
ここから、久米氏という宇治族のうち鵜飼部というおそらくは鵜飼を生業としていた人々が伊那佐という土地に住んでいたことがわかります。
鵜飼とは文字通り鵜(う)という鳥を飼っている人々のことで、鵜を操って魚を捕ることから、「腹が減った」といって助けを求めるのもうなずけます。
あとは伊那佐がどこなのか、ということですが、奈良県宇陀市に伊那佐村があるとのこと(伊那佐村 - Wikipedia)なのでおそらくここのことでしょう。

久米氏について

ここで久米氏という人々について少し説明しておきます。
久米氏については久米氏・山部氏が詳しいのですが、もともと九州のほうにいた人々で主に漁業を生業としていた海の民です。
熊本県の"クマ"、球磨川の"クマ"、熊襲の"クマ"という音と久米氏との関係も気になります。
というのも、古代における日本語では母音が変わっても同じ言葉、あるいは近しい言葉であることがままあります。つまり"クマ"と"クメ"も変化しうるのです。
この「k〇m〇」という言葉に注目していると熊野大社の"クマ"や上賀茂神社下鴨神社の"カモ"、はたまた神の"カミ"など、さまざまな言葉との関係を疑えて楽しいです。

鵜飼さんの出身地

記紀の別の記述によると、

梁を作つて魚を取る者有り、天皇これを問ふ。対へて曰く、臣はこれ苞苴擔の子と、此れ即ち阿太の養鵜部の始祖なり

鵜飼い - Wikipediaより)

ということで、阿太という(おそらくは)地名とも関係があることがわかります。("アダ"という音を聞くと宇陀市の"ウダ"という音との関係を疑いたくなってしまいます)
この"アダ"という地名ですが、別の神話においても登場します。
天孫降臨神話においてニニギがコノハナサクヤヒメと結婚をするのが阿多というところであり、引用元によればそれは薩摩半島西南部を広く表した地名であったということです。
inakaseikatsu.blogspot.jp
これらの"アダ"が同源であるとするならば、鵜飼さんは古くは九州地方でも活躍していたと捉えることができるのではないでしょうか。

神功皇后と鵜飼さん

神武東征の話において活躍する鵜飼さんですが、神功皇后とも少なからず関係をもっています。
というのも、三韓征伐の際に使用した船を和歌山県和歌山市にある紀三所神社(志磨神社・静火神社・伊達神社)という場所に祀ったという話があります。そしてWikpediaによると静火神社の神官は鵜飼さんが務めていたのだそうです。
この紀三所神社の近くには日前(ひの"クマ")神社や竈山("カマ"やま)神社などといった神社が存在しており、先に述べたロジックにより久米氏との関係もあるのではないかと思います。ということはこの鵜飼さんも久米氏の鵜飼さんなのではないでしょうか。
なぜ三韓征伐で用いた船をわざわざ紀伊の国までもっていったのか、なぜ鵜飼さんを神官としたのか、という疑問とともにこの話を再解釈するとかなり素直に次のようになるかと思われます。

神功皇后は海の民である久米氏の協力を大いに受け、三韓征伐に成功した。この久米氏の中には阿多からやってきていた鵜飼部も含まれていた。
三韓征伐ののち、大和入りの際にも神功皇后は久米氏に協力を仰ぎ、鵜飼部もこれに従った。
瀬戸内海を渡り畿内にたどり着いた神功皇后は紀の国をも掌握し、三韓征伐や大和入りなど諸々の功を労って鵜飼氏に紀三所神社周辺の土地を治めさせた。

ちなみに紀三所神社にほど近い海岸沿いにはこれまた神功皇后が祀ったことが始まりとされる淡嶋神社があります。

鵜飼さんをたどって

こうなってくると、神武東征に出てくる鵜飼さんと神功皇后により神官の地位を与えられた鵜飼さんとを繋げてみたくなってくるのが人情というものでしょう。
というわけで、奈良県宇陀市にある伊那佐村と和歌山県和歌山市にある静火神社とをグーグルマップで確認してみましょう。すると意外にも容易く両者を繋げることが可能であるとわかります。
www.google.com
そうです、JR和歌山線が通っています。という冗談はさておき、紀ノ川の上流と下流にそれぞれ位置していることがわかります。この紀ノ川のおかげで静火神社のある和歌山市から伊那佐村の手前となる五條市までは低地となっており、そのため交通が盛んであったのは想像に難くありません。また、古代においては河川を使った水路も非常に重要な交通手段であったので、紀ノ川を通じて往来があったのはもはや明確と言ってもいいでしょう。
つまり、紀三所神社周辺を与えられた鵜飼さんが紀ノ川を遡り内陸へと移住していったのが伊那佐村の鵜飼さんなのではないでしょうか?
あるいはもともと紀ノ川沿いを支配していた鵜飼さんに神功皇后が協力を仰ぎ、その見返りとして紀三所神社周辺の支配権の正当性を認められたというストーリーも考えられます。
この考えを補強するかのように、中間地点である奈良県五條市には阿田という地名が今でも残っています。

まとめ

神武東征における鵜飼さんと、神功皇后の大和入りにおける鵜飼さんとは元をたどれば同じ氏族であり、九州から紀三所神社周辺に移住したのち、紀ノ川沿いに伊那佐村周辺に展開していったのではないか。
この考えが正しいかを見極めるため、これら2点を結ぶ線上に存在する地名や神社、遺跡などの総合的な分析を今後の課題とする。

神社活動記録その1

一昨日と昨日、大学の学生支援機構から応募が出されていた祭礼バイトに行ってきた。

7月24日前半

7月24日の7時から12時半までは神社側の仕事で、花傘巡行という行事で六斎念仏保存会という団体が乗った車を市内中押して廻るというものだった。
念仏と言ってもにぎやかなもので、鐘が4人、太鼓が4人、笛が3人で文字で書くと「こんちきちんこんちきちん」というような調子の囃子だった。
歩道から溢れんばかりの見物客の押し合いへし合いとは無縁なところから至近距離でこういう行事を見られたのは非常に貴重な体験であった。

7月24日後半

7月24日、14時から23時までは三若(三条台若中)という、三条通の商店街周辺を中心とする、祇園祭のうちの神幸祭還幸祭の主体となっている団体のほうへ行き、神輿雑務の仕事をした。
神輿雑務は提灯を持つ係、スピーカーを持つ係、あぐら(神輿を置くための台)を扱う係、台車(神輿移動用)を運ぶ係の4つがあって、自分は台車係をすることになった。
台車は30キログラムほどのもので、それを3人がかりで運ぶという業務だったのでそれ自体は楽なものだったが、いかんせん何キロメートルもの行路を5時間も6時間もかけて神輿とともに歩いたので終わるころにはもうヘロヘロになっていた。
市内を巡回している間は神輿行列の最後尾、荷物を運んでいるトラックよりも後ろの位置にいたので神輿はあまり見ることができなかったが、22時ごろ神輿が八坂神社の境内に入ってからは神輿から数歩ほどしか離れていない、若衆による熱気の真っただ中で祭りを見ることができた。そこからは、観光客の目線からでは絶対に見ることができないような祭りのすさまじさ、熱さを感じられた。

7月25日

7月25日は昨日と同じ三若の集会所へ行き、9時半から16時まで御神酒受け取りという業務を行った。
御神酒受け取りとは、ほうぼうにいる支援者のところへ行き、奉賛金やお酒をもらって回るというものである。その際には謝礼として御供物という八坂神社から受け取ったお守りのようなものを渡すようになっている。
9時半に集会所へ行くと、まずはその御供物を作る作業から始まった。作るといっても、八坂神社からもらってきたちまきや丹波にある神田で刈り取った早稲とお札を一つの袋にまとめるというだけの作業である。
十何人かで手分けをし、600個の御供物を作った後は、それを配って回ることになった。自分は三若役員の爺様方に付き、四条大宮から四条烏丸までの間を回ることになった。奉賛者は個人商店からさる大企業の事務所まで、多岐にわたっていたが、地域が山鉾の順行路と被っているということもあり、数はあまり多くなかった。
四条烏丸まで行くとちょうど昼時だったので爺様方にお昼ご飯をごちそうしてもらい、いろんな話を聞くことができた。
昼食を終え、タクシーで集会所まで戻ると最後に集会所の片づけをすることになった。やることと言えば掃除機をかけたりブルーシートを片付けたりするだけなのだが、この集会所というのが築五十年は経っている昔ながらの古い京町屋で、その隅のほうまで見て回ることができたのでこれはこれでいい体験をすることができた。

以上が、神社活動記録その1である。

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に関する記事を書きたいと思います。