Manuseando canal alfa no efeito shader pixel wpf
-
18-09-2019 - |
Pergunta
Existe algo incomum sobre como o componente alfa é tratado em um shader de pixels? Eu tenho um aplicativo WPF para o qual meu artista está me dando imagens em escala de cinza para usar como fundo, e o aplicativo coloriza essas imagens de acordo com o estado atual. Então, escrevi um shader de pixel (usando a infraestrutura da biblioteca de efeitos do shader do WPF Pixel) para usar como efeito em um elemento de imagem. O shader toma uma cor como um parâmetro, que converte para o HSL para que possa manipular o brilho. Então, para cada pixel cinza, ele calcula uma cor cujo brilho é interpolado entre o parâmetro de cor e o branco proporcionalmente ao brilho do pixel de origem.
float4 main(float2 uv : TEXCOORD) : COLOR
{
float4 src = tex2D(implicitInputSampler, uv);
// ...Do messy computation involving src brightness and color parameter...
float4 dst;
dst.r = ...
dst.g = ...
dst.b = ...
dst.a = src.a;
return dst;
}
Isso funciona bem nos pixels em que alfa = 1. Mas onde alfa = 0, os pixels resultantes saem brancos, em vez de exibir o plano de fundo da janela. Então eu fiz uma pequena mudança:
float4 main(float2 uv : TEXCOORD) : COLOR
{
float4 src = tex2D(implicitInputSampler, uv);
if (src.a == 0)
return src;
...
E agora as partes transparentes são realmente transparentes. Por quê? Por que não dst.a = src.a
A declaração na primeira versão faz isso? Infelizmente, mesmo essa é apenas uma correção parcial, porque me parece que os pixels com 0 <alfa <1 estão saindo branco.
Alguém sabe o que não estou entendendo sobre Alpha?
Solução
Depois de mais algumas pesquisas na web, descobri a peça que estava perdendo.
De acordo com Um artigo sobre MSDN: "O WPF usa alfa pré-multiplicado em todos os lugares internamente por vários motivos de desempenho, então é também a maneira como interpretamos os valores de cores no shader de pixel personalizado".
Portanto, a correção acaba sendo lançar uma multiplicação por Alpha:
float4 main(float2 uv : TEXCOORD) : COLOR
{
...
dst.rgb *= src.a;
return dst;
}
E agora minha saída parece como eu espero.
Outras dicas
0 <alfa <1 está saindo branco
Que faixas você está esperando aqui?
Todos os valores estarão no intervalo de 0,0 e 1,0 ... os shaders de pixels não funcionam em intervalos de cores discretos 256, eles são o ponto flutuante em que 1.0 é a intensidade máxima.
Se seus cálculos acabarem definindo valores R/G/B para> 1.0, você vai ficar branco ...
Cara, estou trabalhando em um jogo XNA e tive que usar um shader de pixels em escala de cinza e tive o mesmo problema que você está enfrentando. Eu não estou familiarizado com o ambiente XNA ou não, mas resolvi o problema alterando o SpriteBatch desenho SpriteBlendMode a partir de SpriteBlendMode.none para SpriteBlendMode.alphablend, Espero que isso possa ajudá -lo a saber o motivo.
Saudações,