Artigo
Texturizando Primitivas Graficas com XNA
Texturizacao com mapeamentos parciais, completos e com um grid de Imagens. Alem de texturizar pontos.
Enviado por Luciano José em 4/5/2008 0:00:00

 

Para melhor proveito do material abaixo, será admitido que você tenha conhecimento nos tópicos:

Primitivas Gráficas com XNA – Artigo vital para o entendimento do que será proposto ao longo de todo o material
 
 
Usando um banco ou grid de imagens com o XNA – Esse artigo será vital para a 2º Demonstração abordada mais adiante.
 
 

Introdução

 
Texturização é o ato de aplicar imagens à superfície de objetos primitivos.
Qualquer objeto que aparece em um jogo, foi texturizado; foi aplicado uma textura(um objeto retangular, composto por texels) a algum ou alguns objetos primitivos que formam, na maioria das vezes, um retângulo.
 
Os pontos(texels) da textura podem ser acessadas através de coordenadas, geralmente conhecidas como UV ou mesmo XY.
 
Quando se vai texturizar algo, essas coordenadas, UV ou XY, podem assumir como valor mínimo 0(zero) e valor máximo 1.


Essas coordenadas(UV ou XY) informam um ponto na textura. Entenda os valores mínimos e máximos das coordenadas estando entre 0% e 100%. Observe o esquema abaixo:
 
  • Valor Mínimo: 0(zero) - um ponto da textura que equivale a 0%
 
  • Qualquer valor entre 0 e 1, por exemplo: 0.5f - um ponto da textura que equivale a 50% - 0.25f - um ponto da textura que equivale a 25%
 
  • Valor Máximo: 1 equivalendo a 100%
 
Essas equivalências valem tanto para a largura(X ou U) como para a altura(Y ou V) da textura.
 

Tipos de Vértices que possibilitam a texturização

 
O XNA FrameWork provê 3 tipos de vértices que permitem armazenar, e conseqüentemente, permitem que uma textura seja aplicada a este(s) objeto(s) primitivo(s):
  • VertexPositionTexture
  • VertexPositionColorTexture
  • VertexPositionNormalTexture
Para as demonstrações abaixo, será utilizado o tipo de vértice: VertexPositionTexture.
Esse tipo de vértice(VertexPositionTexture) armazena a posição em que o vértice estará no espaço e também, a coordenada da textura a ser mapeada para o vértice.
 

1º Demonstração – Texturização parcial e Total de Texturas em objetos retangulares

O responsável pela texturização é o Shader. Nas demonstrações abaixo, será utilizado o Shader provido pelo XNA FrameWork, o objeto BasicEffect.

///
/// Shader provido pelo XNA.
/// Reponsavel por renderizar as primitivas
///
BasicEffect basicEffect; 

Levando em consideração que uma textura é um objeto retangular e para representá-lo, na maioria dos casos precisa-se de no mínimo 4 vértices. Para o propósito deste material, como anunciado anteriormente, os vértices serão do tipo VertexPositionTexture. 

Nesta demonstração, serão utilizadas 2 “retângulos independentes” para aplicar a mesma textura com formas diferentes de mapeamento. Abaixo, observe os 2 arrays de vértices que “abraçarão” os vértices e suas propriedades de posição e coordenadas da textura.
///
/// Será aplicada uma textura completa
///
VertexPositionTexture[] fullTextureTriangleFan;
 
///
/// Será aplicada uma textura parcial; uma parte da textura,
/// neste caso, será a metade
///
VertexPositionTexture[] partialTextureTriangleFan;
 
O método LoadContent desta demonstração:
protected override void LoadContent()
{
. . .
 
//Os 2 metodos de definição, foram chamados no metodo LoadContent,
//pelo fato deles utilizarem valores da instância textura
this.define_FULL_Rectangular_Object(this.posicaoDaTexturaCompleta);
this.define_Partial_Rectangular_Object(this.posicaoDaTexturaParcial);
 
this.basicEffect = new BasicEffect(this.GraphicsDevice, null);
 
. . .
 
//Abilita a texturização; permiti que a textura seja aplicada           
this.basicEffect.TextureEnabled = true;
 
/*À toda primitiva renderizada por este efeito(basicEffect), e
* que tem a capacidade de guardar coordenadas de textura,
* a ela será aplicada esta textura*/           
this.basicEffect.Texture = textura;
 
base.LoadContent();
}
Toda essa 1º Demonstração, vai girar em torno destes 2 métodos: define_FULL_Rectangular_Object e define_Partial_Rectangular_Object.
 

Acessando pontos da textura

Inicialmente serão definidos 4 vértices do tipo VertexPositionTexture. Observe nas imagens abaixo, como seriam definidas as coordenadas de Textura dos 4 vértices, se o objetivo fosse:
 
  • obter uma textura mapeada por completo na superfície delimitada pelos 4 vértices:
 
      Foto 1
 

O código do método define_FULL_Rectangular_Object, faz o que foi abordado no ponto acima, e também, o que está sendo mostrado Foto 1:

 

///
/// Define um objeto retangular para o array de vertices FullTextureTriangleFan
///
///A Textura será renderizada a partir desse ponto
void define_FULL_Rectangular_Object(Vector2 posicao)
{
 
   //Instanciado os 4 vertices
            this.fullTextureTriangleFan = new VertexPositionTexture[4];
 
            fullTextureTriangleFan[0].Position.X = posicao.X;
            fullTextureTriangleFan[0].Position.Y = posicao.Y;
            fullTextureTriangleFan[0].TextureCoordinate = new Vector2(0, 0);
 
            fullTextureTriangleFan[1].Position.X = posicao.X + this.textura.Width;
            fullTextureTriangleFan[1].Position.Y = posicao.Y;
            fullTextureTriangleFan[1].TextureCoordinate = new Vector2(1, 0);
 
            fullTextureTriangleFan[2].Position.X = posicao.X + this.textura.Width;
            fullTextureTriangleFan[2].Position.Y = posicao.Y + this.textura.Height;
            fullTextureTriangleFan[2].TextureCoordinate = new Vector2(1, 1);
 
            fullTextureTriangleFan[3].Position.X = posicao.X;
            fullTextureTriangleFan[3].Position.Y = posicao.Y + this.textura.Height;
            fullTextureTriangleFan[3].TextureCoordinate = new Vector2(0, 1);
  }
 
  • Obter uma textura mapeada parcialmente na superfície delimitada pelos 4 vértices.

Foto 2 – Texturizando 100% da altura da textura e 50% da largura da textura. Toda a região escurecida será desprezada.

 

Observe na foto abaixo(Foto 3) que tanto a largura como a altura entre um vértice e outro, quando se comparado a Foto 1. Entretanto, o objetivo aqui, é mapear a textura parcialmente, e por padrão, quando o que foi mapeado da textura for menor que a superfície do objeto retangular(os vértices dispostos de forma retangular), isso será “esticado” para preencher toda a superfície do objeto retangular. A Foto 3 demonstra o que aconteceu: 

 
 
Foto 3 – Apenas a metade da textura(a metade das larguras) foi mapeada, então, como a superfície formada pelos vértices é maior que essa região mapeada, a textura será “esticada” para preencher.
 

O código do método define_Partial_Rectangular_Object, faz o que foi discutido neste ponto:

 

        ///
        /// Define um objeto retangular para o array de vertices PartialTextureTriangleFan
        ///
        ///A Textura será renderizada a partir desse ponto
        void define_Partial_Rectangular_Object(Vector2 posicao)
        {
            //Instanciado os 4 vertices
            this.partialTextureTriangleFan = new VertexPositionTexture[4];
 
            partialTextureTriangleFan[0].Position.X = posicao.X;
            partialTextureTriangleFan[0].Position.Y = posicao.Y;
            partialTextureTriangleFan[0].TextureCoordinate = new Vector2(0, 0);
 
            partialTextureTriangleFan[1].Position.X = posicao.X + this.textura.Width;
            partialTextureTriangleFan[1].Position.Y = posicao.Y;
            partialTextureTriangleFan[1].TextureCoordinate = new Vector2(0.5f, 0);
 
            partialTextureTriangleFan[2].Position.X = posicao.X + this.textura.Width;
            partialTextureTriangleFan[2].Position.Y = posicao.Y + this.textura.Height;
            partialTextureTriangleFan[2].TextureCoordinate = new Vector2(0.5f, 1);
 
            partialTextureTriangleFan[3].Position.X = posicao.X;
            partialTextureTriangleFan[3].Position.Y = posicao.Y + this.textura.Height;
            partialTextureTriangleFan[3].TextureCoordinate = new Vector2(0, 1);
        }
 

O resultado final com o modo de preenchimento FillMode.WireFrame dos 2 objetos retangulares definidos:

Foto 4

 

O resultado final com o modo de preenchimento padrão, o FillMode.Solid:

Foto 5
 
Projeto para Download:  texturizandoumretangulo.zip 262363 bytes
 

2º Demonstração – Texturização com um grid de Imagens 

 

 Quando uma textura for mapeada por completa, e a região da superfície dos vérticies, for menor que toda textura mapeada – toda a região fora dos limites da superfície dos vértices, não será mostrada na tela.

Esse conhecimento será útil para desenhar alguma região interna de um grid de imagens. Nesta demonstração, praticamente toda a classe Game1 é semelhante ao código da 1º demonstração. O que muda de fato, é o método que irá definir o array de vértices.
 

Observe o grid que será utilizado:

Imagens – Grid de imagens retirado do artigo publicado no SharpGames - Usando um banco ou grid de imagens com o XNA

 

O resultado final obtido será semelhante ao que foi mostrado no artigo de André Furtado: Usando um banco ou grid de imagens com o XNA
 

 

 

Campos Relevantes para esta demonstração

 
          ///
        /// A posicao do passarinho vermelho na tela
        ///
        Vector2 posicao1;
 
        ///
        /// A posicao do passarinho verde na tela
        ///
        Vector2 posicao2;
 
        ///
        /// Os campos (X,Y) do retangulo vão determinar a origem do local
        /// aonde o retangulo será definido na textura.
        ///
        Rectangle rectangle1;
 
        ///
        /// Os campos (X,Y) do retangulo vão determinar a origem do local
        /// aonde o retangulo será definido na textura.
        ///
        Rectangle rectangle2;
 

O método Initialize inicializando os campos acima, com os mesmo valores utilizados no Artigo Usando um banco ou grid de imagens com o XNA:

 

protected override void Initialize()
{
 
            // posicao do passarinho vermelho na tela
            this.posicao1 = Vector2.Zero;
 
            //Nesta demonstração, a posicao(X e Y) e
            //dimensões(Width e Height) escolhidas servirão para
            // mostrar o passarinho vermelho
            this.rectangle1 = new Rectangle(275, 0, 140, 90);
 
            // posicao do passarinho verde na tela
            this.posicao2 = new Vector2(200, 200);
 
            //Nesta demonstração, a posicao(X e Y) e
            //dimensões(Width e Height) escolhidas servirão para
            // mostrar o passarinho verde
            this.rectangle2 = new Rectangle(275, 90, 140, 75);
 
            base.Initialize();          
}

O método LoadContent chamando os métodos de construção do objeto retangular para desenhar alguma imagem isolada na textura:

 

protected override void LoadContent()
{
            ...
 
            this.define_Rectangular_Object(this