みかづきメモ

主にプログラミング関連のメモ帳 ♪(✿╹ヮ╹)ノ 書いてあるコードは自己責任でご自由にどうぞ。記事本文の無断転載は禁止です。

Unity で Texture2DArray を作成したい

使っているシェーダーの都合上、 Texture2DArray を使う必要が出てきたのだけど、
どうやら Texture2DArray は直接作れないようなので、作り方のメモ。


ドキュメントによると、 Texture2DArray はコードから作成する必要がある様子。
なので、エディター拡張として作成します。

docs.unity3d.com

必要な部分だけ取り出すと、下のようなコードで生成できます。

// List<Texture2D> textures;

private void CreateTexture2DArray()
{
    var path = EditorUtility.SaveFilePanel("保存", "Assets", "tex2darray", "asset");
    if (string.IsNullOrWhiteSpace(path))
        return;
        
    var tex2dArray = new Texture2DArray(textures[0].width, textures[1].height, textures.Count, TextureFormat.ARGB32, true)
    {
        filterMode = FilterMode.Bilinear,
        wrapMode = TextureWrapMode.Clamp,
    };
    
    for (var i = 0; i < textures.Count; i++)
    {
        var texture = CreateReadableTexture2D(textures[i]);
        tex2dArray.SetPixels(texture.GetPixels(0), i, 0);
        DestroyImmediate(texture);
    }
    
    tex2dArray.Apply();
    
    AssetDatabase.CreateAsset(tex2dArray, Path.Combine("Assets", path.Substring(Application.dataPath.Length + 1)));
}

private static Texture2D CreateReadableTexture2D(Texture2D texture)
{
    var renderTexture = RenderTexture.GetTemporary(texture.width, texture.height, 0, RenderTextureFormat.Default, RenderTextureReadWrite.Linear);
    Graphics.Blit(texture, renderTexture);

    var previousTexture = RenderTexture.active;
    RenderTexture.active = renderTexture;

    var readableTexture = new Texture2D(texture.width, texture.height);
    readableTexture.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
    readableTexture.Apply();

    RenderTexture.active = previousTexture;
    RenderTexture.ReleaseTemporary(renderTexture);

    return readableTexture;
}

一部の環境では Graphics.CopyTexture が動かないらしく、
Fallback するのも面倒なので、ReadPixels でコピーしています。
ちなみに、 Fallback する場合は、 SystemInfo.copyTextureSupport で分岐してあげれば良いです。

あとは、 textures に詰め込みたいテクスチャを詰め込んで、
CreateTexture2DArray を読んであげれば作成できます。

ということで、メモでした。