set 05, 2008 Registre-se
 
Artigo
Representando Imagens 2D com XNA
Breve abordagem sobre Manipulacao de Texels
Enviado por Luciano José em 15/4/2008 17:51:18

Introdução

No XNA, em geral, a responsabilidade de representar imagens(2D) é atribuída a classe Texture2D.
A classe Texture2D representa uma grade(2D) de Texels; também denominamos isso de Sprite.

Sprite é qualquer imagem atribuída a um jogo. 

Visao geral sobre Texel:
  • Um Texel representa a menor parte de uma Textura.
  •  Um Texel pode ser qualquer um dos formatos disponiveis representados na enumeração SurfaceFormat.
  •  Um Texel é composto de 1 a 4 componentes.

O Formato de Texel mais utilizado é o RGBA(SurfaceFormat.Color). 

O formato RGBA possui 4 componentes  - R(vermelho), G(verde), B(azul), Alpha(canal que determina o quão opaco é o texel) - cada componente possui 8-bit´s, ou seja, cada texel usa um valor de 32-bit´s para representar a sua cor.

Formas de obtenção de uma Textura no XNA

No XNA, é muito comum obter uma textura através do código a seguir:

protected override void LoadContent()
{
         ...               
        
      this.myTexture = this.Content.Load<Texture2D>(“...”);
     
...

}

O código acima ler uma textura através do Contet Pipeline.

 O Content Pipeline provê o suporte dos tipos de imagens a seguir: .bmp, .dds, .dib, .hdr, .jpg, .pfm, .png, .ppm e .tga

Você também pode instanciar um objeto Texture2D. Fazendo assim, para obter algum resultado visual proveniente dessa instância, você precisa manipular a cor de cada texel através de “código C#”.
 
Logo, temos 2 formas para obtenção de uma Textura:
 
  1. Através do Content Pipeline;
 
  1. Instanciando(explícitamente) uma Textura.
 
Existe também uma outra maneira, que é através do método Texture2D.FromFile.
 
Mais informações sobre o Método FromFile da classe Texture2D e aonde utilizá-lo, no artigo do Shinji abaixo:
 

Instanciando um objeto Texture2D

Observe o construtor da classe Texture2D:

 
public Texture2D (
         GraphicsDevice graphicsDevice,
         int width,
         int height,
         int numberLevels,
         ResourceUsage usage,
         SurfaceFormat format
)
graphicsDevice – usado para mostrar a textura na tela.
 
width – a largura, em pixels, da textura.
 
height – a altura, em pixels, da textura.
 
numberLevelsquantidade de pequenas versões da textura; utilizadas quando a textura é redimensionada para preencher uma área menor que o tamanho da textura original. Geralmente, o numero de níveis utilizado é 1.
 
usage – indica o comportamento da textura.
 
format – indica o formato de cada Texel.
 
Como abordado anteriormente, a classe Texture2D representa uma grade(2D) de Texel´s. Então, saber como manipular os Texel´s, é uma tarefa relevante quando se está instanciando(explícitamente) uma textura.
 
A classe Texture2D, provê 2 métodos importantes para manipulação de seus texel´s:
 
  • Texture2D.GetData – Copia os dados da texture para um “array”.
  • Texture2D.SetDate – Copia um “array” de dados para uma textura.

Demonstração 

Para esta demonstração, não será necessário a utilização do método GetData, pelo fato da Textura, quando instanciada, estar desprovida de qualquer tipo de cor, como mostrado na foto a seguir:
 

Observe o local do breakpoint após o objeto ser instanciado - observação dos texel´s da texetura. Na foto, o array de cores contém 100 elementos com cada elemento composto de 4 componentes(RGBA) de valor 0.

Será criado o método criaTexturaSimples, com a seguinte assinatura:
 
void criaTexturaSimples(ref Texture2D textura);
 
Esse método será chamado dentro do método LoadContent e terá como função: criar uma textura que tenha todos os seus Texel´s de uma única cor; uma textura unicolor(que tem só uma cor). Quando isso(a textura) for renderizada na tela, você notará uma forma geometrica de quatro lados e uma única cor.
 
Observe o método:
 
void criaTexturaSimples(ref Texture2D textura)
        {
            //largura e altura da Textura
            int width = 100;
            int height = 100;
         
            //quantidade Total de Texels que a textura vai conter
            int quantidadeTotalDeTexels = width*height;
 
            //instanciando todas as cores que
            //estarão contidas nos texels da textura           
            Color[] coresDaTextura = new Color[quantidadeTotalDeTexels];     
           
            /*instanciando um objeto Texture2D.
             * Para esta demonstração, o formato da superficie a ser usado
             * será do tipo Cor */
            textura = new Texture2D(this.GraphicsDevice, width, height, 0,
                TextureUsage.None, SurfaceFormat.Color);
 
/*Já instanciada, agora a textura já contém todos os Texel´s no
             * formato informado no seu construtor.
             * Neste momento, para obter algum resultado visual, é necessario
             * atribuir uma cor a cada Texel - o código a seguir faz isso.*/
            for (int i = 0; i < quantidadeTotalDeTexels; i++)
            {
                coresDaTextura[i] = Color.Blue;
            }
 
            //modifica os dados atuais da textura para o array de cores processados no
            //bloco de codigo anterior
            textura.SetData<Color>(coresDaTextura);
 
            //Por fim, a textura tem todos os Texel´s com cores atribuidas.
            //Nesta demonstração os Texel´s contêm a cor branca
        }
 
 

Entendendo o que foi feito de maneira Gráfica:

 
Foi criado um textura de largura e altura: 100. Fica inviável demonstrar 10.000 texel´s, portanto, imagine uma textura com altura e largura: 4. Observe a imagem: 

 

  

Neste caso, cada célula da “matriz” é um Texel. Logo, temos um amontoado de Texel´s dispostos de forma Bidimensional(formado por linhas e colunas); como o proprio nome sugere – Texture2D.
 
Observe o código:
 
for (int i = 0; i < quantidadeTotalDeTexels; i++)
            {
                coresDaTextura[i] = Color.Blue;
            }
 
 

Do ponto de vista da textura, os Texel´s da textura são acessados semelhante a foto abaixo:

A linha vermelha, juntamente com as setas preta, representa o fluxo com que o loop(for) está acessando os texels.
 
Se olharmos do ponto de vista do array de cores, ele está sendo acessado, conforme mostrado na figura abaixo:
  
 
 
 

 

Cada célula do vetor unidimensional, representa um Texel e este, recebe a cor azul.

 
Com o array de cores preenchidos, agora só falta atribuir as cores ao texel´s da textura, a linha de código abaixo faz isso:
 
            textura.SetData<Color>(coresDaTextura);
 

Observe graficamente:

 

O método SetData, preenche a textura com as cores fornecidas no array de cores. 

Neste momento a textura já está pronta para ser renderizada na tela e mostrar algum tipo de resultado visual. O resultado visual obtido é uma forma geométrica com 4 lados e totalmente azul.

Criando uma Bandeira

Para a criação desta bandeira, o array de cores será acessado em sua forma “nativa”; o acesso se dará através de linhas e colunas tornando possível uma melhor manipulação dos Texel´s.
 

Observe a bandeira pronta:

 
Bandeira ao lado do quadrado azul. Da esquerda para direita, as cores da bandeira: Purple, Pink and Yellow.
 
Observe a assinatura do método para construção da bandeira acima:
 
void criaBandeira(ref Texture2D bandeira);
 
Esse método é semelhante ao método mostrado anteriormente, nomeado: criaTexturaSimples. 
 
 
 
void criaBandeira(ref Texture2D bandeira)
        {
//variavel auxiliar para acesso aos campos do array de cores
            int aux;
 
            //largura e altura da Textura
            int width = 500;
            int height = 250;
 
            //quantidade Total de Texels que a textura vai conter
            int quantidadeTotalDeTexels = width * height;
 
//A Bandeira criada aqui(semelhante a varias existentes na vida real),
            //é composta por 3 retangulos iguais e com cores diferentes
            int tercaParte = width / 3;
            ...
           
 
/*Já instanciada, agora a textura já contém todos os Texel´s no
             * formato informado no seu construtor.
             * Neste momento, para obter algum resultado visual, é necessario
             * atribuir uma cor a cada Texel - o código a seguir faz isso.*/
            for (int i = 0; i < height/*linha*/; i++)
            {
                //"Prendemos" a linha, e "andamos" com as colunas
 
                for (int j = 0; j < width/*coluna*/; j++)
                {
                    aux = i * width + j;
                   
                    if (j < tercaParte)
                        coresDaTextura[aux] = Color.Purple;
                    else if (j < (tercaParte * 2))
                        coresDaTextura[aux] = Color.Pink;
                    else
                        coresDaTextura[aux] = Color.Yellow;
                }               
            }
...
        }
 
Entendendo o Código de criação da Bandeira:
 
A bandeira criada e mostrada acima, tem 3 faixas de “mesmo tamanho” na vertical. A variavel tercaParte é reponsavel por guardar a largura de cada faixa. Como são 3 faixas, temos:
 
tercaParte + tercaParte + tercaParte = larguraTotalDaTextura;
Obs.: Nem sempre a soma das 3 partes será exatamente igual a largura total da textura, entretanto isso não afetará a textura visualmente.
 
Observe a linha de código do método criaBandeira:
 

int tercaParte = width / 3;

 

Representação gráfica da situação:  

 

for (int i = 0; i < height/*linha*/; i++)
            {
                //"Prendemos" a linha, e "andamos" com as colunas
 
                for (int j = 0; j < width/*coluna*/; j++)
                {
                    aux = i * width + j;
                    
                    if (j < tercaParte)
                        coresDaTextura[aux] = Color.Purple;
                    else if (j < (tercaParte * 2))
                        coresDaTextura[aux] = Color.Pink;
                    else
                        coresDaTextura[aux] = Color.Yellow;
                }               

            }

 

O fluxo de acesso ao array de cores: 

 

Demonstrações feitas acima:  textureproject.zip 44965 bytes

 

Sugestão de Texturas instanciadas e manipuladas

 3 Sugestões("tarefa de casa") para você fazer e praticar o que foi abordado acima.

1. Criar as faixas da bandeira no formato horizontal, como mostrado na figura abaixo: 

 

2. Criar a bandeira acima, com o fluxo de acesso aos Texel´s do array de cores mostrado na imagem abaixo: 

3. Instanciar(explícitamente) um objeto Texture2D, e criar uma moldura circular conforme mostrado na figura abaixo: 

Observe que a região circular da textura está desprovida de cor, ou seja, você pode ver o que "está por trás" dela.

Leia mais sobre o assunto:

Artigo do José Ferreira: http://www.sharpgames.net/Artigos/Tutorial+de+XNA+-+Parte+IV.xna


 Todas as imagens utilizadas neste artigo, foram criadas e/ou editadas com a ferramenta Microsoft Expression Design 2 Beta.

Dúvidas, Críticas e Sugestões são bem vindas.

Obrigado!


Sobre o Autor

lucianoJose
Luciano José
MCP, MCTS. Administrador do SharpGames. Meu Blog: lucianojosefj.spaces.live.com

Clique para avaliar:

Comentários
" Obrigado aew Jalf vlw mesmo!"
Enviado por lucianoJose em 22/4/2008 11:37:56:
 
" Essa técnica é muito boa para criar texturas dinâmicas ou mesmo para aplicar efeitos pixel-a-pixel em texturas sem usar shaders. Muito bom!"
Enviado por jalf em 15/4/2008 21:01:14:
 

Adicione seu Comentário   Voltar
AdSense

Amazon

Logos do XBox 360, XNA e Games For Windows