(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

(:3[kanのメモ帳]

SpriteAtlasなどでまとめたTextureから、任意のSpriteのTextureだけを取得する方法【Unity】


このエントリーをはてなブックマークに追加

この記事でのバージョン
Unity 2018.4.0f1


はじめに

処理を軽くするために、複数の画像を一つにまとめて使うというのは常套手段です。

UnityではSpriteAtlasを使ってまとめたり、


f:id:kan_kikuchi:20190531071214j:plain


最初から1つの画像にまとめたものを、Sprite ModeをMultpleにして使う、などの方法があります。


f:id:kan_kikuchi:20190531071743j:plain
f:id:kan_kikuchi:20190531071722j:plain


ただ、このように複数の画像をまとめて使うとSpriteのTextureを取得した時に困った事になります。

例えばSpriteのテクスチャのサイズをログで表示してみると、

//レンダラーからSprite取得
Sprite sprite = GetComponent<SpriteRenderer>().sprite;
    
//テクスチャのサイズをログで表示
Debug.Log(sprite.texture.width);

f:id:kan_kikuchi:20190601063504j:plain


そのSpriteのサイズではなく、元々の大きな画像のサイズが表示されてしまうのです。


f:id:kan_kikuchi:20190601063516j:plain


実はこの内容の記事は既に書いていて、

その時は任意のSpriteの画素値だけを取得する方法を紹介しました。



そして今回は、任意のSpriteのTextureを取得する方法の紹介です!


なお、記事中の画像は以下のアセットを使っております。





GetTextureSameSizeAsSprite

さっそくプログラムですが、やり方はいたってシンプル、

Spriteから元の画像上の位置とサイズを取得し、

その範囲の画素値を取得、さらに画素値からテクスチャを生成しているだけです。

//Spriteと同じサイズ(部分)のTextureを取得する
private Texture2D GetTextureSameSizeAsSprite(this Sprite sprite){
  //Spriteから全体のテクスチャを取得
  Texture2D texture = sprite.texture;

  //スプライトの位置とサイズを取得
  int     x = (int)sprite.textureRect.x,          y = (int)sprite.textureRect.y;
  int width = (int)sprite.textureRect.width, height = (int)sprite.textureRect.height;

  //スプライト部分の画素値だけ抜き出す
  Color[] pixels = texture.GetPixels(x, y, width, height); 

  //画素値を使ってSprite部分だけのテクスチャを作成
  Texture2D newTexture = new Texture2D(width, height);
  newTexture.SetPixels(pixels);
  newTexture.Apply();
    
  return newTexture;
} 


これを先ほどと同じ感じで使ってみると、Spriteと同じサイズが取得出来てるのが分かります。

//レンダラーからSprite取得
Sprite sprite = GetComponent<SpriteRenderer>().sprite;
    
//Spriteと同じ部分のTextureのサイズをログで表示
Debug.Log(GetTextureSameSizeAsSprite(sprite).width);

f:id:kan_kikuchi:20190601064035j:plain


なお画素値を読み込むにはTextureの設定で、Read/Write Enabledを有効にする必要がありますが、


f:id:kan_kikuchi:20190531073916j:plain


Read/Write Enabledを有効にすると、メモリの使用量が 2 倍になるので、注意が必要です。


f:id:kan_kikuchi:20190531073815j:plain


ちなみにTexture2DからSpriteを生成したい場合はSprite.Createを使います。

Sprite sprite = Sprite.Create(
  texture : texture2D,
  rect    : new Rect(0, 0, texture2D.width, texture2D.height),
  pivot   : new Vector2(0.5f, 0.5f)
);




拡張メソッド

先ほどのプログラムを必要になる度に書くのは面倒なので、拡張メソッド にすると便利かもしれません。

using UnityEngine;

/// <summary>
/// Spriteの拡張クラス
/// </summary>
public static class SpriteExtension{

  /// <summary>
  /// Spriteと同じサイズ(部分)のTextureを取得する
  /// </summary>
  public static Texture2D GetTextureSameSizeAsSprite(this Sprite sprite){
    //Spriteのサイズとてスクチャのサイズが同じならそのままテクスチャを返す
    if (Mathf.Approximately(sprite.rect.height, sprite.texture.height)) {
      return sprite.texture;
    }

    //Spriteから全体のテクスチャを取得
    Texture2D texture = sprite.texture;

    //スプライトの位置とサイズを取得
    int     x = (int)sprite.textureRect.x,          y = (int)sprite.textureRect.y;
    int width = (int)sprite.textureRect.width, height = (int)sprite.textureRect.height;

    //スプライト部分の画素値だけ抜き出す
    Color[] pixels = texture.GetPixels(x, y, width, height); 

    //画素値を使ってSprite部分だけのテクスチャを作成
    Texture2D newTexture = new Texture2D(width, height);
    newTexture.SetPixels(pixels);
    newTexture.Apply();
    
    return newTexture;
  } 

}


上記のようなプログラムを用意する事で、

どのSpriteからでも直接GetTextureSameSizeAsSpriteが使えるようになります。

//レンダラーからSprite取得
Sprite sprite = GetComponent<SpriteRenderer>().sprite;
    
//Spriteと同じ部分のTextureのサイズをログで表示
Debug.Log(sprite.GetTextureSameSizeAsSprite().width);

f:id:kan_kikuchi:20190601064035j:plain