うにてぃブログ

主にUnityとC#に関する記事を書いていきます

まとめ

ライブラリ

github.com

デバッグツール
Easing関数
Missing Script 検索ツール
モデル撮影ツール
Module化ライブラリ
Unity上で使える Git Tool
単純なメッシュを作成するツール
カメラ一覧を表示
アセットのディレクトリを移動する
テクスチャ生成ツール
対象のコンポーネントを利用している Prefab や Scene を探すツール
CustomInspector の テンプレートコードを出力するツール
アセットの参照を確認するツール
Hierarchy に存在するオブジェクトの参照を調べるツール
Texture を加工するツール
ProjectWindow を拡張するツール
AnimationClip の Path を一括で置換するツール

アドベントカレンダー

hacchi-man.hatenablog.com

Builtin Render Pipeline から Universal Render Pipeline (URP) に切り替える方法

URP Assetを作成します

Project SettingsのGraphicsにアセットをセットします

すると確認ダイアログが表示されるのでアセットをセットします

「アプデするよ」って内容が表示されるのでOKを選択します

更新が終わると、URPでないShaderはエラーとなるため、変更する必要があります

例えば、Default-materialはStandardを利用しているのでエラーになります

更新後に作成したオブジェクトには、LitのMaterialがセットされます

【Unity】float で Color.rgb を近似する

Meshの情報を使ってShaderで色を操作する際、RGB値を渡すとfloat3が必要になりますが、多くの色を扱いたい場合はできるだけ使用する数を減らしたいですね。

そのような場合、RGBをfloatに変換し、Shader側でfloatからRGBに変換することで、完全には復元できないかもしれませんが、1つのfloatで済ませることができます。

以下がRGBをfloatに変換する処理です。

/// <summary>
/// RGBをfloatに変換 
/// </summary>
float ColorToFloat(Color color)
{
    var rgb = new Vector3Int(
        Mathf.FloorToInt(color.r * 255f + 0.5f),
        Mathf.FloorToInt(color.g * 255f + 0.5f),
        Mathf.FloorToInt(color.b * 255f + 0.5f)
    );
    float packed = rgb.x * 65536 + rgb.y * 256 + rgb.z;
    return packed / (256 * 256 * 256);
}

復元する際には、以下のようにして、ある程度似た色に戻すことができます。

half4 FloatToColor(float packed)
{
    packed *= 256 * 256 * 256;
    half3 color = half3(0, 0, 0);

    color.b = fmod(packed, 256);
    packed = floor(packed / 256);
    color.g = fmod(packed, 256);
    color.r = floor(packed / 256);
    return half4(color / 255, 1);
}

実際に利用してみた結果、色がそこまで大きくずれていないことが確認できましたね。

【Unity】TextMeshPro でタップした箇所の文字を取得する汎用処理とサンプルコード

TextMeshProを使用して、タップした箇所の文字を取得するための一般的な処理について説明します。

using TMPro;
using UnityEngine.EventSystems;

/// <summary>
/// TextMeshPro のタップ処理
/// </summary>
public static class TextMeshProTapUtility
{
    /// <summary>
    /// タップした箇所の文字を取得
    /// </summary>
    public static bool TryGetTapCharacter(this TMP_Text self, PointerEventData eventData, out char character)
    {
        character = default;
        var index = TMP_TextUtilities.FindIntersectingCharacter(self, eventData.position, eventData.pressEventCamera, false);
        if (index < 0)
            return false;
        
        character = self.textInfo.characterInfo[index].character;
        return true;
    }
    
    /// <summary>
    /// タップした箇所の単語を取得
    /// </summary> 
    public static bool TryGetTapWord(this TMP_Text self, PointerEventData eventData, out string word)
    {
        word = default;
        var index = TMP_TextUtilities.FindIntersectingWord(self, eventData.position, eventData.pressEventCamera);
        if (index < 0)
            return false;
        
        var wordInfo = self.textInfo.wordInfo[index];
        var wordStartIndex = wordInfo.firstCharacterIndex;
        word = self.text.Substring(wordStartIndex, wordInfo.characterCount);
        return true;
    }
    
    /// <summary>
    /// タップした箇所のリンクを取得
    /// </summary>
    public static bool TryGetLink(this TMP_Text self, PointerEventData eventData, out string link)
    {
        link = default;
        var index = TMP_TextUtilities.FindIntersectingLink(self, eventData.position, eventData.pressEventCamera);
        if (index < 0)
            return false;
        
        link = self.textInfo.linkInfo[index].GetLinkID();
        return true;
    }
}

サンプル

以下は、上記のユーティリティクラスを利用したサンプルコードです。

using UnityEngine;
using TMPro;
using UnityEngine.EventSystems;

public class TextMeshProClickHandler : MonoBehaviour, IPointerClickHandler
{
    [SerializeField]
    private TextMeshProUGUI _textMeshPro;

    public void OnPointerClick(PointerEventData eventData)
    {
        if (_textMeshPro.TryGetLink(eventData, out var link))
        {
            Debug.Log("Clicked link: " + link);
        }
        
        if (_textMeshPro.TryGetTapCharacter(eventData, out var character))
        {
            Debug.Log("Clicked character: " + character);
        }
        
        if (_textMeshPro.TryGetTapWord(eventData, out var word))
        {
            Debug.Log("Clicked word: " + word);
        }
    }
}

このサンプルコードは、TextMeshProTapUtilityクラスを使用して、タップした箇所のリンク、文字、および単語を取得する方法を示しています。

【Unity】Unityの組み込みリソースを手軽に確認するツール

UnityEditor上で利用可能なアイコンやGUIStyleを調べるのが手間だと感じていました。そこで、これらのリソースを一覧で確認できる便利なツールを作成しました。

github.com

このツールを使用することで、元々組み込まれているアイコンやGUIStyleに簡単にアクセスできます。手軽にリソースを確認し、開発プロセスを効率化できます。

詳細やツールの使用方法については、GitHubリポジトリをご覧いただければと思います。興味がありましたらぜひチェックしてみてください。

【Unity】テクスチャやスプライトのサムネイルが表示されない

特定の Unity バージョンで、テクスチャやスプライトを設定する際に表示されるウィンドウで、サムネイルが正しく表示されない現象が発生しています。

初めは Unity のキャッシュの変更が原因かと考えていましたが、実際にはバグで表示されていないようでした。

Issue Tracker を見てみると以下のバージョン以降でこの問題が修正されていることが確認できました。

バグの詳細は Unity のIssue Trackerで確認できます

対応策

UnityEditorがキャッシュしていれば正常に表示されるため、以下のように無理やりロードしてキャッシュすることで、バグのあるバージョンでもサムネイルが正しく表示されるようになります。

private static List<Sprite> _cache;

[MenuItem("Tools/CacheThumbnail")]
private static void Cache()
{
    _cache = new List<Sprite>();
    var loadGUIDs = AssetDatabase.FindAssets("t:Sprite", new string[] {"Assets"});
    foreach (var guid in loadGUIDs)
    {
        var path = AssetDatabase.GUIDToAssetPath(guid);
        _cache.Add(AssetDatabase.LoadAssetAtPath<Sprite>(path));
    }
}

【Unity】Bloom 効果を RenderTexture で正しく反映させる方法

Scene 上のオブジェクトには Bloom 効果がかかっているのに、RenderTexture を利用した際に Bloom 効果が反映されないことがあるという現象が起きました。

この問題を解決するために、以下のコードを使用しテストを行いました。

using UnityEngine;
using UnityEngine.UI;

public class BlogComponent : MonoBehaviour
{
    [SerializeField]
    private Camera _targetCamera;
    [SerializeField]
    private RawImage _targetRawImage;
    
    private RenderTexture _renderTexture;
    
    private void Start()
    {
        var width = Screen.width;
        var height = Screen.height;
        _renderTexture = RenderTexture.GetTemporary(width, height, 16);
        _targetCamera.targetTexture = _renderTexture;
        _targetRawImage.texture = _renderTexture;
    }

    private void OnDestroy()
    {
        if (_renderTexture != null)
        {
            RenderTexture.ReleaseTemporary(_renderTexture);
            _renderTexture = null;
        }
    }
}

Bloom、つまり HDR カラーを利用する際には RenderTexture の FormatがB10G11R11_UFloatPack32 または R16G16B16A16_SFloatにする必要があります。デフォルトの RenderTexture のフォーマット R8G8B8A8_UNorm では、輝度の広範な変動を正確に表現するのが難しく、Bloom 効果には適していません。

そのため、Bloomを利用したい場合は以下のようにフォーマットを指定してあげる必要があります。

_renderTexture = RenderTexture.GetTemporary(width, height, 16, GraphicsFormat.R16G16B16A16_SFloat);

この変更により、RenderTexture にも正しく Bloom 効果が反映されるようになりました。

【Unity】TextMeshPro を利用した Prefab の Addressables 対応時の問題

Unity で TextMeshPro を使用する際に、フォントアセットを Addressable に対応させない場合、各 UI のバンドルにフォントデータが含まれ、バンドルのサイズが大きくなってしまいます。

一方で、フォントアセットを Addressable に対応させた場合は、フォントアセットのバンドルを参照するため、UI のバンドルにフォントデータは含まれません。これにより、"Bundle File Size" が大幅に減少します。

このようなバンドル作成時の重複問題は、"Addressable Reports"の"Potential Issues"から確認できます。問題がなければ何も表示されないため、表示された場合は確認することをお勧めします。

Addressableを利用する際には、フォントアセットの対応を適切に行うことで、バンドルの効率的な管理が可能となります。問題が発生した場合は、"Addressable Reports"を活用して早めに対処することがポイントです。