如何修改此WebGL片段着色器以增加高光的亮度以及减少亮度

时间:2014-10-22 15:19:50

标签: webgl shader fragment-shader

我目前在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. 当前过滤器的高光设置为1.00(基本上是源图像)
  2. enter image description here

    1. 当前过滤器的高光设置为0.00,因为您可以看到高光被展平/移除。
    2. enter image description here

      1. 最后,当我更改片段着色器中的clamp以允许值高于1.00并将高亮值设置为2.00
      2. 时,会发生以下情况

        enter image description here

        我只是希望能够提升亮点,使它们更明亮/更明确。即与将值设置为0.00

        相反

1 个答案:

答案 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函数(不确定)。

所以这是我未经优化的着色器版本,设置为shadowshighlights都在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的技巧。只是一个猜测。