Vamos aprender XNA? – Parte 19 – Multitexturing

Publicado em 11/10/2011

0


Olá pessoal, tudo certo?!

Este é o primeiro post sobre XNA que escrevo desde o TechEd. Fiquei realmente feliz e satisfeito ao perceber tantas pessoas presentes nas minhas palestras.

No post de hoje, mostro a aplicação de uma técnica simples de multitexturing no “game” que estamos desenvolvendo. Veja o resultado:

image

O post de hoje pode ser percebido como uma “continuação” da parte 13. Se está chegando agora, recomendo a leitura dos outros posts dessa série.

Todo o código fonte está disponível em https://github.com/ElemarJR/VamosAprenderXNA.

IMPORTANTE: O post de hoje é inspirado nas idéias presentes no livro . Realmente achei interessante a proposta do autor e por isso reproduzo o conceito aqui.

Multitexturing, muitas texturas

Multitexturing faz sentindo quando desejamos aplicar mais de uma textura em um mesmo modelo. No “terreno” acima foram utilizadas quatro texturas: Rocha, Areia, Grama e Neve.

Para decidir que textura aplicar, utilizei um mapa de cores.

image

Basicamente, aplico:

  • grama no preto;
  • areia no vermelho;
  • rocha no verde;
  • neve no azul.

O bacana dessa técnica é que podemos modificar a “posição das texturas” simplesmente alterando esse bitmap.

Construindo o Effect

O effect proposto no livro é extramemente simples. Começa pelas texturas e samplers. Observe:


              
texture RTexture;
sampler RTextureSampler = sampler_state
{
        texture = ;
        AddressU = Wrap;
        AddressV = Wrap;
        MinFilter = Anisotropic;
        MagFilter = Anisotropic;
};

texture GTexture;
sampler GTextureSampler = sampler_state
{
        texture = ;
        AddressU = Wrap;
        AddressV = Wrap;
        MinFilter = Anisotropic;
        MagFilter = Anisotropic;
};

texture BTexture;
sampler BTextureSampler = sampler_state
{
        texture = ;
        AddressU = Wrap;
        AddressV = Wrap;
        MinFilter = Anisotropic;
        MagFilter = Anisotropic;
};

texture BaseTexture;
sampler BaseTextureSampler = sampler_state
{
        texture = ;
        AddressU = Wrap;
        AddressV = Wrap;
        MinFilter = Anisotropic;
        MagFilter = Anisotropic;
};

texture WeightMap;
sampler WeightMapSampler = sampler_state
{
        texture = ;
        AddressU = Wrap;
        AddressV = Wrap;
        MinFilter = Anisotropic;
        MagFilter = Anisotropic;
};

            

Depois, parâmetros básicos e estrutura de dados:


              
float4x4 World;
float4x4 View;
float4x4 Projection;

float3 LightDirection = float3(1, -1, 0);
float TextureTiling = 6;

struct VertexShaderInput
{
    float4 Position : POSITION0;
        float2 UV : TEXCOORD0;
        float3 Normal : NORMAL0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
        float2 UV : TEXCOORD0;
        float3 Normal : TEXCOORD1;
};

            

Por fim, os shaders:


              
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);

        output.Normal = input.Normal;
        output.UV = input.UV;

    return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
        float light = dot(
                normalize(input.Normal),
                normalize(LightDirection)
                );
        
        light = clamp(light + 0.4f, 0, 1);

        float3 rtex = tex2D(RTextureSampler, input.UV * TextureTiling);
        float3 gtex = tex2D(GTextureSampler, input.UV * TextureTiling);
        float3 btex = tex2D(BTextureSampler, input.UV * TextureTiling);
        float3 base = tex2D(BaseTextureSampler, input.UV * TextureTiling);

        float3 weightMap = tex2D(WeightMapSampler, input.UV);

        float3 output = clamp(1.0f - weightMap.r - weightMap.g - weightMap.b, 0, 1);
        output *= base;

        output += weightMap.r * rtex + weightMap.g * gtex + weightMap.b * btex;

        return float4(output * light, 1);
}

technique Technique1
{
    pass Pass1
    {
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}

            

Repare como a combinação entre as texturas é feita de forma extremamente simples. Basicamente, utilizamos a “intensidade” de cada elemento no WeightMap para aplicar a textura que desejamos.

A configuração no Game também é bastante simples:


              
var effect = Content.Load("MultitextureTerrainEffect");
effect.Parameters["WeightMap"].SetValue(Content.Load("WeightMap"));
effect.Parameters["BaseTexture"].SetValue(Content.Load("grass"));
effect.Parameters["RTexture"].SetValue(Content.Load("sand"));
effect.Parameters["GTexture"].SetValue(Content.Load("rock"));
effect.Parameters["BTexture"].SetValue(Content.Load("snow"));

            

Bacana!

Era isso!

Smiley piscando

Etiquetado:, ,
Publicado em: Post