MRが楽しい

MRやVRについて学習したことを書き残す

Unityでアセットから参照したテクスチャをDestroyすると権限エラーが発生する

本日は Unity の小ネタ枠です。
Unityでアセットから参照したテクスチャをDestroyすると権限エラーが発生する問題の対処です。

前回記事

本記事は以下の前回記事の続きです。
bluebirdofoz.hatenablog.com

アセットから参照したテクスチャをDestroyすると権限エラーが発生する

前回記事のスクリプトを以下のように修正し、コンポーネントが無効化されたときテクスチャデータを Destroy で破棄する処理を追加しました。
・TextureRawImageTest.cs

using UnityEngine;
using UnityEngine.UI;

public class TextureRawImageTest : MonoBehaviour
{
    [SerializeField]
    private Texture2D assetTexture;

    [SerializeField]
    private RawImage targetImage;
    
    void OnEnable()
    {
        targetImage.texture = assetTexture;
    }

    private void OnDisable()
    {
        Destroy(targetImage.texture);
    }
}

このスクリプトを使ってシーンを再生し、オブジェクトを無効化すると以下の権限エラーが発生します。

Destroying assets is not permitted to avoid data loss.
If you really want to remove an asset use DestroyImmediate (theObject, true);

本エラーはアセット内のデータ削除が許可されていないため、発生するエラーです。
本サンプルシーンではテクスチャの参照を Assets フォルダ内のテクスチャを直接参照しており、アセット内のデータの削除を避けるため、削除がキャンセルされました。

エラーメッセージにある通り、削除を強制的に実施したいときは DestroyImmediate (theObject, true); を利用すれば削除可能です。
ただし、Assets フォルダ内のデータが削除されるため、シーンの復旧が困難になる可能性があることに注意が必要です。

Assetsフォルダ内のデータ削除を回避しながらDestroyを行う

Assetsフォルダ内のデータ削除を回避しながらDestroyを行いたい場合は、一旦テクスチャデータをコピーしてコピーインスタンスの参照を RawImage に渡しておきます。
テクスチャデータのコピーには Graphics.CopyTexture が利用可能です。
docs.unity3d.com

以下の通り、サンプルコードを修正しました。
Assets フォルダのテクスチャを参考にコピーデータを作成し、そのコピーデータを削除するため、問題なく Destroy が実行できます。
・TextureRawImageTest.cs

using UnityEngine;
using UnityEngine.UI;

public class TextureRawImageTest : MonoBehaviour
{
    [SerializeField]
    private Texture2D assetTexture;

    [SerializeField]
    private RawImage targetImage;
    
    void OnEnable()
    {
        Texture2D copyTexture = new Texture2D(
            assetTexture.width,
            assetTexture.height,
            assetTexture.format,
            assetTexture.mipmapCount,
            false);
        Graphics.CopyTexture(assetTexture, copyTexture);
        targetImage.texture = copyTexture;
    }

    private void OnDisable()
    {
        Destroy(targetImage.texture);
        Debug.Log("Destroy Success !!");
    }
}