使用混合模式可以制作丰富多彩的效果。而OpenGL中可以轻松开启这种模式,但更关键的是图形算法。本文参照 Photoshop blend算法 ,介绍如何通过shader,在OpenGL中实现混合效果。
在OpenGL中可以开启混合模式:
glEnable( GL_BLEND ); // 启用混合
glDisable( GL_BLEND ); // 禁用关闭混合
统一说法,参照Photoshop,下方图层、 baseColor 为原色。上方图层、 blendColor 为混合色。下面介绍 Photoshop blend算法 的详细实现。
先上一张公式汇总图,图片来自网络,出于效率和效果的平衡,有些公式跟下文提到的有些出入。
使上方图层完全遮住下方图层。
gl_FragColor = baseColor * (1.0-blendColor.a) + blendColor * blendColor.a;
整个变暗块都是通过混合色的叠加,使结果更暗。常用的是变亮变暗,程度正常,正片叠底及滤色,较为柔和。
两个图层中较暗的颜色将作为混合的颜色保留,比混合色亮的像素将被替换,而比混合色暗像素保持不变。
gl_FragColor = min(baseColor,blendColor);
整体效果显示由上方图层和下方图层的像素值中较暗的像素合成的图像效果,任意颜色与黑色重叠时将产生黑色,任意颜色和白色重叠时颜色则保持不变。
gl_FragColor = baseColor*blendColor;
选择该项将降低上方图层中除黑色外的其他区域的对比度,使图像的对比度下降,产生下方图层透过上方图层的投影效果。
gl_FragColor = vec4(1.0) - (vec4(1.0)-baseColor)/blendColor);
上方图层将根据下方图层的灰度与图像融合,此模式对白色无效。
gl_FragColor = baseColor+blendColor-vec4(1.0);
使上方图层的暗调区域变为透明,通过下方的较亮区域使图像更亮。
gl_FragColor = max(baseColor,blendColor);
该项与“正片叠底”的效果相反,在整体效果上显示由上方图层和下方图层的像素值中较亮的像素合成的效果,得到的图像是一种漂白图像中颜色的效果。
gl_FragColor = vec4(1.0) - ((vec4(1.0)-baseColor)*(vec4(1.0)-blendColor));
和“颜色加深”效果相反,“颜色减淡”是由上方图层根据下方图层灰阶程序提升亮度,然后再与下方图层融合,此模式通常可以用来创建光源中心点极亮的效果。
gl_FragColor = baseColor/(vec4(1.0)-blendColor);
根据每一个颜色通道的颜色信息,加亮所有通道的基色,并通过降低其他颜色的亮度来反映混合颜色,此模式对黑色无效。
gl_FragColor = baseColor+blendColor;
叠加柔光这块是使50%灰度上的颜色更亮,50%灰度下的颜色更暗,主要用于增加对比度的,常用的是叠加和柔光,柔光更柔和。
此项的图像最终效果最终取决于下方图层,上方图层的高光区域和暗调将不变,只是混合了中间调。
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);
}
使颜色变亮或变暗让图像具有非常柔和的效果,亮于中性灰底的区域将更亮,暗于中性灰底的区域将更暗。
gl_FragColor = 2.0 * baseColor * blendColor + baseColor*baseColor -2.0*baseColor*baseColor*blendColor;
此项和“柔光”的效果类似,但其程序远远大于“柔光”效果,适用于图像增加强光照射效果。
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);
}
根据融合颜色的灰度减少比对度,可以使图像更亮或更暗。
gl_FragColor = baseColor + baseColor * (2*blendColor - vec4(1.0)) / (2*(vec4(1.0)-blendColor));
根据混合颜色的灰度,来减少或增加图像亮度,使图像更亮。
gl_FragColor = baseColor + 2 * blendColor - vec4(1.0);
如果混合色比50%灰度色亮,则将替换混合色暗的像素,而不改变混合色亮的像素;反之如果混合色比50%灰度色暗,则将替换混合色亮的像素,而不改变混合色暗的像素。
gl_FragColor = min(baseColor,2*blendColor - vec4(1.0));
上方图层的亮区将下方图层的颜色进行反相,暗区则将颜色正常显示出来,效果与原图像是完全相反的颜色。
gl_FragColor = vec4(abs(blendColor-baseColor).rgb,1.0);
创建一种与“差值”模式类似但对比度更低的效果。3lian.com,与白色混合将反转基色值,与黑色混合则不发生变化。
gl_FragColor =vec4((baseColor + blendColor).rgb - (2.0*baseColor*blendColor).rgb,1.0);
gl_FragColor = vec4(baseColor.rgb-blendColor.rgb,1.0);
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;yy++)
{
for(int x=0;xx++)
{
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。在实际使用的过程中,不一定严格按照公式来编写,只要效果看着正确就可以使用,有时候没准还会获得出乎意料的效果呢。