我目前在WebGL中使用此片段着色器将高光/阴影调整应用于照片纹理。
着色器本身是直接从适用于iOS的优秀GPUImage库中提取的。
uniform sampler2D inputImageTexture;
varying highp vec2 textureCoordinate;
uniform lowp float shadows;
uniform lowp float highlights;
const mediump vec3 luminanceWeighting = vec3(0.3, 0.3, 0.3);
void main()
{
lowp vec4 source = texture2D(inputImageTexture, textureCoordinate);
mediump float luminance = dot(source.rgb, luminanceWeighting);
mediump float shadow = clamp((pow(luminance, 1.0/(shadows+1.0)) + (-0.76)*pow(luminance, 2.0/(shadows+1.0))) - luminance, 0.0, 1.0);
mediump float highlight = clamp((1.0 - (pow(1.0-luminance, 1.0/(2.0-highlights)) + (-0.8)*pow(1.0-luminance, 2.0/(2.0-highlights)))) - luminance, -1.0, 0.0);
lowp vec3 result = vec3(0.0, 0.0, 0.0) + ((luminance + shadow + highlight) - 0.0) * ((source.rgb - vec3(0.0, 0.0, 0.0))/(luminance - 0.0));
gl_FragColor = vec4(result.rgb, source.a);
}
此着色器只会缩小0.0 - 1.0
等级的高光。不过,我希望它能够在1.0-2.0
的范围内提亮亮点。
目的是设置一个完整的滤镜,当高光均匀度小于1.0
时减少图像高光,并在高于1.0
时增加高光的强度。黑暗阴影均匀也是如此
亮点:
0.0(duller) ---- 1.0 (default - original pixel values) ----- 2.0 (brighter)
我试过简单地将高亮变量上的夹子更改为0.0,2.0
,虽然当制服高于1.0
时确实会增加高光的亮度,但它也会严重影响颜色。
我对图像处理和构建片段着色器的理解充其量是非常弱的,因为我能说出来。
我只是希望有人能指出我正确的方向。
编辑:
以下是一些示例屏幕截图: -
1.00
(基本上是源图像)
0.00
,因为您可以看到高光被展平/移除。
clamp
以允许值高于1.00
并将高亮值设置为2.00
我只是希望能够提升亮点,使它们更明亮/更明确。即与将值设置为0.00
答案 0 :(得分:4)
我不太了解阴影和高光方程,但我可以看到它们被设置为永远不会增强阴影和高光,而是将它们清除掉。因此,我们需要一个辅助步骤来进行增强。
对于亮点,我认为要处理更亮的颜色,你需要混合白色而不是添加一些东西,所以你不会得到色调变化。我使用一个基本的对比度方程来挑选高光,然后将其立方体来剪掉中间调和阴影。 whiteTarget
只是拉出0.0-2.0范围的上半部分,用作乘数来确定增亮效果的强度。
对于阴影,我们将范围从0.0-1.0(其中0未更改,1被淘汰)更改为0.0-2.0(其中1未更改,2则被清除)。因此,应删除shadow
等式中的+ 1.0&s。然后对于0.0-1.0范围,我只是复制了我为高光所做的事情,除了向黑色混合。也许可以优化以避免mix
函数(不确定)。
所以这是我未经优化的着色器版本,设置为shadows
和highlights
都在0.0-2.0等级,1.0是标称值。您可能想要使用那些我将亮度立方体的线条,以及我用于对比度的值(目前为1.5),但对我来说它现在的方式似乎很好 - 我调整它以试图避免当输入参数处于两个极端时,阴影和高光范围之间的任何丑陋重叠。
uniform sampler2D inputImageTexture;
varying highp vec2 textureCoordinate;
uniform lowp float shadows;
uniform lowp float highlights;
const mediump vec3 luminanceWeighting = vec3(0.3, 0.3, 0.3);
void main()
{
lowp vec4 source = texture2D(inputImageTexture, textureCoordinate);
mediump float luminance = dot(source.rgb, luminanceWeighting);
//(shadows+1.0) changed to just shadows:
mediump float shadow = clamp((pow(luminance, 1.0/shadows) + (-0.76)*pow(luminance, 2.0/shadows)) - luminance, 0.0, 1.0);
mediump float highlight = clamp((1.0 - (pow(1.0-luminance, 1.0/(2.0-highlights)) + (-0.8)*pow(1.0-luminance, 2.0/(2.0-highlights)))) - luminance, -1.0, 0.0);
lowp vec3 result = vec3(0.0, 0.0, 0.0) + ((luminance + shadow + highlight) - 0.0) * ((source.rgb - vec3(0.0, 0.0, 0.0))/(luminance - 0.0));
// blend toward white if highlights is more than 1
mediump float contrastedLuminance = ((luminance - 0.5) * 1.5) + 0.5;
mediump float whiteInterp = contrastedLuminance*contrastedLuminance*contrastedLuminance;
mediump float whiteTarget = clamp(highlights, 1.0, 2.0) - 1.0;
result = mix(result, vec3(1.0), whiteInterp*whiteTarget);
// blend toward black if shadows is less than 1
mediump float invContrastedLuminance = 1.0 - contrastedLuminance;
mediump float blackInterp = invContrastedLuminance*invContrastedLuminance*invContrastedLuminance;
mediump float blackTarget = 1.0 - clamp(shadows, 0.0, 1.0);
result = mix(result, vec3(0.0), blackInterp*blackTarget);
gl_FragColor = vec4(result, source.a);
}
顺便说一句,任何想法为什么原始result
行不断向所有内容添加0?好像它可以简化为
vec3 result = (luminance + shadow + highlight) * source.rgb / luminance;
但也许这是在计算中而不是在计算之后转换为lowp
的技巧。只是一个猜测。