【Unity】 簡単に水に近い表現を実現したい (Metaball)

1 はじめに

こんにちは、カヤックのソーシャルゲーム事業部のmadaです。この記事はカヤックUnityアドベントカレンダー2018の22日目の記事です。

「Lion Studios」が作成した「Happy Glass」というゲームを遊んでみて、液体の表現に興味を持ちました。この記事では「簡単に水に近い表現を実現したい」話をします。

IMAGE ALT TEXT HERE

Happy Glass - Lion Studios- Youtube

2 Metaball?

調べてみると水の表現に、Metaballという手法が使えそうでした。Metaballの説明をしようとすると数式が出てくるので、先に実装した結果を紹介します。2つの水滴が接近したときに水滴がひっつくような表現が、なんとなくできているのではないでしょうか。

f:id:kayac-mada:20181221151922g:plain

2DのMetaballを数式で説明すると、以下の式になります。画面上の(x,y)ピクセルを塗るときに、式の条件を満たしている場合塗る、そうでない場合塗らない、と制御します。例として2つのメタボールが存在するときの2次元の等高線グラフも作成してみました。

f:id:kayac-mada:20181221151929p:plain

f:id:kayac-mada:20181221151932p:plain

3 Metaballの実装概要

早速Metaballを実装していきましょう。実装するのは先程紹介した数式です。数式を分解し、3ステップに分けて紹介します。

3.1 ShaderでΣ内の計算

Σ内の計算を実装します。数式は以下の通りです。Shaderで実装するので、出力を画像のRGBAにする必要があり、_Scale, _Clip という調整用パラメーターを用意しています。frag関数の中で、uvの中心(0.5, 0.5)からの距離を色に変換しています。今回は後から調整しやすいようにShaderで実装しましたが、調整用パラメーターが定まれば画像データにしてしまっても良いところです。

f:id:kayac-mada:20181221151936p:plain:h80

Shader "Metaball/MetaballParticle" {
Properties
{
    _Color ("Color", Color) = (1,1,1,1)
    _Scale ("Scale", Range(0,0.05)) = 0.01
    _Cutoff ("Cutoff", Range(0,05)) = 0.01
}

SubShader
{
    Tags
    {
        "Queue"="Transparent"
        "IgnoreProjector"="True"
        "RenderType"="Transparent"
        "PreviewType"="Plane"
    }

    Cull Off
    Lighting Off
    ZWrite Off
    Blend One OneMinusSrcAlpha

    Pass
    {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #pragma multi_compile_fog

        #include "UnityCG.cginc"

        struct appdata_t
        {
            float4 vertex   : POSITION;
            float4 color    : COLOR;
            float2 texcoord : TEXCOORD0;
        };

        struct v2f
        {
            float4 vertex   : SV_POSITION;
            fixed4 color    : COLOR;
            float2 texcoord : TEXCOORD0;
        };

        sampler2D _MainTex;
        fixed4 _Color;
        fixed _Scale;
        fixed _Cutoff;

        v2f vert(appdata_t IN)
        {
                v2f OUT;
                OUT.vertex = UnityObjectToClipPos(IN.vertex);
                OUT.texcoord = IN.texcoord;
                OUT.color = IN.color * _Color;
                return OUT;
        }

        fixed4 frag (v2f i) : SV_Target {
            fixed2 uv = i.texcoord - 0.5;
            fixed a = 1 / (uv.x * uv.x + uv.y * uv.y);
            a *= _Scale;
            fixed4 color = i.color * a;
            clip(color.a - _Cutoff);

            return color;
        }
     ENDCG
     }
}
}

f:id:kayac-mada:20181221151941p:plain:w300

3.2 カメラとRenderTextureでΣの実装

つぎにΣの実装を行います。3.1でΣ内の計算出力を画像にしたので、Σの実装はn個のMetaballを描写するだけです。次の処理で必要なのでCameraの出力はRenderTextureに設定しておきます。

f:id:kayac-mada:20181221151944p:plain:h80

f:id:kayac-mada:20181221151947p:plain:w300

f:id:kayac-mada:20181221151950p:plain:w300

3.3 ShaderでThresholdの実装

次にthresholdの実装を行います。実装は3.2で出力したRenderTextureを描写するShaderのfrag関数の中で、clip(color.a - _Cutoff);を呼ぶだけです。内側と境界に異なる色を設定できるように、clip関数の後に条件分岐を設定しています。

f:id:kayac-mada:20181221151953p:plain:h80

Shader "Metaball/MetaballRenderer" {
Properties
{
    _MainTex ("MainTex", 2D) = "white" {}
    _Color ("Color", Color) = (1,1,1,1)
    _Cutoff ("Cutoff", Range(0,1)) = 0.5
    _Stroke ("Storke", Range(0,1)) = 0.1
    _StrokeColor ("StrokeColor", Color) = (1,1,1,1)
}

SubShader
{
    Tags
    {
        "Queue"="Transparent"
        "IgnoreProjector"="True"
        "RenderType"="Transparent"
        "PreviewType"="Plane"
    }

    Cull Off
    Lighting Off
    ZWrite Off
    Blend One OneMinusSrcAlpha

    Pass
    {
    CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #pragma multi_compile_fog

        #include "UnityCG.cginc"

        struct appdata_t
        {
            float4 vertex   : POSITION;
            float4 color    : COLOR;
            float2 texcoord : TEXCOORD0;
        };

        struct v2f
        {
            float4 vertex   : SV_POSITION;
            fixed4 color    : COLOR;
            float2 texcoord : TEXCOORD0;
        };


        sampler2D _MainTex;
        half4 _Color;
        fixed _Cutoff;
        fixed _Stroke;
        half4 _StrokeColor;

        v2f vert(appdata_t IN)
        {
            v2f OUT;
            OUT.vertex = UnityObjectToClipPos(IN.vertex);
            OUT.texcoord = IN.texcoord;
            OUT.color = IN.color * _Color;
            return OUT;
        }

        fixed4 frag (v2f i) : SV_Target
        {
            fixed4 color = tex2D(_MainTex, i.texcoord);
            clip(color.a - _Cutoff);
            color = color.a < _Stroke ? _StrokeColor : _Color;
            return color;
        }
    ENDCG
    }
}
}

f:id:kayac-mada:20181221151957p:plain:w300

成果物

以上で2DのMetaballのRenderingができるようになりました。ボールにColliderを付けて上から落としてみた画像を貼ります。まぁまぁ水に近い表現ができていると思います。比較的に簡単にできるのでタイトル通り、「簡単に水に近い表現が実現できた!」と言い切っておきます。

f:id:kayac-mada:20181221152001g:plain

簡単に上のシーンの構成を紹介します。

1. 「MetaBallLayer」のみを描写する「MetaBallCamera」を作成します。
2. 単体Metaball(水玉)を描写するために空のPrefabを作成します。
3. Prefabに(3.1)で紹介したShaderで描写するQuadを作成します。
4. Prefabのレイヤーを「MetaBallLayer」に設定します。
5. (3.2)で紹介したように、「MetaBallCamera」のRenderTargetにRenderTextureを設定します。
6. RenderTextureを「MainCamera」に描写するQuadを作成します。
7. ステージ(黒い棒)にColliderを付け、MainCameraで描写します。
8. 単体MetaballのPrefabを大量にInstantiateし、物理挙動に任せます。

※ Quadは UnityMenu > GameObject > 3D Object > Quad から生成できます

明日は?

明日は目からビームが出ている漫画名刺の「アファトさん」による「Compute ShaderでランタイムにSDFテクスチャーを生成するエクスペリメント」です。明日の記事もお楽しみに!

JetBrains IDE を使うなら覚えておきたい 10 の tips

こんにちは!技術部の小池です。

Tech KAYAC Advent Calendar 2018 の22日目を担当させていただきます。

はじめに

みなさんお手元の開発環境/エディタは何をお使いですか?私は数年前まで iOS 開発は Xcode、Android 開発は Android Studio、サーバサイド開発は Sublime Text 2 と複数の開発環境を使い分けていましたが、環境ごとに脳内キーバインドを切り替えるのが苦痛でもう無理だわ〜〜ってなったので JetBrains IDE に統一しています。

IntelliJ IDEA をはじめとする JetBrains IDE はプロダクトがたくさんあり一見わかりにくいのですが、ほとんどは IntelliJ IDEA と、IntelliJ IDEA に言語プラグインを同梱したものです。Golang 用の GoLand、C# 用の Rider、C/C++ 用の CLion、Objective-C 用の AppCode 等は IntelliJ IDEA + プラグイン形式ではなく独立したプロダクトとして開発されています(他にも Visual Studio 向けのプロダクトもあります)。しかし各 IDE はキーマップがほぼ共通のため環境の違いを意識せずに使うことができます。とっても便利。

今年の夏頃に JetBrains 社に日本チームができたので日本語でもサポートが受けられるようになりました。また Eclipse の日本語化も行っている WillBrains 社による日本語化も進んでおり、日本語でも十分使えるようになってきていると思います。

最近弊社で Rider や GoLand を使い始めた方が増えているので JetBrains IDE 共通で使える tips を紹介しようと思います。

ショートカットキーはキーバインドごとに違うのでここでは記述しません。以下のように Preferences で機能名からショートカットキーを検索することができますので参考にしてください。

preferences

Search Everyware

多分どのキーバインドでも shift キーを2回押すと出てくる超便利機能です。ファイル、クラス、シンボル、IDEの機能まであらゆるものを爆速サーチしてくれます。困ったらこれを使って探す癖をつけると良いです。サーチウィンドウ右上の Include non-project items にチェックを入れる(さらに shift キーを2回押す)とプロジェクトが依存している外部パッケージも検索することができます。

include_non_project_items

たとえば GoLand であれば Golang の標準パッケージのソースをプロジェクトのソースと一緒に検索できます。

Settings Repository

あまり使っている方を見ないのですが、Settings Repository を使うとローカルの 設定を GitHub 上で同期させることができます。会社のマシンでも家のマシンでもストレスなく設定を最新に保つことができます。dotfiles を GitHub 上で管理するのと同じような感じですね。他にも JetBrains サーバを使って設定を同期させる方法もありますが、たまに動作が不安定になるので私はずっとこちらを使っています。

Key Promoter X

プラグインです。ショートカットキーを使わずにメニューを開いてコマンドを実行する怠惰なエンジニアにショートカットキーを叩き込んでくれるのがこの Key Promoter X です。たとえば ⌘ + C のコピーを右クリックメニューから選んで実行すると以下のようなウィンドウが右下に出てきてショートカットキーを教えてくれます。

key_promoter_x

このコマンドはマウスで実行するぞ!というものがあれば個別に ignore することもできます。

Edit Custom VM Options

JVM のヒープサイズを変更できます。デフォルトでは大きなプロジェクトではインデクシングに結構時間がかかる程度にはサイズが小さいので、どかどかっと大きくしてしまいましょう。また、Preferences -> Appearance の項目の Show memory indicator にチェックを入れると右下にメモリ使用量が表示されるようになります。

Show Intention Actions

実行するとカーソル上の構文ごとに最適なアクションを提案してくれます。警告が出てるところでは警告を解消するためのアクションが、何も警告がないところではよりよいコードにするためのアクションがあれば提示されます。私は警告が出てたらとりあえずこれを使うようにしています。

show_intention_action

Jump to Source

クラスやメソッドの定義元に飛んでいくやつです。他の IDE でもよくある機能ですが、ジャンプした履歴を保持しており、Back 機能でジャンプした定義元から呼び出し元のコードに戻ることができます。爆速でコードを往復できます。

Quick Definition

カーソル上のクラスやメソッドの定義元の実装をチラっと見ることができます。ジャンプするほどではないけどちょっと見たいときに便利です。

quick_definition

Parameter Info

カーソル上のメソッド呼び出しコードの引数の型を見ることができます。GoLand を使っているときに特に重宝します。

parameter_info

Presentation Assistant

プラグインです。使用したショートカットキーを画面に表示してくれます。普段はあんまり意味がないですが、プレゼン中など他の人に画面を見せるときに使用するといい感じの演出になるのでおすすめです。

Productivity Guide

自分がよく使う機能と使わない機能を一覧で出してくれます。ミーティングの合間等に眺めてみるとほほう、となります。私の Productivity Guide はこちら。

productivity_guide

おわりに

ざっくりとしてしまいましたが tips の紹介でした。JetBrains IDE には他にも膨大な機能があるので色々お試しください〜。

明日は iemon さんによる 「matter.js or M5stack or その他」です!おたのしみに〜