GLSL - 用于图像处理/混合的片段着色器

时间:2016-06-22 00:22:28

标签: android ios opengl-es webgl

我正在尝试构建一个着色器,它允许您通过将渐变不透明蒙版应用于顶部的一个来组合两个图像,就像在photoshop中一样。我已经达到了可以将蒙面图像覆盖在另一个上面的程度,但是作为一个新手我对一些事情感到困惑。

似乎着色器内部的图像有时会倾斜以适合画布大小,并且它们始终从位置0,0开始。我已经找到了一些我发现尝试扩展纹理的片段,但总是得不到令人满意的结果。

我很好奇是否在视图中有大小,倾斜和翻译纹理的标准方法,或者GLSL中的图像是否必然以某种方式限制,这将阻止我完成目标

我也不确定我是如何应用渐变/蒙版的,如果这是正确的方法,因为我目前对渐变的形状没有很多控制。 / p>

这是我到目前为止所拥有的:

  precision highp float;
  varying vec2 uv;
  uniform sampler2D originalImage;
  uniform sampler2D image;
  uniform vec2 resolution;

  void main(){

    float mask;
    vec4 result;

    vec2 position = gl_FragCoord.xy / ((resolution.x + resolution.y) * 2.0 );

    mask = vec4(1.0,1.0,1.0,1.0 - position.x).a;

    vec4 B = texture2D(image,uv);
    vec4 A = texture2D(originalImage,uv) * (mask);

    result = mix(B, A, A.a);

    gl_FragColor = result;
  }

产生如下图像:

我希望能够独立改变图像的位置,并确保它们符合适当的尺寸。

我试过天真地改变这样的立场:

vec2 pos = uv;
pos.y = pos.y + 0.25;
texture2D(image, pos)

哪个会移动纹理,但会导致一堆奇怪的线条拖动:

我试图像这样摆脱它们:

gl_FragColor = uv.y < 0.25 ? vec4(0.0,0.0,0.0,0.0) : result;

但它什么都不做

1 个答案:

答案 0 :(得分:2)

当图像尺寸不同时,你真的需要决定你想要发生什么。您可能想要的是它出现没有图像所以检查您的UV坐标并在图像外使用0,0,0,0

//vec4 B = texture2D(image,uv);

vec4 getImage(sampler2D img, vec2 uv) {
  if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
    return vec4(0);
  }
  return texture2D(img, uv);
}

vec4 B = getImage(image, uv);

对于尺寸/倾斜/平移图像的标准方法,请使用矩阵

uniform mat4 u_imageMatrix;

...

vec2 newUv = u_imageMatrix * vec4(uv, 0, 1).xy;

An example of implementing canvas 2d's drawImage using a texture matrix

总的来说,虽然我不认为大多数图像处理程序/库会尝试在着色器中执行所有操作。相反,他们用非常简单的原语构建图像。我最好的猜测是他们使用仅A * MASK的着色器然后绘制B,然后在A * MASK上进行混合。

换句话说,如果你在Photoshop中有30层,他们就不会生成一个着色器,它可以在一个巨型着色器中同时计算所有30个层中的最终图像。相反,每个图层都将使用更简单的着色器自行应用。

我也希望他们为蒙版创建一个纹理,而不是在着色器中使用数学。这样,掩模可以是任意复杂的,而不仅仅是2级斜坡。

注意我说你做错了。你可以自由地做任何你想做的事。我只是说我怀疑,如果你想构建一个通用的图像处理库,你可以用更小的构建块获得更多的成功,而不是试图在着色器中做更复杂的事情。

ps:我认为getImage可以简化为

vec4 getImage(sampler2D img, vec2 uv) {
  return texture2D(img, uv) * step(0.0, uv) * step(-1.0, -uv);
}