1. 程式人生 > >OpenGL(十七)Photoshop blend演算法 與 圖層混合模式

OpenGL(十七)Photoshop blend演算法 與 圖層混合模式

使用混合模式可以製作豐富多彩的效果。而OpenGL中可以輕鬆開啟這種模式,但更關鍵的是圖形演算法。本文參照 Photoshop blend演算法 ,介紹如何通過shader,在OpenGL中實現混合效果。

OpenGL中開啟混合

在OpenGL中可以開啟混合模式:

glEnable( GL_BLEND );   // 啟用混合
glDisable( GL_BLEND );  // 禁用關閉混合

統一說法,參照Photoshop,下方圖層、 baseColor 為原色。上方圖層、 blendColor 為混合色。下面介紹 Photoshop blend演算法 的詳細實現。

公式彙總

先上一張公式彙總圖,圖片來自網路,出於效率和效果的平衡,有些公式跟下文提到的有些出入。


正常混合

正常 Opacity

使上方圖層完全遮住下方圖層。

gl_FragColor = baseColor * (1.0-blendColor.a) + blendColor * blendColor.a;

使結果更暗

整個變暗塊都是通過混合色的疊加,使結果更暗。常用的是變亮變暗,程度正常,正片疊底及濾色,較為柔和。

變暗 Darken

兩個圖層中較暗的顏色將作為混合的顏色保留,比混合色亮的畫素將被替換,而比混合色暗畫素保持不變。

gl_FragColor = min(baseColor,blendColor);

正片疊底 Multiply

整體效果顯示由上方圖層和下方圖層的畫素值中較暗的畫素合成的影象效果,任意顏色與黑色重疊時將產生黑色,任意顏色和白色重疊時顏色則保持不變。

gl_FragColor = baseColor*blendColor;

顏色加深 Color Burn

選擇該項將降低上方圖層中除黑色外的其他區域的對比度,使影象的對比度下降,產生下方圖層透過上方圖層的投影效果。

gl_FragColor = vec4(1.0) - (vec4(1.0)-baseColor)/blendColor);

線性加深 Linear Burn

上方圖層將根據下方圖層的灰度與影象融合,此模式對白色無效。

gl_FragColor = baseColor+blendColor-vec4(1.0);

使結果更亮

變亮 Lighten

使上方圖層的暗調區域變為透明,通過下方的較亮區域使影象更亮。

gl_FragColor = max(baseColor,blendColor);

濾色 Screen

該項與“正片疊底”的效果相反,在整體效果上顯示由上方圖層和下方圖層的畫素值中較亮的畫素合成的效果,得到的影象是一種漂白影象中顏色的效果。

gl_FragColor = vec4(1.0) - ((vec4(1.0)-baseColor)*(vec4(1.0)-blendColor));

顏色減淡 Color Dodge

和“顏色加深”效果相反,“顏色減淡”是由上方圖層根據下方圖層灰階程式提升亮度,然後再與下方圖層融合,此模式通常可以用來建立光源中心點極亮的效果。

gl_FragColor = baseColor/(vec4(1.0)-blendColor);

線性減淡 Linear Dodage

根據每一個顏色通道的顏色資訊,加亮所有通道的基色,並通過降低其他顏色的亮度來反映混合顏色,此模式對黑色無效。

gl_FragColor = baseColor+blendColor;

溶合顏色

疊加柔光這塊是使50%灰度上的顏色更亮,50%灰度下的顏色更暗,主要用於增加對比度的,常用的是疊加和柔光,柔光更柔和。

疊加 Overlay

此項的影象最終效果最終取決於下方圖層,上方圖層的高光區域和暗調將不變,只是混合了中間調。

vec4 lumCoeff=vec4(0.2125,0.7154,0.0721,1.0);
float luminance = dot(baseColor.rgb,lumCoeff.rgb);
if(luminance < 0.45)
{
    gl_FragColor = 2.0 *baseColor * blendColor;
}
else if(luminance >0.55)
{
    gl_FragColor = vec4(1.0)-2.0* ((vec4(1.0)-baseColor)*(vec4(1.0)-blendColor));
}
else
{
    vec4 colorT1 =  2.0 *baseColor * blendColor;
    vec4 colorT2 =  vec4(1.0)-2.0* ((vec4(1.0)-baseColor)*(vec4(1.0)-blendColor));
    gl_FragColor =  mix(baseColor,blendColor,(luminance-0.45)*10);
}

柔光 Soft Light

使顏色變亮或變暗讓影象具有非常柔和的效果,亮於中性灰底的區域將更亮,暗於中性灰底的區域將更暗。

gl_FragColor = 2.0 * baseColor * blendColor + baseColor*baseColor -2.0*baseColor*baseColor*blendColor;

強光 Hard Light

此項和“柔光”的效果類似,但其程式遠遠大於“柔光”效果,適用於影象增加強光照射效果。

vec4 lumCoeff=vec4(0.2125,0.7154,0.0721,1.0);
float luminance = dot(blendColor.rgb,lumCoeff.rgb);
if(luminance < 0.45)
{
    gl_FragColor = 2.0 *baseColor * blendColor;
}
else if(luminance >0.55)
{
    gl_FragColor = vec4(1.0)-2.0* ((vec4(1.0)-baseColor)*(vec4(1.0)-blendColor));
}
else
{
    vec4 colorT1 =  2.0 *baseColor * blendColor;
    vec4 colorT2 =  vec4(1.0)-2.0* ((vec4(1.0)-baseColor)*(vec4(1.0)-blendColor));
    gl_FragColor =  mix(baseColor,blendColor,(luminance-0.45)*10);
}

亮光 Vivid Light

根據融合顏色的灰度減少比對度,可以使影象更亮或更暗。

gl_FragColor = baseColor + baseColor * (2*blendColor - vec4(1.0)) / (2*(vec4(1.0)-blendColor));

線性光 Linear Light

根據混合顏色的灰度,來減少或增加影象亮度,使影象更亮。

 gl_FragColor = baseColor + 2 * blendColor - vec4(1.0);

點光 Pin Light

如果混合色比50%灰度色亮,則將替換混合色暗的畫素,而不改變混合色亮的畫素;反之如果混合色比50%灰度色暗,則將替換混合色亮的畫素,而不改變混合色暗的畫素。

gl_FragColor = min(baseColor,2*blendColor - vec4(1.0));

色差顏色

差值 Difference

上方圖層的亮區將下方圖層的顏色進行反相,暗區則將顏色正常顯示出來,效果與原影象是完全相反的顏色。

gl_FragColor = vec4(abs(blendColor-baseColor).rgb,1.0);

排除 Exclusion

建立一種與“差值”模式類似但對比度更低的效果。3lian.com,與白色混合將反轉基色值,與黑色混合則不發生變化。

gl_FragColor =vec4((baseColor + blendColor).rgb - (2.0*baseColor*blendColor).rgb,1.0);

減去 Subtract

gl_FragColor = vec4(baseColor.rgb-blendColor.rgb,1.0);

劃分 Divide

gl_FragColor = baseColor/blendColor;

單圖處理

平滑

與高斯模糊相同,運算元都為1

float kernel[9];
kernel[6]=1;kernel[7]=1;kernel[8]=1;
kernel[3]=1;kernel[4]=1;kernel[5]=1;
kernel[0]=1;kernel[1]=1;kernel[2]=1;
int index=0;
for(int y=0;y<coreSize;y++)
{
    for(int x=0;x<coreSize;x++)
    {
        vec4 currentColor=texture2D(U_MainTexture,V_Texcoord+vec2((-1+x)*texelOffset,(-1+y)*texelOffset));
        color+=currentColor*kernel[index++];
    }
}
color/=9.0;
gl_FragColor=color;

銳化

同上面的平滑效果,其運算元為

kernel[6]=0;kernel[7]=-1;kernel[8]=0;
kernel[3]=-1;kernel[4]=4;kernel[5]=-1;
kernel[0]=0;kernel[1]=-1;kernel[2]=0;
//如果不明顯
gl_FragColor = baseColor + color;

邊緣檢測

同上面的平滑效果,其運算元為

kernel[6]=0;kernel[7]=1;kernel[8]=0;
kernel[3]=1;kernel[4]=-4;kernel[5]=1;
kernel[0]=0;kernel[1]=1;kernel[2]=0;
//如果不明顯
gl_FragColor = baseColor + color;

總結

本文介紹了 Photoshop blend演算法 的OpenGL實現方式。主要是編寫各種Shader。在實際使用的過程中,不一定嚴格按照公式來編寫,只要效果看著正確就可以使用,有時候沒準還會獲得出乎意料的效果呢。