Batching Sprite
Autor: KlanPaia | Publicado: 2013-02-02T14:08:00-08:00



Batching Sprite

Se nós tentamos usarmos o debugTexture do tutorial texturas para processar todos os nossos sprites e tiles, as chances de que haja problemas de desempenho são grandes. Isto é porque estamos apenas colocando um sprite em um momento para a GPU. O que nós precisamos é de "lote" sprites para a melhoria do&nbsp;desempenho, por isso usamos um SpriteBatch.




Intro



Como discutido no tutorial texturas, um sprite é nada mais do que um conjunto de vértices que compõem uma forma retangular. Cada vértice contém um certo número de atributos que a definem, tais como:



Posição (x, y) - onde o vértice encontra-se na tela

TexCoord (s, t) - o que a região da nossa textura deseja processar

Cor (r, g, b, a) - o vértice de cor, utilizado para especificar tingimento ou transparência

Doseadores mais sprites são bastante simples de usar, e pode ser parecido com isso no seu jogo:





//called on game creation
public void create() {
    //create a single batcher we will use throughout our application
    spriteBatch = new SpriteBatch();
}

//called on frame render
public void render() {
    //prepare the batch for rendering
    spriteBatch.begin(); 

    //draw all of our sprites
    spriteBatch.draw(mySprite1, x, y);
    spriteBatch.draw(mySprite2, x, y);
    ...

    //end the batch, flushing the data to GPU
    spriteBatch.end();
}

//called when the display is resized
public void resize(int width, int height) {
    //notify the sprite batcher whenever the screen changes 
    spriteBatch.resize(width, height);
}


Primeiro, begin() o batch, nós simplesmente dizemos que ele está em "modo de desenho" e chamamos o use() em nosso programa de shader. Então, chamando spriteBatch.Draw (...) colocamos as informações da vértice do sprite (posição, texcoord, cor) em uma pilha muito grande. Os vértices não são passados ​​para a GPU até que uma das seguintes situações ocorra:




O batch é forçado a render com o end () ou em outra ligação que libera o batch, como flush ()



O usuário tenta desenhar um sprite que usa uma textura diferente do que o último. O batch tem de ser limpado e&nbsp;novamente&nbsp; texturizar antes de podermos continuar



Chegamos a capacidade de nossa pilha, por isso precisamos liberar para começar tudo de novo



Esta é a&nbsp;ideia&nbsp;básica por trás de um doseador sprite. Como você pode ver, usando muitas texturas vai levar a muitas chamadas (como o batch terá de lavar para cada nova textura). É por isso que uma textura atlas (folha de sprite AKA) é sempre recomendado, que nos permite prestar muitos sprites em uma chamada de desenho único.





A API LWJGL-básico inclui uma implementação SpriteBatch mínima para se usar







TextureRegion


Como discutido, para o melhor desempenho, deve-se usar um atlas de texturas e desenhar as regiões dele (AKA sub-imagens) para colocar as sprites em nosso jogo. Para isso temos uma classe TextureRegion. Ela nos permite especificar em pixels a posição do eixo (x, y) e seu tamanho (altura, largura) da nossa imagem&nbsp;



Vamos dar um exemplo, onde queremos tornar nossa Sprite um destaque:













Imagem da Sprite

















Podemos ter uma TextureRegion da Sprite com o seguinte:


//specify x, y, width, height of tile
region = new TextureRegion(64, 64, 64, 64);


Como você pode ver, o &nbsp;TextureRegion nos permite obter sub-imagens sem se preocupar com o cálculo das coordenadas da textura. Podemos, então, desenhar nossa sprite do Batshing Sprite &nbsp;assim:
... inside SpriteBatch begin / end ...
spriteBatch.draw(region, x, y);






Vertex Color


Nós podemos mudar a coloração e transparência de todos os sprites&nbsp;através&nbsp;da "cor de vértice."



O RGB resultante é multiplicada pela cor, textura, assim se utilizou uma textura branca (1, 1, 1, 1) e uma cor especificada na vértice como (1, 0, 0, 1), o resultado seria o vermelho. O componente alfa da cor nos permite ajustar a opacidade dos sprites desenhados na tela.




spriteBatch.begin();

//draw calls will now use 50% opacity
spriteBatch.setColor(1f, 1f, 1f, 0.5f);
spriteBatch.draw(...);
spriteBatch.draw(...);

//draw calls will now use 100% opacity (default)
spriteBatch.setColor(1f, 1f, 1f, 1f);
spriteBatch.draw(...);

spriteBatch.end();

Na série anterior,&nbsp;pensávamos&nbsp;que nossa texturas era um quadrado por ter quatro pontas, mas na realidade o Sprite Batch vai usar dois triângulos adjacentes para representar um sprite retangular. Os vértices podem ser ordenados de maneira diferente dependendo do motor (No LibGDX tende-se a usar da parte inferior para a esquerdo), mas a&nbsp;ideia&nbsp;básica é assim:
















Um única sprite&nbsp;&nbsp;possui dois triângulos ou seis vértices. Cada vértice tem oito atributos (X, Y, S, T, R, G, B, A), que juntos formam Posição, TexCoord e Cor. Isto significa que a cada sprite, estamos empurrando 48 floats para uma pilha! Um Sprite Batcher mais otimizado pode compactar o RGBA em um&nbsp;único&nbsp;float , ou pode abrir mão de algumas cores da vértice.

E agora?


Criar o seu próprio batcher Sprite não é fácil, e requer a compreensão de shaders, buffers de vértice, e matemática matriz básica. Antes de mergulhar nestes tópicos avançados, &nbsp;recomendo ficar mais&nbsp;expete&nbsp;com o SpriteBatcher fornecido para você pelo LWJGL-básico. Alternativamente, você pode usar o LibGDX como a implementação, pois ele é muito semelhante. Você também deve se sentir confortável com GLSL antes de tentar a sua própria batcher Sprite.

Se você ainda está interessado em aprender mais sobre como tudo funciona, veja o ShaderProgram e os artigos SpriteBatcher.

Fonte:&nbsp;https://github.com/mattdesl/lwjgl-basics/wiki/Sprite-Batching