うどんてっくメモ

技術的なメモをまったりと

【Unity】「uPalette」で色を管理すると捗るという話

はじめに

UIデザインを作っていく上で必要になってくるのが色を管理する仕組みです。 決定形のボタンにはこの青色を、警告的な文言にはこの赤色を、レベルに合わせてこの色の段階を、などなど、色のルールづけが多い場面は多々あります。 そんな時に便利なのがuPaletteです。Haruma-K(@harumak_11) さんがOSSとして公開しているツールで、プロジェクト内の色の管理及び一元変更を実現してくれます。

light11.hatenadiary.com

github.com

実際に開発で使っている筆者が、uPaletteはいいぞという点をいくつか紹介します。 本記事で紹介および検証を行なっているツールのバージョンは次の通りです。

  • Unity 2021.3.0f1
  • uPalette 2.1.1

バージョンによっては挙動に差異がある場合もありますので、ご了承ください。

基礎的な機能の利便性

GUI操作によるシンプルな色の設定の実現

uPaletteではColorSynchronizerというコンポーネントをGraphicにアタッチし、色の設定を行います。 UnityのWindowとしてエディタ拡張が実装されており、GUIの操作をぽちぽちすることで色の登録からColorSynchronizerのアタッチ、色の反映までを実現します。 UIを量産する上で簡単なGUI操作でポチポチと設定を変えられるのはとても重要で、uPalleteはしっかりその部分が作り込まれています。

特徴的なのが、設定側の色の変更に対してリアルタイムで対応するGraphicの色が変わることです。設定側でやっぱり色味を変えようとした際に一律でシーンやPrefab Modeで色の更新を確認することができます。 また、この色を使ってるのどれだっけ?みたいな場面で、逆にハイライトすることが可能です。

もちろんColorSynchronizerのコンポーネントから設定した色は参照可能で、インスペクターから変更することも可能です。

このように、UIパーツの色を管理する上で必要な機能はとても使いやすい形で提供されています。

システム的な使い勝手を考慮した設計

静的に配置しているオブジェクトの色をよしなに変えられることも大切ですが、システムを開発する上では動的にスクリプト側から色を変えたい場合も存在します。 たとえば動的に表示したいデータが持つenumに伴って、このenumは赤、このenumは青という色の変化を行うケースです。 そんな時はスクリプトからの反映が必要ですが、uPaletteではそれらの機能もスクリプト側で公開されており、システム側でもよしなに取り扱うことが可能です。 まずは設定した色の参照ですが、uPaletteではPaletteというクラスで管理されています。

public abstract class Palette<T> : ISerializationCallbackReceiver
{
    ...

    public IObservable<(string entryId, int index)> EntryOrderChangedAsObservable => _entryOrderChangedSubject;
    public IObservable<(string themeId, int index)> ThemeOrderChangedAsObservable => _themeOrderChangedSubject;

    public IReadOnlyObservableProperty<Theme> ActiveTheme => _activeTheme;
    public IReadOnlyObservableDictionary<string, Theme> Themes => _themes;
    public IReadOnlyObservableDictionary<string, Entry<T>> Entries => _entries;

    ...

色はもちろん、2.0.0から追加されたGradationなどの情報もこのPaletteで管理されています。 それぞれのPaletteはPalleteStoreというシングルトンで管理されており、シンプルな実装で色を参照可能です。

public sealed class PaletteStore : ScriptableObject
{
    ...

    public Palette<Color> ColorPalette => _colorPalette;
    public Palette<Gradient> GradientPalette => _gradientPalette;
    public Palette<CharacterStyle> CharacterStylePalette => _characterStylePalette;
    public Palette<CharacterStyleTMP> CharacterStyleTMPPalette => _characterStyleTMPPalette;

    ...
image.color = PaletteStore.Instance.ColorPalette.Entries["color_id"];

色の反映対象となるColorSynchronizerのコンポーネントについても、継承することで独自の拡張をすることを想定した作りになっています。 これによって独自で実装した描画コンポーネントなどにもuPaletteの反映ロジックを適応させることが可能になっています。 わかりやすい例としてそもそものuPaletteが実装するGraphicに色をつけるコンポーネントの実装とその元となるクラスを示します。

// 何かしらにuPaletteが作用するための大元のクラス
public abstract class ValueSynchronizerBase<T> : MonoBehaviour
{
        
    public abstract EntryId EntryId { get; }

    protected virtual void OnEnable()
    {
        StartObserving();
    }

    protected virtual void OnDisable()
    {
        StopObserving();
    }

    internal abstract Palette<T> GetPalette(PaletteStore store);

    protected abstract void OnValueChanged(T value);
}

// ValueSynchronizerBase<T>を継承した色の反映クラス
public abstract class ColorSynchronizer : ValueSynchronizer<UnityEngine.Color>
{
    [SerializeField] private ColorEntryId _entryId = new ColorEntryId();

    public override EntryId EntryId => _entryId;

    internal override Palette<UnityEngine.Color> GetPalette(PaletteStore store)
    {
        return store.ColorPalette;
    }
}

public abstract class ColorSynchronizer<T> : ColorSynchronizer where T : Component
{
    [SerializeField] [HideInInspector] private T _component;

    protected T Component
    {
        get
        {
            if (_component == null)
            {
                _component = GetComponent<T>();
            }

            return _component;
        }
    }
}

// Graphicを対象に色の反映を行うクラス
// Attributeはエディタ拡張で色を設定する際に対応するValueSynchronizerを見つけるために必要
[ColorSynchronizer(typeof(Graphic), "Color")]
public sealed class GraphicColorSynchronizer : ColorSynchronizer<Graphic>
{
    protected internal override UnityEngine.Color GetValue()
    {
        return Component.color;
    }

    protected internal override void SetValue(UnityEngine.Color value)
    {
        Component.color = value;
    }

    protected override bool EqualsToCurrentValue(UnityEngine.Color value)
    {
        return Component.color == value;
    }
}

独自のコンポーネントに色をいい感じにつける場合にはColorSynchronizerを継承した独自クラスを定義し、反映部分のロジックだけ実装すればいいわけです。 このように、uPaletteはシステム的にエンジニアが使いやすいように作られている点も個人的な推しポイントです。

ver2.0.0でさらに便利になったポイント

uPaletteは最近2.0としてメジャーアップデートがありました。実は1.0では「こうなると嬉しいな〜」と思っていた点があったのですが、いい感じに改修していただけました。 改修された点についてもいくつか紹介します。

enumが自動で生成されるように

前述にもあるように、uPaletteではstringのidをキーとして色を管理します。エンジニアとしてはstringのidをそのままコードに使うよりは何かしらの識別子が欲しいものです。 筆者も1.0の頃は独自のenumを定義しており、色の設定更新にともなってよしなにuPaletteが作るようにならないかなと思っていました。 2.0からは色の設定を更新すると、次のようなenumと付随する実装が生成されます。

namespace uPalette.Generated
{
    public enum ColorTheme
    {
        Default,
    }

    public static class ColorThemeExtensions
    {
        public static string ToThemeId(this ColorTheme theme)
        {
            switch (theme)
            {
                case ColorTheme.Default:
                    return "ef6ad2f2-968e-4e08-b17d-45be08828273";
                default:
                    throw new ArgumentOutOfRangeException(nameof(theme), theme, null);
            }
        }
    }

    public enum ColorEntry
    {
        ColorName1,
        ColorName2,
    }

    public static class ColorEntryExtensions
    {
        public static string ToEntryId(this ColorEntry entry)
        {
            switch (entry)
            {
                case ColorEntry.ColorName1:
                    return "1cb426b2-2b90-4234-b637-3bee8c7d3157";
                case ColorEntry.ColorName2:
                    return "c7c6fc92-47c0-4ff1-b0ec-4b507b25a97e";
                default:
                    throw new ArgumentOutOfRangeException(nameof(entry), entry, null);
            }
        }
    }
...

enumだけでなく、拡張メソッドとしてidへの変換まで用意してくれるのは親切です。 生成するかどうかの設定や生成先はProject Settingsから調整可能です。

Gradationやテキストのスタイルにも対応

色だけではなく、GradationやテキストのスタイルまでuPalette上で管理できるようになりました。

色同様にUIを量産する上で一元管理したい要素なのでこれもありがたい更新です。

一連の色の設定をまとめたThemeという単位で管理が可能に

個々の色の設定だけでなく、一定の設定をまとめてテーマという単位で取り扱うことも可能になりました。 こちらは公式のデモを見るのが一番わかりやすいです。

色はもちろん、文字のスタイルなどもテーマごとに一括で切り替わっているのがわかるかと思います。 たとえば画面ごとに全体の雰囲気を変える必要があるようなケースだったり、設定でダークモードなどの色のテーマを選択できるような機能を作りたい場合にはかなり重宝する機能です。

おわりに

uPaletteを活用することで、色の一元管理を行う機能をさくっとプロジェクトに導入することができます。 独自でこの辺りの機能を作るのが億劫なみなさまはぜひ一度試してみて欲しいです。

引用

github.com

【Unity】TextMeshProのアウトラインを理解する

はじめに

本記事で紹介および検証を行なっているツール、ライブラリのバージョンは次の通りです。

  • Unity 2021.3.1f1
  • com.unity.textmeshpro@3.0.6

バージョンによっては挙動に差異がある場合もありますので、ご了承ください。

TextMeshProのアウトライン

UIを作っていく上で必要になりがちなアウトライン表現ですが、TextMeshProでやる場合にはMaterialのパラメータで実現できます。

Thicknessの値を大きくすれば、アウトラインを太くすることが可能です。

適当にアウトラインをつけたいだけならこれでいいのですが、たとえば5pxのアウトラインをつけたい!ということをする際、パラメータをどう設定すればいいかいまいち掴めませんでした。 そこで、Forumを漁ってみると公式の説明が投稿されていました。

forum.unity.com

この説明をもとに、アウトラインの大きさや見え方の仕組みについて紹介します。

アウトラインの大きさ

まず最終的なアウトラインの大きさの式から示します。

アウトラインのサイズ(大体) = FontSize * Padding / Sampling Point Size * Thickness * 2

たとえばテキストのFontSizeが50px、参照するFontAssetのSampling Point Sizeが100px、Paddingが9px、そしてMaterialのThicknessが0.5であれば、アウトライン幅は50 * 0.09 * 0.5 * 2 = 4.5pxになります。ここで大体という注釈をつけているのは、内部計算で端数の切り捨てや補完の計算が働くケースもあるためです。詳細は本記事では省略するため、実際のシェーダーの中身を参照してもらうといいかと思います。

FontSize

そのままで、TextMeshProによるGUIコンポーネントに設定されたFont Sizeです。

Padding / Sampling Point Size

わかりにくいですが、FontAssetのGeneration SettingsにあるSampling Point SizeをPaddingで割ったものになります。 Sampling Point Sizeが100でPaddingが9であれば「サンプリングされている文字のサイズに対するパディングの割合値」は0.09といった形です。

Sampling Point SizeとPaddingはTextMeshProにおけるSDF Textureでの文字ひとつひとつのサイズと間隔を表します。Atlas Population Modeについて、動的にサンプリングするDynamicであればこの画像にもあるGeneration Settingsの値を変更して調整しますが、事前にサンプリングしておくStaticであればFont Asset Creatorによる生成時にバインドされます。

この生成時にも、SP/PD Ratioという値で出力されてたりします。

Thickness

冒頭でも説明した、MaterialのOutlineにあるパラメータです。

内側と外側のアウトライン

注意しなければならないのが、このアウトラインは文字の輪郭を中心軸に外側と内側に描画されることです。 なので、大きさを求める計算式では最後に2を掛けています。 また、アウトラインの見せ方にも注意が必要です。たとえば外側にアウトラインをつけたいだけだと、内側に描画されてしまう分文字部分が潰れてしまいます。 対応するにはMaterialのFaceにあるDilateというパラメータを調整します。Dilateは文字の太さの拡縮の役割があります。

以上のように、アウトラインの大きさや見え方を調整するにはさまざまなパラメータを考慮する必要があります。

まとめ

これまで雰囲気でTextMeshProのアウトラインをつけていましたが、TextMeshProのパラメータを理解するいい機会になりました。 文中でも言及しましたが、詳細なロジックは実際のTextMeshProのシェーダーで確認できます。興味のある方はぜひのぞいてみるのがおすすめです。 また、本記事に誤りがある場合には筆者までコメントなどで指摘いただけますと幸いです。

【Unity】TextMeshProのバージョンを更新してRectMask2Dのsoftnessを反映させる

本記事で紹介および検証を行なっているツールのバージョンは次の通りです。

  • Unity 2021.2.0f1
  • com.unity.textmeshpro@3.2.0-pre.2

バージョンによっては挙動に差異がある場合もありますので、ご了承ください。


RectMask2Dのsoftnessを使ってソフトマスクをかけていたところ、効果がTextMeshProに反映されていないことに気づきました。

f:id:myudon:20220313010801g:plain

issueを調べてみると、どうやらTextMeshPro3.2.0-pre.2以降で対応されているそうです。

issuetracker.unity3d.com

当然preview版のパッケージなので不具合が発生する可能性もあるのですが、更新することでsoftnessの問題は解決しそうです。(ちなみにこの記事を検証しているUnity2021.2.0f1のTextMesh Proのバージョンは3.0.6となります。) その場合、Package ManagerからTextMeshProのバージョンを上げる必要があります。 preview版なので、Add by package name...から直接入力します。

f:id:myudon:20220227213926p:plain:w500

f:id:myudon:20220227214242p:plain:w500

TextMesh Proのバージョンを上げたらEssential Resourcesも同時に更新する必要があります。 Window -> TextMesh Pro -> Import Essential Resourcesから更新してください。

f:id:myudon:20220313004743p:plain:w500

f:id:myudon:20220313005220p:plain:w500

以上の工程で正常にバージョンを上げると、softnessが反映されることが確認できます。

f:id:myudon:20220313010830g:plain

バージョン差分は公式のよりChangeLogより参照できるので、気になる方は確認してください。

docs.unity3d.com

【Rider】Code Cleanup Profileを使ってカスタムしたコード整形を行う

RiderにはCode Cleanupというコードの整形機能があり、いい感じにコードを整えてくれます。

pleiades.io

便利ではあるものの、デフォルトのまま使うといささかプロジェクトのコード規約にそぐわなかったり、意図しない不要な差分を生み出てしまうこともあります。 プロジェクトに適切な整形処理だけ走らせたい、そんな時にはカスタマイズした設定、Code Cleanup Profileを作成することで実現することができます。

Code Cleanup Profileの設定

まずはCode CleanUpを行う画面をCode -> Reformat and Cleanup Codeから開きます。

f:id:myudon:20220206214705p:plain

左下に表示されるのが設定となるCode Cleanup Profileです。デフォルトではFull Cleanup、Reformat & Apply Syntax Style、Reformat Codeの3つが用意されており、特に指定がなければFull Cleanupが指定され実行します。 右には実際にそのProfileに設定されている処理の項目が表示されます。

f:id:myudon:20220206215002p:plain

新しくProfileを作るには左上のEditボタンを押します。

f:id:myudon:20220206215714p:plain

Profileの設定画面が開くので、左上のプラスボタンから新規Profileを名前をつけて作成します。

f:id:myudon:20220206215907p:plain

後は使いたい処理を右から選択して適用します。選択後は右下のSaveを必ず押してください。 筆者はUnityでのC#コーディングに活用しているため、C#周りの設定をよしなに採用して使っています。

f:id:myudon:20220206220309p:plain

そしてCleanupを行う際に、作成したProfileを選択して実行すれば完了です。

f:id:myudon:20220206220634p:plain

Reformat and Cleanup on Saveでの活用

Rider2021.3以降には、保存時にReformatおよびCode Cleanupを呼び出す新機能が備わっています。

www.jetbrains.com

この機能においてもCode CleanUp Profileの適応が可能です。 Tools -> Actions on SaveからReformat and Cleanup on Saveを設定する画面を開き、Profileと指定されている部分を設定します。 デフォルトだとビルトインのFull Cleanupが指定されています。

f:id:myudon:20220206211639p:plain

設定したら、実際に保存してみて処理が走るか確認してください。

おわりに

RiderのCode Cleanupは適切に使いこなすことで、効率的にコーディングを進められます。 プロジェクトに則したProfileをもとに、Code Cleanupの導入を検討してみてはいかがでしょうか。

Unity2022でさらに進化したSearch Windowが便利だった

はじめに

2022年も始まりということで、Unity2021から導入され、さらにUnity2022で進化を遂げているSearch Windowの使い方について紹介します。 Search WindowについてはUnity2021以降で使用できる機能になりますので、ご留意ください。

本記事で紹介および検証を行なっているツールのバージョンは次の通りです。

  • Unity 2022.1.0b1

バージョンによっては挙動に差異がある場合もありますので、ご了承ください。

Search Window

Search Windowはプロジェクト内のアセットの参照およびさまざまな操作について、名前や特定の条件で絞り込んで検索する機能です。

f:id:myudon:20220102213051p:plain

WindowsであればCtrl + KMacであればCmd + Kのショートカットキーで開きます。 また、Projectビューの検索欄の右にあるボタンでも表示されます。一番検索欄に近い矢印が入ってるボタンです。

f:id:myudon:20220102215304p:plain

アセットについてパス、種類、名前などを指定して一覧として確認することが可能です。 次の画像は入れているPackage含めて全ての場所にあるTextureアセットを確認しているところです。

f:id:myudon:20220103011028p:plain

タイプと名前と言ったように、複合した条件も指定できます。

f:id:myudon:20220103011632p:plain

また、各種メニュー行える操作、および各種設定のウィンドウについてもSearch Windowからショートカットすることができます。

f:id:myudon:20220103011751p:plain

f:id:myudon:20220102220607p:plain

筆者はよく「あの画面ってどうやって出すんだっけ...」みたいになっておもむろにググるみたいなことがちょこちょこあったのですが、これを活用すれば名前さえ把握していればささっと出すことが可能です。

また、現在開いているシーンのヒエラルキー状のオブジェクトの検索も可能です。 ヒエラルキーにある検索機能でも同等のことはできるので、条件を色々と変えてヒエラルキーの内容を色々と確認したい時には有用です(ちょっとした検索をその場でしたいだけであれば、ヒエラルキーの検索機能でやってしまった方が早いです)。

f:id:myudon:20220103013424p:plain

2022で進化した絞り込み機能 Query Builder Mode

Unity2022からSearch Windowの絞り込み機能が視覚的に進化しました。 そもそもUnity2021では絞り込みを行う際に直に条件を打ち込む必要がありました。 タブキーでサジェストしてくれるものの、一定記述する必要はあったので、やや直感的ではありませんでした。

f:id:myudon:20220103001044p:plain

Unity2022ではこれがGUIによって設定できるQuery Builder Modeというのが追加されました。 これによって絞り込みたい要素をかなり視覚的に設定できます。

f:id:myudon:20220103001231p:plain

使う時には左上のボタンで切り替えます。

f:id:myudon:20220103010901p:plain

Query Builder Modeでは検索条件を追加する時は検索欄にあるプラスボタンを押して、フィルタ条件を指定します。

f:id:myudon:20220103012106p:plain

f:id:myudon:20220103012048p:plain

フィルタはアセットの種類やアタッチされているComponentなど、色々な条件がメニューに用意されています。 追加したフィルタは右クリックで後からアクティブの切り替えや中身の差し替えが可能です。

f:id:myudon:20220103020646p:plain

物によっては対象となるパラメータを元に条件を指定することも可能です。 たとえばアセットのIDやファイルサイズだったり、Prefabの種類だったり、特定のコンポーネントについてインスペクターから指定できる設定値だったり、様々なフィルタが用意されています。

f:id:myudon:20220103020502p:plain

f:id:myudon:20220103021234p:plain

f:id:myudon:20220103021255p:plain

パラメータ系のフィルタについては値やその条件となる等号などを調整可能です。

f:id:myudon:20220103021315p:plain

もちろんこれらの情報はQuery Builder Modeじゃなくとも記述すれば適応できるのですが、直感的に指定できるので便利です。

f:id:myudon:20220103014928p:plain

f:id:myudon:20220103015511p:plain

以上がQuery Builder Modeの紹介になります。

おわりに

本記事では紹介していない細かい機能もあるのですが、こちらは公式ドキュメントを参考にしてください。

docs.unity3d.com

何かしらアセットを探したり、メニューの操作や設定の調整で時間を消耗している人は活用してみてはいかがでしょうか。

2021年の振り返りと2022年の抱負

2021年にやったことを振り返りつつ、2022年頑張ることを書いていきます。

2021年やったこと

個人ブログ投稿 12本

昨年この技術ブログである「うどんてっくメモ」を再開し、今年は12個の記事を投稿しました。 単純に割ると月1つ出るかな、ぐらいのペースでした。

myudon.hatenablog.com

特にUnityが多くを占めていましたが、個人的に勉強を始めたRustに関してもちょろっと記事を出せたのは良かったなと思います。 閲覧数についても日々じわじわと上がっていっており、少し達成感を感じています。 今後も定期的に知識をアウトプットする場として活動していきたいです。

Zenn投稿 1本

基本的にアウトプットをブログに移行したのでQiita投稿はなかったのですが、Zennは一度投稿してみたくてRustの記事を書きました。

zenn.dev

結果的に想定していたよりも多くの方に見ていただけたようで、個人的には嬉しい記事になりました。 今後もちょっとしたTips系統はZennとかQiitaとかにあげれたらいいかもなと思っています。

技術書典の出典 会社と個人

技術書典で「UniTips」というUnityの技術書を定期的に会社で出しているのですが、2021年も執筆に参加しました。

creator.game.cyberagent.co.jp

第1回から携わってきていて、もう7冊目になるらしいです。時の流れを感じます。 技術書典12も既に予定されていますが、そこにも執筆予定です。 そして、個人執筆としてついに本を出すことができました。2021年の目標として掲げていた大きな点ですが、無事達成できました。

執筆自体は2月ぐらいからまずAmethystでサンプルゲームを作ったものをざっくり文章化し、それに伴って実装も調整したりし、なんやかんや半年ぐらいはかかった気がします。 隙間時間でちょこちょこと書いていたというのが大きな要因ではあるのですが、半年かかってようやく形になって本をビルドした時は感慨深いものがありました。 Twitter上でも多くの方に拡散していただけまして、結果としては想定を遥かに上回る数を手に取っていただけました。 今後も個人での本の執筆は挑戦していきたいですね。

商業誌執筆2冊

商業誌については業務でのお話と、技術書典で出した本の商業化のお話をいただきまして、執筆する運びとなりました。

creator.game.cyberagent.co.jp

nextpublishing.jp

商業誌を書く機会がまさか2回もあると思っていなかったので、今思うと貴重な体験をさせてもらえたなと思っています。 特に店頭に自分が書いた本が並んだり、Amazonでも自分の書いた本がヒットするというのはなかなかに嬉しかったです。 今後もお話をいただける機会があったり、チャンスがあったりすれば積極的に取り組んでみたいですね。

CA.unityの開催

どちらかというと業務に寄った話なのでアレですが、CA.unityというUnityのLTイベントを企画し、開催し始めました。 これは今年やったことの中でも大きな挑戦でした。

meetup.unity3d.jp

特に第1回は763人もの参加登録があり、運営としても驚愕のスケールとなりました。参加してくださったみなさま、本当にありがとうございました。 アーカイブに関しては全てUnityLearningMaterialsに掲載されてますので、ぜひチェックしてみて下さい。

learning.unity3d.jp

Gotanda.unity 登壇

Gotanda.unityというUnityのLTイベントについて、初登壇しました。 外部LTイベントについて、聞き手側としてはちらほら参加させてもらっているものの、登壇したことないなということで思い切って参加登録をポチりました。

learning.unity3d.jp

LT自体は社内ではちょこちょことやっていたので、ある程度は喋れるだろうと思っていたのですが、いざ本番になったらとても緊張したのを覚えています。 今振り返るともっと綺麗に話せたなとか、もっとスライド構成よくできたなとか、外部資料として残るならここの情報は可視化した方が良かったなとか、反省点が多いです。いい経験になりました。 今後も外部登壇にはチャレンジしていく予定です。

Qiitaアドベントカレンダー 2つ参加

毎年恒例アドベントカレンダー、2021年は会社のものとUnityのものに参加させていただきました。

myudon.hatenablog.com

myudon.hatenablog.com

会社のものについては去年同様に自分が運営を務めているのですが、今年も多くの方にご協力いただき、中身の大変濃いカレンダーが完成しました。 Unity、Golang、課金基盤、技術施策、新卒体験記などなど...さまざまな知見が詰まっていますので、よければ覗いてみて下さい。

qiita.com

2022年の抱負

アウトプットの戦略を立てる

2021年はブログ投稿、本の執筆、外部LT登壇、CA.unity、SNS宣伝などなど多角的にアウトプットに挑戦した一年でした。 結果的にこれまでの年で一番多くの人に知見を届けられたかなと思っています。多角的にやることで、アウトプットの手段についてのノウハウやそれぞれのメリデメを体感することができました。 これらの経験を活かし、自分にとっても業界にとってもより良いアウトプットに繋げられるように戦略をしっかり立てていきたいです。

  • アウトプットする内容の中でどこを簡潔に、どこを詳細に言語化するのか
  • どういったアウトプットの手法、規模感が好ましいか
  • 自分の知見でどの部分がアウトプットとして切り出せるか、どの部分がターゲットに有意義な知見になっているか
  • どういった広報で多くの人に届けることができるか

これらを考えつつ、良質なアウトプットを積極的にしていきたいなと思います。

インプットを大きめの年に

2021年は多角的にアウトプットを行った結果少しインプットは自分の満足いくものにはなりませんでした。 隙間時間に本を読んだり、記事を読んだり、というインプットは継続的にしているものの、ガッツリとインプットに時間を割いて知識を積む時間を作るというのは少し余裕がなかった一年でした。 今年はアウトプットを計画的にする中で効率化し、その時間をインプットに割いてより技術力を高める年にしていきたいです。 特に個人的にはRustに興味が強く、まだまだ勉強したいものも多いので、重視して計画していきます。

最後に

ここまでポエムを読んでいただきありがとうございました。 2021年はアウトプットについて大きな挑戦をしつつ、積極的に活動の幅を広げてみた一年でした。 2022年は2021年で培った土台をもとに、より多くのアクションを計画しながら知識を研鑽していければと思います。 2022年もよろしくお願いいたします。

【Unity】Unity2021.2で正式リリースされた2D Lightの紹介

この記事はUnity Advent Calender 2021 16日目の記事です。
15日目は @monry さんの「Unity Addressables Tips 〜2021年に於けるアップデート情報を添えて〜」でした。

先日Unity2021.2がリリースされ、さまざまな機能の改修が公式で紹介されていました。 その一つが「2D Light」の正式リリースです。

f:id:myudon:20211107200347g:plain

2D Lightはその名の通り2Dの描画物に対してライティングを行うもので、より高度な2D演出を可能にしてくれます。 初めての登場としてはUnity2019あたりで、Experimentalな機能としてここまで提供されていました。そんな正式リリースした2D Lightについて、その基礎的な機能や使い方について紹介します。 本記事で紹介および検証を行なっているツールのバージョンは次の通りです。

  • Unity 2021.2.0f1
  • Universal Render Pipeline 12.0.0

バージョンによっては挙動に差異がある場合もありますので、ご了承ください。

使い方

2D Renderer(SRP Asset)のとMaterialの設定

まず2D Lightを使うには、SRPの2D Rendererの設定を行う必要があります。 必要なのは2D Rendererのアセットです。メニューから2D Renderer付きのURP Assetを作成します。

f:id:myudon:20211105000856p:plain

作成するとRendererとPipelineのアセットが生成され、Pipelineには自動的にRendererがアタッチされた状態となります。 Edit -> Project SettingsからGraphicsの項目を開き、この生成したアセットを設定します。

f:id:myudon:20211105193736p:plain

Qualityごとの設定についても、必要に応じてアタッチしてください。

f:id:myudon:20211105194155p:plain

以上でRendererの設定は完了です。
Lightの影響を受けるスプライトについては専用のLitシェーダーが設定されていることを確認してください。

f:id:myudon:20211107185334p:plain

以上でスプライトが2D Lightの影響を受けるまでの前準備が完了です。

基本的なLightの作成と設定

2D Lightには次の4つの種類が存在します。

  • Global
  • Freeform
  • Sprite
  • Spot

それぞれのライトはヒエラルキー上の右クリックのメニューから作成できます。 作成されるもの自体は2D LightのコンポーネントがアタッチされたGame Objectで、その設定が違うだけです。

f:id:myudon:20211106103851p:plain

パラメータの設定はインスペクター上で設定可能です。 ColorとIntensity、そしてTarget Sorting Layerの項目があり、ライトの色と光の強さ、および対象のSorting Layerを調整できます。

f:id:myudon:20211106183050p:plain

ライトの種類ごとの挙動や設定についても説明します。

Global Light

Global Lightは全体を照らすライトです。設定した値が全体のライティングに反映されます。

f:id:myudon:20211107175031g:plain

全体的な2Dのベースのライティングの調整に活用するライトです。

Freeform Light

Freeform Lightはその名の通り自由変形してライティングする領域を矩形で指定できるライトです。

f:id:myudon:20211107175105g:plain

2Dの描画物に対してとりあえず任意の部分を明るくしたいといったケースでは非常にお手軽に反映させることができます。

Spot Light

Spot Lightは特定の位置に照明を当てたような円形のライティング効果を与えるライトです。 半径や円形に広がるライティング効果の減衰などを調整し、照らし方の調整ができます。

f:id:myudon:20211107175223g:plain

一点から照らすような効果を与えたい時にはSpot Lightを調整するといいでしょう。

Sprite Light

Sprite Lightはライティング効果を特定のスプライトの形状及び値を元に行います。

f:id:myudon:20211107175551g:plain

特定のシルエットによってライティング効果を出したい時には活用できます。

以上が2D Lightを使う上で基本となるライトの種類と設定になります。

Blending

2D Lightではそのライティング効果について、インスペクターからブレンドする計算を乗算にするか加算にするかを選択することができます。

f:id:myudon:20211107200834p:plain

画像にあるようにインスペクタからライトのブレンドを示すBlend Type、反映順序を示すLight Order、そして重なった際のライトの値の処理の種類となるOverlap Operationを設定できます。 Overlap Operationについては純粋な加算となるAdditiveとアルファ値の合成となるAlpha Blendが存在しており、単純にLightを合成する場合には前者を、Light Orderに沿って反映される効果を上書きしたい場合には後者を選択します。

Shadow Caster

2D Lightではライティングだけでなく、影を落とすこともできます。

f:id:myudon:20211113200446p:plain

影を落とすには2D Lightの設定と、スプライト側のコンポーネントのアタッチが必要になります。 まず2D Light側です。インスペクタのShadowsからStrengthを与えるとそれに伴った影が落ちるようになります。

f:id:myudon:20211107201618p:plain

そしてスプライト側ですが、これにはShadow Caster 2Dというコンポーネントをアタッチします。

f:id:myudon:20211107201731p:plain

落とす影の設定として、Use Renderer SilhouetteとCasts ShadowsとSelf Shadowsの三つの項目があります。 Casts Shadowsはそのまま影を落とすかどうかの設定となり、Use Renderer SilhouetteとSelf Shadowsは影の形状を調整する設定になります。Use Renderer Silhouetteでは影について描画されるスプライトの形状を加味するかどうか、Self Shadowsは自身に影を落とすかどうかの設定です。 こちらは公式ドキュメントの説明画像がわかりやすいです。引用した画像を次に示します。

f:id:myudon:20211109222017p:plain

また、複数のShadow Caster 2Dを利用する際には、Composite Shadow Caster 2Dというコンポーネントを利用します。 複数のそれらのオブジェクトの親にComposite Shadow Caster 2Dをアタッチすることで、それぞれをマージした一つの影として効果をシーン上に落とすことが可能です。

f:id:myudon:20211113195046p:plain

こちらについても公式ドキュメントの説明画像がわかりやすいです。 引用した画像を次に示します。 f:id:myudon:20211109223134p:plain

複数の影を干渉させるような表現を行う際には活用すべきコンポーネントとなります。

Normal Map

スプライトについて、ノーマルマップを用意したものについてはLight 2Dの効果にも反映されます。 例としてレンガのパターンで紹介します。これは反映せずにSpot Lightを当てた画像です。

f:id:myudon:20211106194404p:plain

これに適当に作ったNormal Mapを設定し、ライトの設定も調整すると次のようにライティング効果が変わります。

f:id:myudon:20211106194804p:plain

陰影が反映されて立体感が演出されているのがわかるかと思います。この手順についてみていきます。
まずはスプライト側です。これは難しいことはなく、該当するスプライトのSprite EditorからSecondery Textureとしてノーマルマップを指定するだけです。 スプライトのインスペクタからSprite Editorを選択し、左上のメニューからSecondary Textureの指定を行います。

f:id:myudon:20211107161718p:plain

_NormalMapと名前をつけ、設定するテクスチャをアタッチします。設定したSecondary Textureは選択して確認可能です。

f:id:myudon:20211107161613p:plain

以上でスプライト側の設定は完了です。次に2D Light側の設定を行います。 インスペクタの下の方にメニューがあるのでそこを調整します。

f:id:myudon:20211107162032p:plain

Qualityではその精度を設定できます。デフォルトではDisable、つまりは無効になっており、簡易的な計算によるFastとより正確な計算によるAccurateを選択します。 Distanceはライトとスプライトの距離を示しています。

Light Explorer

2D Lightも通常のLight同様にLight Explorerで設定の調整ができます。Light Explorerについて知りたい方は公式ドキュメントを参考にしてください。

f:id:myudon:20211107200730p:plain

一括でシーン中の光源の管理をしたいときにおすすめな機能です。

おわりに

Unity2021.2でようやく正式版になった2D Lightですが、さまざまな機能が用意されています。 単純に2Dの世界を明るくするだけではなく、よりリッチな表現をする上では非常に便利な機能となっているので、2Dの演出を考えている人はぜひ試してみてください。

さて、明日の Unity Advent Calendar 2021 は @Takaaki Ichijo さんの「ゲームのアドベンチャーパート(キャラクター掛け合い)の時系列演出をつくる」です。
お楽しみに〜!

参考文献

本記事の検証をするにあたって以下のサイトの素材を使用させていただきました。

かわいいフリー素材集 いらすとや

岩の無料イラスト | フリーイラスト素材集 ジャパクリップ

また、機能については公式ドキュメントを参考にさせていただきました。詳細な仕様を知りたい方はこちらを参照してください。

2D Graphics Features | Universal RP | 13.0.0