サイトのトップへ戻る

libGDX ドキュメント 日本語訳

サイト内検索

Spritebatch、TextureRegion、Sprite

この記事では、OpenGL を使って画像を描写する方法とlibgdx のSpriteBatchクラスを使って描写を簡略化・最適化する方法についての簡単な概要を記載します。



画像を描写する

元の画像形式(例えばpngなど)から復号化されてGPU にアップロードされた画像のことをTexture と呼びます。 Texture を描写するには、Texture 上の対応するジオメトリの各頂点の位置を指定することで、ジオメトリが設定されてTexture が適用されます。 例えば、Rectangle の四隅とTexture の四隅を対応させるために、ジオメトリをRectangle にしてTexture を適用することができます。 Texture の一部であるRectangle は、 Texture Regionと呼ばれます。

実際に描写を行うには、まずTextureのバインド(すなわちカレントTextureの作成)を行い、そのジオメトリを描写を行うOpenGL へ渡します。 画面上で描写されるTextureのサイズと位置は、ジオメトリとOpenGL viewport 設定の両方によって決まります。 多くの 2D ゲームでは画面解像度に合わせてviewport を設定します。 つまり、ジオメトリはピクセル単位で設定され、それによって画面上の適切な位置とサイズでtexture を描写することが簡単になります。

ゲーム作成では、四角い形状で作成されたTextureを描写することがよくあります。また、同じTexture や同一Texture内の異なる領域を何度も描写することもよくあります。 各Rectangle を同時にGPU へ送って描写するのは非効率です。 その代わりに、同一TextureのRectangle をたくさん設定した後に一度にまとめて GPU へ送ることができます。SpriteBatch クラスがこうした処理を行います。

SpriteBatch には各rectangleを描写するためのテクスチャと座標が渡されます。ジオメトリをGPUへは送らずに集めておきます。 最後に渡されたTextureと異なるTextureが渡されると、SpriteBatchは最後に渡されたTextureのバインドを行い、描写するために集めたジオメトリをOpenGL へ渡し、新しいテクスチャのジオメトリの収集を開始します。

Changing textures every few rectangles that are drawn prevents SpriteBatch from batching much geometry. また、Textureのバインドは負荷が高い操作です。 こうした理由から、ジオメトリのバッチ処理を最大化してTexture の変更を避けるために、大量の小さな画像を大きな画像に格納して、その大きな画像の任意の領域を描写する手法が一般的です。 詳細については TexturePacker を参照してください。



SpriteBatch

アプリケーションでSpriteBatch (ソース)を使用する場合は以下のようになります:

public class Game implements ApplicationAdapter {
    private SpriteBatch batch;

    public void create () {
        batch = new SpriteBatch();
    }

    public void render () {
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // This cryptic line clears the screen.
        batch.begin();
        // Drawing goes here!
        batch.end();
    }
}

SpriteBatchの描写処理は全て、beginメソッドと endメソッドの間で実行する必要があります。 beginメソッドと endメソッドの間で、SpriteBatch以外の描写処理が発生することはありません。

SpriteBatchは動的なテクスチャがないことを想定しています。カスタムシェーダーを使ってあなたが自分でテクスチャをバインドする場合、 以下のコードを使ってその設定をリセットできます。:

Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0);


Texture

Texture クラスは画像ファイルを復号化して、それを GPU メモリに読み込みます。 画像ファイルは "assets" フォルダに置いて下さい。 画像のサイズは、互換性とパフォーマンスの理由から2のべき乗 (16x16, 64x256, など)である必要があります。

private Texture texture;
...
texture = new Texture(Gdx.files.internal("image.png"));
...
batch.begin();
batch.draw(texture, 10, 10);
batch.end();

上記ではテクスチャが作成されて SpriteBatch に渡され、描写がされています。 テクスチャは(10,10)座標の四角い範囲内に描写され、横幅と高さはテクスチャのサイズと等しくなります。 SpriteBatch にはテクスチャを描写するための多くのメソッドが用意されています:

メソッドのシグネチャ 説明
draw(Texture texture, float x, float y) テクスチャの横幅と高さをそのまま使ってテクスチャを描写します
draw(Texture texture, float x, float y,
int srcX, int srcY, int srcWidth, int srcHeight)
テクスチャの一部を描写します。
draw(Texture texture, float x, float y,
float width, float height, int srcX, int srcY,
int srcWidth, int srcHeight, boolean flipX, boolean flipY)
テクスチャの一部を描写し、 widthheightを変更させ、必要に応じて反転を行います。
draw(Texture texture, float x, float y,
float originX, float originY, float width, float height,
float scaleX, float scaleY, float rotation,
int srcX, int srcY, int srcWidth, int srcHeight,
boolean flipX, boolean flipY)
この膨大なメソッドでは、テクスチャの一部を描写し、widthheightを変更し、原点を中心にして拡大縮小と回転を行い、必要に応じて反転を行います。
draw(Texture texture, float x, float y,
float width, float height, float u,
float v, float u2, float v2)
テクスチャの一部を描写し、widthheightを変更します。 これは、ピクセル座標ではなく0-1範囲のテクスチャ座標を使用する高度なメソッドです。
draw(Texture texture, float[] spriteVertices, int offset, int length) これは、生のジオメトリ、Texture座標、色情報を渡すための高度なメソッドです。これを使って、任意の四辺形(長方形ではない)を描写できます。


TextureRegion

TextureRegion クラス (ソース) ではテクスチャ内の四角範囲を指定でき、テクスチャの一部を描写する場合に便利です。

private TextureRegion region;
...
texture = new Texture(Gdx.files.internal("image.png"));
region = new TextureRegion(texture, 20, 20, 50, 50);
...
batch.begin();
batch.draw(region, 10, 10);
batch.end();

上記の 20, 20, 50, 50 はテクスチャの一部を表す範囲情報で、それを(10,10)の位置に描写します。 SpriteBatchに対して Textureといくつかのパラメータを一緒に渡すことで同じ処理が行えますが、 TextureRegionは一つのオブジェクトでその範囲情報の設定まで行えるので使いやすいです。

SpriteBatchにはTextureRegionを描写するための多くのメソッドが用意されています:

メソッドのシグネチャ 説明
draw(TextureRegion region, float x, float y) TextureRegion の横幅と高さをそのまま使ってTextureRegion を描写します。
draw(TextureRegion region, float x, float y,
float width, float height)
widthheightを変更してTextureRegion を描写します。
draw(TextureRegion region, float x, float y,
float originX, float originY, float width, float height,
float scaleX, float scaleY, float rotation)
widthheightを変更し、原点を中心にして拡大縮小と回転を行ってTextureRegion を描写します。


Sprite

Sprite クラス (ソース) では、 texture region、描写されるジオメトリ、描写される色を設定できます。

private Sprite sprite;
...
texture = new Texture(Gdx.files.internal("image.png"));
sprite = new Sprite(texture, 20, 20, 50, 50);
sprite.setPosition(10, 10);
sprite.setRotation(45);
...
batch.begin();
sprite.draw(batch);
batch.end();

上記の 20, 20, 50, 50 はテクスチャの一部を表す範囲情報で、それを45度回転させて(10,10)の位置に描写します。 SpriteBatchに対して TextureTextureRegionをいくつかのパラメータと一緒を渡せば同様の処理が行えますが、Spriteは一つのオブジェクトでその全ての設定が行えるので使いやすいです。 また、Spriteはジオメトリを保持して必要な時に再計算するだけなので、フレーム間でscaleやscaleやその他プロパティに変更がある場合はわずかですが効率的になります。

Spriteではモデル情報 (位置情報、回転度情報、 など) とビュー情報 (描写されるテクスチャ)を一まとめで扱うので注意してください。 モデルとビューを厳密に分けるデザインパターンを適用する場合、 Spriteを使うのは不適切です。 その場合は、TextureTextureRegionを使用すると良いでしょう。

また、Sprite のコンストラクタでは位置情報を設定することができないので注意してください。 Sprite(Texture, int, int, int, int)を実行しても位置情報の編集は できませんSprite#setPosition(float,float) を実行する必要があります。実行しない場合 sprite は既定の位置( 0, 0)に描写されます。



色付け処理

テクスチャを描写する際に色付けをすることができます:

private Texture texture;
private TextureRegion region;
private Sprite sprite;
...
texture = new Texture(Gdx.files.internal("image.png"));
region = new TextureRegion(texture, 20, 20, 50, 50);
sprite = new Sprite(texture, 20, 20, 50, 50);
sprite.setPosition(100, 10);
sprite.setColor(0, 0, 1, 1);
...
batch.begin();
batch.setColor(1, 0, 0, 1);
batch.draw(texture, 10, 10);
batch.setColor(0, 1, 0, 1);
batch.draw(region, 50, 10);
sprite.draw(batch);
batch.end();

上記では Texture, TextureRegion, Sprite に色付けをして描写しています。 このカラー値は1-0の範囲のRGBA値を使って設定します。ブレンド処理が無効になっている場合、アルファ値は無視されます。



ブレンド処理

ブレンド処理は既定では有効になっています。つまり、テクスチャを描写する場合、半透明の部分は画面上で既に描写されているピクセルと融合されます。

ブレンド処理を無効にした場合、テクスチャは画面上に既に描写されているピクセルと置き換わります。 不要な場合はブレンド処理を常に無効にするとより効果的です。 例えば、画面全体に大きな背景画像を描写する場合、まず最初にブレンド処理を無効にすることでパフォーマンスが向上します:

Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // This cryptic line clears the screen.
batch.begin();
batch.disableBlending();
backgroundSprite.draw(batch);
batch.enableBlending();
// Other drawing here.
batch.end();

Note: 毎フレームごとに画面をクリアするようにしてください。画面をクリアしなかった場合、テクスチャに透明度が設定されていたとしても何百回も繰り返し描写されることによって不透明に表示されてしまいます。 また一部のGPUアーキテクチャでは、毎フレームごとに画面をクリアすると(不透明画像を画面全体に描写する、というクリア方法でも)、パフォーマンスが向上します。



Viewport

SpriteBatch は自分の projection と transformation matrixesを独自に管理します。 SpriteBatch が作成された時、SpriteBatch は現在のアプリケーションのサイズを使ってy-up座標系のorthographic projection を設定します。 begin が呼び出された時、SpriteBatchviewportを設定します。



パフォーマンスのチューニング

SpriteBatchには、GPUへ送る前にバッファできるSpriteの最大数を設定できるコンストラクタが用意されています。 最大数が少なすぎる場合は、GPUに対する余計な呼び出しが発生してしまいます。 最大数が大きすぎる場合は、 SpriteBatchに対して必要以上のメモリが使用されてしまいます。

SpriteBatchにはmaxSpritesInBatchという名前のpublic int 型フィールドがあります。 これはSpriteBatchが作成されてから破棄されるまでに、GPUへ一度に送ったSpriteの最大数を示します。 SpriteBatchにとても大きなバッファサイズを設定してからこのフィールドを確認すれば、最適なバッファサイズを決めるのに役立つでしょう。 最大値はmaxSpritesInBatchと同じか、少し大きい値にすると良いでしょう。 このフィールドに0を設定し、任意のタイミングでバッファをリセットすることができます。

SpriteBatch には renderCallsという名前の public int型フィールドがあります。 end が呼び出された後、このフィールドには直近のbeginendが呼び出されるまでの間に、何回ジオメトリがGPU へ一括送信されたかを示す値が入ります。 これは、異なるtextureをバインドしなければならない時やSpriteBatchのキャッシュがspriteで一杯になってしまった時に発生します。 SpriteBatchのバッファサイズが適切に設定されているのにrenderCallsの数が多い(おそらく 15-20以上)場合は、大量のTextureのバインドが発生していることを示します。

SpriteBatch にはバッファのサイズと数を設定できる追加のコンストラクタがあります。 これは、頂点配列(VAs)ではなく頂点バッファオブジェクト (VBOs)を使用する高度な機能です。 バッファの一覧が保持され、各renderメソッドの呼び出しでは一覧にある次のバッファを使用します(ラップアラウンド方式)。 maxSpritesInBatch が低くて renderCalls が大きい場合は、パフォーマンスが少し向上します。