2016-02-18 105 views
0

  • 高斯模糊手柄alpha透明度

    1. 我使用描述了OpenGL與GLSL着色器做高斯模糊效果的機器人ES 2.0。
    2. 如果沒有alpha通道,它的工作原理是正確的,但是當我有png的alpha通道時,結果會變得太暗,它將會是相同的鏈接:http://www.jhlabs.com/ip/premultiplied_blur.jpg(中間有一個黑暗的效果)。
    3. 而所有的文章說使用預乘alpha,但我不知道如何使用它,是同一個人可以幫助我,謝謝。
  • 我該怎麼辦模糊

    1. 負荷爲png質感
    2. 創建FBO渲染水平模糊
    3. 創建FBO呈現垂直模糊
    4. 渲染結果紋理屏幕
  • 我着色器文件

\t static const char* ULBlurShader_vertexShader = 
 
\t \t "uniform mat4 fpsWorldViewProjectionMatrix;\n" 
 
\t \t "attribute vec4 gInPosition;\n" 
 
\t \t "attribute vec2 gInTex0;\n" 
 
\t \t "varying vec2 varTex0;\n" 
 
\t \t "void main() {\n" 
 
\t \t " \t gl_Position = fpsWorldViewProjectionMatrix * gInPosition;\n" 
 
\t \t " \t varTex0 = gInTex0.xy;\n" 
 
\t \t "}\n"; 
 

 
\t static const char* ULBlurShaderHor_pixelShader = 
 
\t \t "uniform sampler2D sampler0; \n" 
 
\t \t "uniform vec4 fpsGaussBlur; \n" 
 
\t \t "uniform vec4 fpsGaussWeights[65]; \n" 
 
\t \t "varying vec2 varTex0;\n" 
 
\t \t "vec4 gaussBlurHorizontal(const int anRadius,vec2 avBaseCoo, vec2 avSamplerRes)" 
 
\t \t "{ \n" 
 
\t \t " \t float fStartX = avBaseCoo.x - anRadius*avSamplerRes.x; \n" 
 
\t \t " \t vec4 color = vec4(0, 0, 0, 0); \n" 
 
\t \t " \t for (int x = 0; x < anRadius * 2; x++) \n" 
 
\t \t " \t { \n" 
 
\t \t " \t \t color += texture2D(sampler0, vec2(fStartX + x*avSamplerRes.x, avBaseCoo.y))*fpsGaussWeights[x/4][x % 4]; \n" 
 
\t \t " \t } \n" 
 
\t \t " \t return color; \n" 
 
\t \t "}\n" 
 
\t \t "void main() {\n" 
 
\t \t " \t gl_FragColor.rgba = gaussBlurHorizontal(int(fpsGaussBlur.y), varTex0, vec2(fpsGaussBlur.z, fpsGaussBlur.w)); \n" 
 
\t \t "}\n"; 
 

 
\t static const char* ULBlurShaderVert_pixelShader = 
 
\t \t "uniform sampler2D sampler0; \n" 
 
\t \t "uniform vec4 fpsGaussBlur; \n" 
 
\t \t "uniform vec4 fpsGaussWeights[65]; \n" 
 
\t \t "varying vec2 varTex0;\n" 
 
\t \t "vec4 gaussBlurVertical(const int anRadius,vec2 avBaseCoo, vec2 avSamplerRes)" 
 
\t \t "{ \n" 
 
\t \t " \t float fStartY = avBaseCoo.y - (anRadius*avSamplerRes.y); \n" 
 
\t \t " \t vec4 color = vec4(0, 0, 0, 0); \n" 
 
\t \t " \t for(int y=0; y<anRadius*2; y++) \n" 
 
\t \t " \t { \n" 
 
\t \t " \t \t color += texture2D(sampler0, vec2(avBaseCoo.x, fStartY+y*avSamplerRes.y))*fpsGaussWeights[y/4][y%4]; \n" 
 
\t \t " \t } \n" 
 
\t \t " \t return color; \n" 
 
\t \t "}\n" 
 
\t \t "void main() {\n" 
 
\t \t " \t gl_FragColor.rgba = gaussBlurVertical(int(fpsGaussBlur.y), varTex0, vec2(fpsGaussBlur.z, fpsGaussBlur.w));\n" 
 
\t \t "}\n";

回答

0

是好可惜有透明度的整體問題,會發生什麼其他的顏色通道當像素是透明的。如果您嘗試繪製沒有alpha透明度的圖像(使用RGB1),您將看到透明像素爲黑色。至少在某些情況下,這可能看起來很自然,但不是全部。想象一下,你有一個圖像,具有良好的純白色漸變,從完全不透明度下降到包括完全透明。那麼第一個像素將是(1,1,1,1),某個像素的某個位置可能是(1,1,1,0.5),並且可能接近末尾(1,1,1,0.00X),但接下來具有α爲0的像素將變成(0,0,0,0)而不是(1,1,1,0)。所以這是你正在混合的黑色,你看到了黑色邊框。

因此,看起來PNG出口商做了一個錯誤,因爲所有的透明像素應該仍然是紅色的,但事實並非如此。如果圖像具有不同的顏色(在您的情況下不只是白色或紅色),那麼導出程序可能無法預測這些像素是什麼顏色。所以最終這是一個正確的狀態。

那麼在這種情況下你需要重新平衡透明像素的顏色混合。這也意味着改變你的模糊着色器的工作方式。在計算顏色時(但不是alpha),您需要忽略透明像素,或者甚至更好,您需要根據透明度和alpha通道縮放顏色上的效果。

我會給你一個例子,總結5像素在一定的權重類似於模糊。可以說相對尺度是1,2,5,2,1。你現在正在做的是color = (c1*1 + c2*2 + c3*5 + c4*2 + c5*1)/(1+2+5+2+1),但是你在這個方程中有一個優化,你已經有了一個標準化的值,你可以叫fpsGaussWeights,在我的例子中它是1/11, 2/11, 5/11 ...... (Eleven通過求和(1+2+5+2+1)得到)所以你以c1*1/11 + c2*2/11結束......現在讓我們改變方程以包含alpha值。現在,原來是

color = (c1*1*c1.a + c2*2*c2.a + c3*5*c3.a + c4*2*c4.a + c5*1*c5.a)/(1*c1.a+2*c2.a+5*c3.a+2*c4.a+1*c5.a) 

但是你需要做到這一點只在顏色部分,以便

color.rgb = (c1.rgb*1*c1.a + c2.rgb*2*c2.a + c3.rgb*5*c3.a + c4.rgb*2*c4.a + c5.rgb*1*c5.a)/(1*c1.a+2*c2.a+5*c3.a+2*c4.a+1*c5.a) 

而Alpha通道保留了以前的模糊方程。正如你所看到的,你可能不再包含權重的歸一化值,因爲當乘以alpha通道時,你的權重值的總和不會是1.0。

現在我希望你可以自己在for循環中優化這個方程。如果使用低精度,還要注意溢出。

看看這個爲參考(甚至可能只是工作,但我沒有測試它,甚至仔細檢查它):

int sampleCount = 5; 
    float weights[sampleCount]; 

    vec4 color = vec4(.0); 
    float fullWeight = .0; 
    for(int i=0; i<sampleCount; i++) { 
     float actualWeight = weights[i] * textureColor.a; 
     vec4 textureColor = ; // fetch the pixel 
     color.rgb += textureColor.rgb * actualWeight; // can produce overflow 
     /* 
      We may do the computation on the fly so we do not need to divide in the end. This will remove the overflow issue 
     color.rgb = (color.rgb*fullWeight + textureColor.rgb*actualWeight)/(fullWeight + actualWeight); 
      Leads to: 
     float newWeightResult = (fullWeight + actualWeight); 
     float leftWeight = fullWeight/(fullWeight + actualWeight); //will be less or equal then 1 
     float rightWeight = actualWeight/(fullWeight + actualWeight); //will be less or equal then 1 
     color.rgb = color.rgb*leftWeight + textureColor.rgb*rightWeight; // no overflow 
      The color.rgb /= fullWeight line needs to be removed when using this 
     */ 

     color.a += textureColor.a * weights[i]; 
     fullWeight += actualWeight; 
    } 
    color.rgb /= fullWeight; 

使用,因爲它們仍然可以保持權重。我只使用(1,2,5 ...),因此更容易解釋。

1

我有同樣的問題,尤其是模糊alpha = 0.0像素包圍的文本時。文字會消失,直到無法看到(中圖)。 但是,一旦我在模糊後添加了「Gamma校正」步驟後,我設法得到了更好的結果。

Left: original, Middle: Blur only (practically invisible), Right: Blur+Gamma Correction

所以,你的情況下,模糊完成後,按照這樣的調整RGBA值:

color = pow(color, vec4(1.0/fGamma)) 

哪裏fGamma0.01.0之間的float(我用fGamma=5.0在我的例子)。

這裏是一個很好的解釋的鏈接: https://learnopengl.com/#!Advanced-Lighting/Gamma-Correction

+0

你的意思是「其中1/fGamma是在0.0和1.0之間的浮動」?你使用了哪些陰影代碼?我嘗試了對文本模糊進行伽馬校正,但文本仍然不可見 – PhilLab