Fragment Shader

Responsabilidades

Blending, Computaćão do modelo de iluminaćão, mapeamento ambiental (environment mapping)

Exemplos:

Código comum a todos os exemplos:

struct VertexShaderInput
{
    float4 Position : POSITION0;
    float4 Normal : NORMAL0;
    float2 texcoords : Texcoord0; 
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
    float2 texcoords : Texcoord0; 
};

// código do vertex shader
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;
    output.Position = mul(input.Position, ModelViewProj);
    output.texcoords = input.texcoords; 

    return output;
}

geração de cores/texturas

Textura de um quadrado

float4 CreateRectTexture(VertexShaderOutput input) : COLOR0
{
    float4 color;
    if( input.texcoords.x < 0.05 || input.texcoords.y < 0.05 || 
        input.texcoords.y > 0.95 || input.texcoords.x > 0.95 ){
        color= float4( 1,0,0,1 );
    } else{
        color = float4(0,0,0,0);
    }

    return color;;
}
quadradoMiniatura.png

Textura de tijolos (simples)

float4 CreateBrickTexture(VertexShaderOutput input) : COLOR0
{
    input.texcoords = float2( ceil( input.texcoords.x / 0.05 ), ceil( input.texcoords.y / 0.05 ) );

    float4 brickColor = float4( 1,1,1,1 );

    if( fmod( input.texcoords.y, 6) < 2  ){    
        if( fmod( input.texcoords.y, 3) < 2 && fmod( input.texcoords.x, 4) < 3 ){
            brickColor = float4(1,0,0,1);
        }
    } else {
        input.texcoords.x += 2.0;
        if( fmod( input.texcoords.y, 3) < 2 && fmod( input.texcoords.x, 4) < 3 ){
            brickColor = float4(1,0,0,1);
        }
    }

    return brickColor;
}
brickMiniatura.png

Gradiente simples

float4 distancia(VertexShaderOutput input) : COLOR0
{
    float distance = distance( input.texcoords, float2(0.5, 0.5) );

    return float4( distance, distance, distance, 1);
}
gradienteMiniatura.png

Gradiente 2

float4 gradiente(VertexShaderOutput input) : COLOR0
{
    float4 color1 = float4(0.7,0.2,0,1);
    float4 color2 = float4(0.1, 0.3, 0.7,1);
    float4 diff = color2-color1;

    float distance = distance( input.texcoords, float2(0.5, 0.5) );
    if( distance == 0 )
        diff = 0;
    else
        diff *= distance;

    return color1 + diff;
}
gradiente2Miniatura.png

Gradinete 2 realizado de modo alternativo

float4 gradienteAlternativo(VertexShaderOutput input) : COLOR0
{
    float4 color1 = float4(0.7,0.2,0,1);
    float4 color2 = float4(0.1, 0.3, 0.7,1);

    float distance = distance( input.texcoords, float2(0.5, 0.5) );

    return lerp( color1, color2, distance );
}
gradiente2Miniatura.png

Gradiente 4

float4 gradient2(VertexShaderOutput input) : COLOR0
{
    float4 color1 = float4(0.7,0.2,0,1);
    float4 color2 = float4(0.1, 0.3, 0.7,1);
    float4 diff = color2-color1;

    float distance = 2 * distance( input.texcoords, float2(0.5, 0.5) );
    diff /= distance;

    return color1 + diff;
}
gradiente3.png

Gradiente "errado"

float4 gradienteErrado(VertexShaderOutput input) : COLOR0
{
    //float value = noise( input.texcoords );
    float2 value = input.texcoords;

    return float4( value, value );
}
gradiente4Miniatura.png

Mexendo com texturas

Texturas são muito utilizadas em programas shader. Basicamente textura é uma imagem 2D, mas não necessariamente uma textura é usada sempre para imagem, tendo como propósito a aplicação de efeitos como Bump mapping e Environment Mapping. No XNA é necessário declarar no arquivo de efeitos (.fx) dois atributos, um que conterá a textura e o outro um sampler, objeto que acessa as coordenadas de uma textura. Tais variáveis são especificadas no exemplo que se seguirão da seguinte maneira e são como se fossem variáveis globais do shader (são uniforms para serem mais precisos)

Texture rectTexture;
sampler TextureSampler = sampler_state{
    texture = <rectTexture>;
    magfilter = LINEAR;
    minfilter = LINEAR;
    mipfilter = LINEAR;
    addressU = WRAP;
    addressV = WRAP;
};

Aplicando uma textura em um priimitivo através do fragment shader

float4 exibirImagem(VertexShaderOutput input) : COLOR0
{
    float4 color = tex2D( TextureSampler, float2( abs(input.texcoords.x-inv.x), abs(input.texcoords.y-inv.y) ) );

    return color ;
}
texturaMiniatura.png

Aplicação de uma textura transformada de RGB para Escala de Cinza

float4 ColorToGrayscale(VertexShaderOutput input) : COLOR0
{
    float4 color = tex2D( TextureSampler, input.texcoords );
    float3 conv = float3( 0.3, 0.59, 0.11 );
    float value = dot( float3( color.xyz ), conv );

    return float4( value, value, value, 1);
}
texturaPB.png

Binarização

Binarização é transformar uma imagem com L níveis de cor para apenas 2 níveis de cor. Uma implementação simples dela se dá por simplesmente transformar a imagem para a escala de cinza, daí os valores de escala de cinza de 0 a 127 (0.49) são mapeados para preto (0) e de 129 a 255 (0.51 a 1.0) são mapeados para branco (1.0).

float4 Binarizacao(VertexShaderOutput input) : COLOR0
{
    float4 color = ColorToGrayscale( input );

    return round( color );
}
binarizacao.png

Mostra de canais de cor

Uma função simpels disponíveis em diversos editores de imagem é a exibição dos canais de cor em separado da imagem. O mesmo pode ser feito usando shaders, mas para isso, vamos usar uma variável uniforme separada chamada channel

int channel;

A variável channel assume os valores 0 para o canal vermelho, 1 para o canal verde e 2 para o canal azul. O código a seguir mostra o código e os respectivos canais de cor para a imagem de floresta que nós estamos usando como referência.

float4 Binarizacao(VertexShaderOutput input) : COLOR0
{
    float4 color = ColorToGrayscale( input );

    return round( color );
}
texturaVerdeMiniatura.png
texturaVermelhaMiniatura.png
texturaAzulMiniatura.png

Transformação da imagem

Outro efeito que pode ser útil é a transformação da imagem em uma outra. Essa transformação pode esticar e encolher regiões da figura ou mesmo mudar a figura inieira como no próximos shader

Para este shader foi declarada uma variável float denominada opção

float opcao;
float4 mix(VertexShaderOutput input) : COLOR0
{
    const float PI_2=3.14159/2;

    if( opcao == 0 ){
        input.texcoords.x = sin(input.texcoords.x * PI_2);
        input.texcoords.y = cos(input.texcoords.y * PI_2);
    } else{
        input.texcoords.x = cos(input.texcoords.x * PI_2);
        input.texcoords.y = sin(input.texcoords.y * PI_2);
    }
    float4 color = tex2D( TextureSampler, input.texcoords );

    return color ;
}
texturaTransfMiniatura1.png Transformação quando a opção é 0
texturaTransfMiniatura2.png Transformação quando a opção é diferente de 0

Outros três shaders que representam transformações são apresentados logo a seguir. Ambos usam a variável channel definida em um exemplo anterior

float4 anotherMix(VertexShaderOutput input) : COLOR0
{
    if( channel == 0 ){
        const float E=1.71828182845905;

        input.texcoords.x = log(input.texcoords.x * E);
        input.texcoords.y = log(input.texcoords.y * E);
    } else if( channel == 1 ){
        input.texcoords.x = log2(input.texcoords.x * 2);
        input.texcoords.y = log2(input.texcoords.y * 2);
    } else{
        input.texcoords.x = log10(input.texcoords.x * 10);
        input.texcoords.y = log10(input.texcoords.y * 10);
    }
    float4 color = tex2D( TextureSampler, input.texcoords );

    return color ;
}

float4 outroMix(VertexShaderOutput input) : COLOR0
{
    if( channel == 0 ){
        const float E=1.71828182845905;

        input.texcoords.x = log(input.texcoords.x * E+1);
        input.texcoords.y = log(input.texcoords.y * E+1);
    } else if( channel == 1 ){
        input.texcoords.x = log2(input.texcoords.x +1);
        input.texcoords.y = log2(input.texcoords.y +1);
    } else{
        input.texcoords.x = log10(input.texcoords.x *9+1);
        input.texcoords.y = log10(input.texcoords.y *9+1);
    }
    float4 color = tex2D( TextureSampler, input.texcoords );

    return color ;
}

float4 curiosidade(VertexShaderOutput input) : COLOR0
{
    if( input.texcoords.x < input.texcoords.y ){
        input.texcoords.x /= input.texcoords.y;
    } else{
        input.texcoords.y /= input.texcoords.x;
    }

    return tex2D( TextureSampler, input.texcoords );
}

(Pôr imagens aqui)

Links

http://msdn.microsoft.com/en-us/library/bb509635(us.85).aspx

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-Share Alike 2.5 License.