7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

同一のTextureから複数のSpriteを生成した時のSetPassCallは1という話+動的にそれを行う方法

Last updated at Posted at 2017-04-15

この記事の内容はタイトルそのままです。
複数画像を1つのテクスチャにパッキングして、そこから元の画像の枚数分Spriteを生成した時、SetPassCallは1で済むということです。
SetPassCallをどれだけ減らせるかが大事なモバイル環境では特に有用なのではないかと思います。

今回はTexturePackingもSprite生成も動的に行うことによって柔軟にこれを活用できる方法を書いていきます。

以下にわかりやすい結果の画像を貼っておきます。
test1.png

(※わかりづらいですが、何もない場合のSetPassCallは2なので増えたのは1だけです。)

なお、Unity5.6.0f3で検証しています。

#はじめに

#検証する

Scriptを1つ書きます。
内容は

  1. WWWを使って、画像を10枚ダウンロードする。
  2. すべての画像がダウンロードできたらそれらを用いて1枚の画像にパッキングする。
  3. パッキングされたテクスチャからSprite.Createを用いて元の画像をSprite化する。
  4. 10個のSpriteRendererに対して3.で作ったSpriteを割り当てる。
TexPacker.cs
using System.Collections;
using System.Collections.Generic;
using UniRx;
using UnityEngine;
using System.Linq;

public class TexPacker : MonoBehaviour
{
    void Start()
    {
        //10個SpriteRendererを取得する
        var spriteRenderers = GetComponentsInChildren<SpriteRenderer>();
        //1.WWWを使って、画像を10枚ダウンロードする
        var streams = Enumerable.Range(0,spriteRenderers.Count()).Select(i => Observable.FromCoroutine<Texture2D>(obs => GetTextures(i.ToString(), obs)));
        //2. すべての画像がダウンロードできたら
        Observable.WhenAll(streams)
            .Subscribe(textures =>
            {
                //2.それらを用いて1枚の画像にパッキングする。
                var packedTexture = new Texture2D(4096, 4096);
                
                //このuvsにはPackした画像のどこに元画像があるかを格納するものです。
                //(x:0.39, y:0.88, width:0.25, height:0.06)のような値がパックした枚数分入ってます。
                var uvs = packedTexture.PackTextures(textures, 0, 4096, false);

                //元画像を切り出すためにPackした画像のWとHをとっておく
                var packedTextureWidth = packedTexture.width;
                var packedTextureHeight = packedTexture.height;

                for (var i = 0; i < spriteRenderers.Length; i++)
                {
                    //3.元の画像をSprite化する。Packした画像のwとh、そしてuvsを使うことで元の画像を切り抜ける。
                    //またメッシュは矩形でいいので、SpriteMeshType.FullRectを指定してSprite化するとき余計な負荷がかからないようにする。
                    var s = Sprite.Create(packedTexture, new Rect(packedTextureWidth * uvs[i].x, packedTextureHeight * uvs[i].y, packedTextureWidth * uvs[i].width, packedTextureHeight * uvs[i].height), Vector2.one * 0.5f, 100, 10, SpriteMeshType.FullRect);
                    
                    //4.10個のSpriteRendererに対して3.で作ったSpriteを割り当てる。
                    spriteRenderers[i].sprite = s;
                }
            });
    }

    //WWWを使ってダウンロードするやつ。今回はStreamingAssetsからロードしている。
    IEnumerator GetTextures(string i, IObserver<Texture2D> observer)
    {
        var filePath = "file:///" + Application.streamingAssetsPath + "/image" + i + ".png";
        var www = new WWW(filePath);
        {
            while (!www.isDone) { yield return null; }
            var tex = www.texture;
            observer.OnNext(tex);
        }
        observer.OnCompleted();
    }
}

この時のHierarchyはこうなっています。
CropperCapture[324].png

#終わり
結果は記事の最初に示した通りです。

以上で複数のSpriteがあってもSetPassCallを1に抑えることができました。
動的にできるのでネット上に画像があってもWWW使ってやればいいと思います。
こういうときにUniRxのWhenAllのありがたみを感じますね。

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?