Eu tenho tido muitos problemas ao tentar fazer com que uma função de mistura do OpenGL funcionasse como eu esperava, como o que eu esperaria (ou de qualquer programa de edição de imagem sensível). Como exemplo, usarei essas duas imagens para mesclar (um pouco difícil de ver em fundos brancos para que as cores sejam rotuladas):
Imagens a serem mescladas
É isso que espero que aconteça (e o que acontece no paint.net):
resultado esperado
Obviamente, a função de mistura padrão do opengl faz com que seja assim (muito errado):
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
Após uma tonelada de testes, este é o mais próximo que pude de criar uma função de mistura "boa":
glBlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
Porém, olhando para o resultado original esperado, você notará que algumas das cores são um pouco mais escuras do que deveriam (a parte central esquerda). Especificamente, eles são pré-multiplicados à metade de seu valor de cor (por causa do 0,5 alfa), e não consigo criar uma função que não faça isso (sem causar problemas de mistura estranhos com a parte transparente vermelha quase invisível).
Alguém conhece uma solução para esse problema? Uma que eu tinha era usar alfa pré-multiplicado nas fontes (embora eu não queira fazer isso porque exige trabalho extra para converter todas as cores que eu uso no meu jogo para pré-multiplicar ou apenas escrever algumas coisas em cada sombreador) e fazer assim :
glBlendFuncSeparate (GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA) (sem pré-multiplicação )
Obviamente, isso também está errado, mas este é realmente o único resultado correto que obtive até agora:
glBlendFuncSeparate (GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA) (entradas pré-multiplicadas)
O único problema é: como eu me livraria da pré-multiplicação para exibi-la na tela? Provavelmente, exigiria um ciclo de renderização adicional para cada coisa que eu misturar e isso parece muito complexo para esse problema, então ainda estou procurando uma resposta (é interessante que eu não consiga encontrar nada sobre isso, porque o OpenGL é tão amplamente usado que Eu imagino que alguém tenha encontrado esse problema).
Fontes:
Teste on-line da função de mistura - http://www.andersriggelsen.dk/glblendfunc.php
Imagem da camada inferior - http://i.stack.imgur.com/XjLNW.png
Imagem da camada superior - http: //i.stack.imgur .com / 9CN6w.png
fonte
Respostas:
No seu primeiro exemplo (
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
), você está dizendo para ele misturar cores com base no alfa da imagem que é desenhada na parte superior (o "Primeiro plano"). Portanto, quando você mescla 50% entre a cor do primeiro plano(38,50,168)
e a cor do plano de fundo(38,50,168)
no canto inferior esquerdo da imagem, obtém, sem surpresa, exatamente a mesma cor(38,50,168)
. Porque essa mistura cruzada é exatamente o que você disse ao OpenGL para fazer.A julgar pela sua imagem "esperada", você não deseja fazer uma mistura cruzada entre as duas cores - você deseja sobrepor a cor do primeiro plano à cor de fundo com força total, e não a mistura cruzada entre elas.
Para fazer isso, você deseja usar glBlendFuncSeparate (já que está tratando a cor do plano de fundo de maneira diferente da alfa) e especifique que, durante a operação de mesclagem, o valor alfa do plano de fundo seja tratado como 100%.
Para facilitar a visualização, eis os valores finais de RGB sendo produzidos:
E aqui estão os valores finais de transparência sendo produzidos.
(Essa área de transparência '100%' deve realmente ser rotulada como 99,7% transparente, e a área '50% 'inferior direita deve ser rotulada como 49,7% transparente, ambas devido ao bit vermelho no lado direito da primeira imagem. Além disso, lamento listar números usando "transparência" em vez de opacidade; possivelmente um pouco confuso.)
Se houver problemas específicos, aponte a área da imagem RGB ou alfa que está produzindo valores incorretos.
fonte
GL_ONE
? Caso contrário, as equações alfa parece comdest_alpha = src_alpha * src_alpha + 1 * dest_alpha
(0,0,0)
. De curso é mais escuro do que quando você misturá-la em 50% contra(255,255,255)
.finalAlpha = srcAlpha + destAlpha * (1 - srcAlpha)
efinalColor = ((srcColor * srcAlpha) + (destColor * destAlpha * (1 - srcAlpha))) / finalAlpha
OColor * Alpha
bit no cálculo de cores pode ser feito nos shaders emitindo valores pré-multiplicados, mas não há como dividir pelo finalAlpha para se livrar da pré-multiplicação. (Retirado daqui )Eu tive exatamente o mesmo problema quando queria renderizar um conjunto de objetos de buffer de estrutura sobrepostos, como camadas. O problema é que as funções de mesclagem Open GL são lineares e funcionam quando o fundo de destino é opaco. Mas a equação de mesclagem real para mesclar duas camadas transparentes não é uma equação linear e contém uma parte de divisão.
out_color = {src_color * src_alpha + dest_color * dest_alpha * (1-src_alpha)} / out_alpha
Eu não acho que é possível fazer isso com as implementações atuais do OpengGL. Portanto, como solução alternativa, tive que usar um sombreador de pixels para calcular manualmente a saída de cada pixel.
fonte