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;;
}
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;
}
Gradiente simples
float4 distancia(VertexShaderOutput input) : COLOR0
{
float distance = distance( input.texcoords, float2(0.5, 0.5) );
return float4( distance, distance, distance, 1);
}
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;
}
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 );
}
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;
}
Gradiente "errado"
float4 gradienteErrado(VertexShaderOutput input) : COLOR0
{
//float value = noise( input.texcoords );
float2 value = input.texcoords;
return float4( value, value );
}
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 ;
}
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);
}
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 );
}
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 );
}
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 ;
}
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