【Unity】「HIT」のログイン時のようなエフェクトをつくる
HITとは?
NEXONが出してるスマホゲームです。UE4製で綺麗なグラフィックのアクションゲームです。
mobile.nexon.co.jp
ログイン時のエフェクトってどんなの?
実装方針
まずこんな画像を用意します。
こういうのはパーリンノイズが向いてる気がするので、パーリンノイズで生成しました。
色を高さと見なして、こんな風にしたらそれっぽいのができそうですね!
(図は Processing で生成しました)
EffectVisualize.pde · GitHub
実装
シェーダの全体像です。
Shader "Custom/LoginEffectShader" { Properties { [PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {} _MaskTex("Mask Texture", 2D) = "white" {} _Height("Height", Float) = 0 } SubShader { Tags { "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" "PreviewType" = "Plane" "CanUseSpriteAtlas" = "True" } Blend One OneMinusSrcAlpha Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 2.0 #pragma multi_compile _ ETC1_EXTERNAL_ALPHA #include "UnityCG.cginc" struct appdata_t { float4 vertex : POSITION; float4 color : COLOR; float2 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct v2f { float4 vertex : SV_POSITION; fixed4 color : COLOR; float2 texcoord : TEXCOORD0; UNITY_VERTEX_OUTPUT_STEREO }; v2f vert(appdata_t IN) { v2f OUT; UNITY_SETUP_INSTANCE_ID(IN); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); OUT.vertex = UnityObjectToClipPos(IN.vertex); OUT.texcoord = IN.texcoord; return OUT; } sampler2D _MainTex; sampler2D _MaskTex; float _Height; fixed4 frag(v2f IN) : SV_Target { float maskHeight= tex2D(_MaskTex, IN.texcoord).r; if (maskHeight> _Height) { discard; } return tex2D(_MainTex, IN.texcoord); } ENDCG } } }
Properties ブロック内で、ノイズ画像の _MaskTex と現在の高さを表す _Height を定義します。
_MaskTex("Mask Texture", 2D) = "white" {} _Height("Height", Float) = 0
フラグメントシェーダ内で、今見ている位置より高い位置のピクセルを破棄しています。
fixed4 frag(v2f IN) : SV_Target { float maskHeight = tex2D(_MaskTex, IN.texcoord).r; if (maskHeight > _Height) { discard; } return tex2D(_MainTex, IN.texcoord); }
あとは、C# スクリプトから適当に _Height を操作します。
using DG.Tweening; using UnityEngine; public class EffectTweener : MonoBehaviour { [SerializeField] SpriteRenderer _spriteRenderer; Material _material; int _heightPropertyID; bool _isHidden = false; void Start() { _heightPropertyID = Shader.PropertyToID("_Height"); _material = _spriteRenderer.material; } void Update() { if (Input.GetMouseButtonDown(0)) { if (_isHidden) { Play(from: 0f, to: 1f); } else { Play(from: 1f, to: 0f); } _isHidden = !_isHidden; } } void Play(float from, float to) { DOTween.Kill(this); DOTween.To( () => from, a => _material.SetFloat(_heightPropertyID, a), to, 1.5f) .SetId(this); } }
ここまでの結果です。
仕上げ
フチに色を付けたり、Bloomで光らせたりして盛ります。
fixed4 frag(v2f IN) : SV_Target { float maskHeight = tex2D(_MaskTex, IN.texcoord).r; if (maskHeight > _Height) { discard; } fixed4 color = tex2D(_MainTex, IN.texcoord); float edgeHeight = 0.015; return lerp( color, fixed4(0, 4, 2, 0), step(_Height - edgeHeight, maskHeight) ); }
まとめ
マスク画像を工夫すればもっと面白い表現ができそうです。
できればフラグメントシェーダ内の条件分岐をなくしたいです。
2017/01/26追記:シェーダーの改善
今回の記事のような処理は、αカットアウトシェーダを使うとよりシンプルに実装できると指摘をいただきました。
docs.unity3d.com
Unityのビルトインシェーダにあるαカットアウトシェーダ(Unlit/Transparent Cutout)を使って実装してみます。
仕組み
αカットアウトシェーダは名前の通り、画像のα値と閾値によってピクセルを破棄するか決定します。
元画像のα成分にマスク情報を埋め込んだ画像を用意します。
この画像を、Unlit/Transparent Cutout シェーダをセットしたマテリアルで描画して、_Cutoff プロパティを操作するとこのように動きます。
(前回と背景が変わっていますが、分かりやすさのためです。結果は前回とほぼ同じです)
フチに色を付ける
Unityのビルトインシェーダはここからダウンロードできます。
https://unity3d.com/jp/get-unity/download/archive
フチに色が付くように Unlit/Transparent Cutout の frag 関数内を改造したシェーダをつくりました。
fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.texcoord); clip(col.a - _Cutoff); UNITY_APPLY_FOG(i.fogCoord, col); float edgeHeight = 0.015; return lerp( col, fixed4(0, 4, 2, 1), step(col.a, _Cutoff + edgeHeight) ); }
改造したシェーダの全体像はこちらです。
https://gist.github.com/setchi/b5c9fd72c3cb5317dae44cb6f3eb7fef
実行結果です。
最初の実装と比較して
最初の実装では画像を二枚使用していたのに対し、一枚の画像で実装できました。
また、不要なピクセルをより手前(Alpha Test)の段階で破棄できて効率的になりました。
【Unity】uGUIで使えるハイパーテキストを作りました
経緯
以前 uGUI Text で Twitter のクリック可能なハッシュタグのようなものを実装しようとして挫折したのをふと思い出して再挑戦しました。
作ったもの
uGUI Text の指定した部分文字列にクリック時のコールバックや文字色を設定できる仕組みを作りました。
github.com
使い方
Text を継承した抽象クラスの HypertextBase.cs に、任意の位置の文字列に文字色とクリックされたときのコールバックを設定できるAPI を用意しているので、継承して自分の好きなように実装します。
サンプルとして正規表現によるハイパーテキストの実装例を置いてあります。
RegexHypertext.cs
uGUI-Hypertext/RegexHypertext.cs at master · setchi/uGUI-Hypertext · GitHub
こんな風に使えます。
using UnityEngine; public class RegexExample : MonoBehaviour { [SerializeField] RegexHypertext text; const string RegexURL = @"https?://(?:[!-~]+\.)+[!-~]+"; const string RegexHashtag = @"[##][A-Za-zA-Za-z一-鿆0-90-9ぁ-ヶヲ-゚ー]+"; void Start() { text.OnClick(RegexURL, Color.cyan, url => Debug.Log(url)); text.OnClick(RegexHashtag, Color.green, hashtag => Debug.Log(hashtag)); } }
結果
おわりに
現状、Canvas の Render Mode が Screen Space - Overlay の場合にしか対応できていません。今後対応予定です。
2016/08/22 追記: すべての Render Mode に対応しました。
その他、不具合・要望があれば
setchi (@setchi) | Twitter
に連絡ください!
【Unity】シェーダーを利用して音声波形を描く
今、広い範囲の音声波形を高速にリアルタイム描画する問題に取り組んでいます。
要件として描画対象の範囲をグリグリ変更できる必要があって、これまでLineRendererやGLによる描画を試みましたがどれも欲しいパフォーマンスに届きませんでした。
そこで、波形情報をテクスチャに埋め込んでシェーダーで描画する方法を試してみました。
AudioClipから波形情報を取得する
var audioSource = GetComponent<AudioSource>(); var samples = new float[audioSource.clip.samples * audioSource.clip.channels]; audioSource.clip.GetData(samples, 0);
で取得できます。
docs.unity3d.com
波形情報をテクスチャに埋め込む
描画領域の横幅 x 1サイズのテクスチャを生成して、色情報に波形データを埋め込んでいきます。
手抜き実装なので r 成分しか使ってませんが、rgba 全ての成分を使えばより小さいテクスチャサイズで実現できます。
また、1サンプルを1ピクセルに対応させるとテクスチャサイズが膨大になりすぎるので適当に間引きします。
public class WaveformRenderer : MonoBehaviour { [SerializeField] AudioSource audioSource; [SerializeField] RawImage image; [SerializeField] int imageWidth; Texture2D texture; float[] samples = new float[500000]; void Start() { texture = new Texture2D(imageWidth, 1); texture.SetPixels(Enumerable.Range(0, imageWidth).Select(_ => Color.clear).ToArray()); texture.Apply(); image.texture = texture; } void Update() { audioSource.clip.GetData(samples, audioSource.timeSamples); int textureX = 0; int skipSamples = 200; float maxSample = 0; for (int i = 0, l = samples.Length; i < l && textureX < imageWidth; i++) { maxSample = Mathf.Max(maxSample, samples[i]); if (i % skipSamples == 0) { texture.SetPixel(textureX, 0, new Color(maxSample, 0, 0)); maxSample = 0; textureX++; } } texture.Apply(); } }
説明に余分なコードは省いています。実際のソースコードはここにあります。
NoteEditor/WaveformRenderer.cs at 21a1878556f1b492a7a9a150339512a6ba5330ca · setchi/NoteEditor · GitHub
このようなテクスチャが生成されます。
(実際は縦1pxです。見やすく縦方向に伸ばしています)
シェーダーで波形を描画する
フルソースはここにあります。
NoteEditor/Waveform.shader at a56ec2d55987a8f22c392bfe1739af87a9e97bc9 · setchi/NoteEditor · GitHub
重要なのは下記の部分です。
テクスチャの r 成分からボリュームを取り出して、自身のV座標がボリュームの範囲内なら緑、そうでなければ黒を出力しています。
fixed4 frag(v2f v) : SV_Target{ float volume = tex2D(_MainTex, v.uv.x).r * 0.5; float uvY = v.uv.y - 0.5; return lerp( fixed4(0, 0, 0, 1), fixed4(0, 1, 0, 1), -volume < uvY && uvY < volume ); }
最終的にこのように出力されます。
【Unity C#】Undo / Redoの実装
今Unityで音ゲーの譜面を作るエディタを開発していて、Undo/Redo の実装をする機会があったのでメモです。
今回はCommandパターンで実装しました。
UndoRedoManager.cs
NoteEditor/CommandManager.cs at master · setchi/NotesEditor · GitHub
ユーザが何か行動すると、それに対するUndoメソッド/Redoメソッドを内包したコマンドオブジェクトをマネージャに渡します。
NoteEditor/CanvasWidthScalePresenter.cs at master · setchi/NotesEditor · GitHub
マネージャは受け取ったコマンドをUndo用スタックにPushしていきます。
Undoの実行はUndo用スタックからPopして、コマンドのUndoメソッドを実行します。
RedoはUndoに対するUndo実装です。
NoteEditor/CommandManager.cs at master · setchi/NotesEditor · GitHub
【n Back Tracer】リリースしました。
Unity習作2本目のカジュアルゲームをリリースしました。
次々と現れるパターンを記憶しながら、N個前のパターンを素早くなぞる脳トレゲームです。難しい選択肢を選ぶほど高得点を狙えます。
n Back Tracer - Google Play の Android アプリ
コードはGitHubに公開しています。
setchi/n_back_tracer · GitHub
【Kagaribi】リリースしました
Unity習作のカジュアルゲームをリリースしました。
火の玉を操作して白い枠をできるだけ多くくぐっていくシンプルなゲームです。
真ん中を通るのが高得点のコツです。
Kagaribi - Google Play の Android アプリ
コードはGitHubに公開しています。
setchi/kagaribi · GitHub
【Unity】手軽にHTTP通信する
Unityで手軽にHTTP通信するクラスを作りました。
Actionを使うので使用する側でSystemを読み込みます。
using System;
POSTではパラメータをDictionaryで渡すので下記も必要です。
using System.Collections.Generic;
静的サイトジェネレータHEXOを試したメモ
http://hexo.io/
ブログといえば動的生成が当たり前だと思ってたんですが、静的ファイルに生成してデプロイする手法もあるらしいです。
静的サイトジェネレータにも色々あるんですが、普段良く使っているNode.js上で動くものにします。その中でGitHubスター数が一番多い(2014/11/27現在)、
hexojs/hexo · GitHub
を選びました。
インストールからデプロイまで、この記事が参考になりました。
個人的にハマった点
faviconの設定方法が分からん
テーマフォルダの中で設定できました。
僕はLightというテーマにしたので、
themes/light/source/
にfavicon.pngを置いて
テーマフォルダ内の_config.ymlに設定することで反映されました。
favicon: /favicon.png
DISQUSのコメント欄が反映されない
こんな感じになってしまう。
DISQUSのshortnameを登録していなかったのが原因でした。ここから登録できます。
Disqus | Register site
登録したshortnameを、プロジェクト直下の_config.ymlに設定します。
# Disqus disqus_shortname: shortname
無事コメント欄が現れました。
プラグイン
ここでプラグインの一覧が見れます。
Plugins · hexojs/hexo Wiki · GitHub
導入したもの
FlashSoft/hexo-console-optimize · GitHub
HTML/CSS/JavaScriptをminifyして出力してくれます。
hexojs/hexo-generator-sitemap · GitHub
sitemapを生成してくれます。
jaredly/hexo-admin · GitHub
記事の投稿・編集ができる管理画面が使えるようになります。
左上のNew Postの挙動がおかしくて、_draftフォルダ内にタイトル名.mdは生成されるのだけど管理画面に反映されませんでした。
マークダウン編集していて、右のプレビューのスクロール位置が同期するのは地味に便利でした。右上の歯車アイコンからカテゴリなどの詳細設定ができます。
Github Pagesにデプロイしました。
http://setchi.github.io/
あとOGPの設定方法とか画像の投稿方法とか調べながら遊んでみます。