Search code examples
three.jsglslwebglfragment-shader

GLSL - Blur only the red channel


So, I have these two functions in GLSL. One that splits a texture by its rgb channels and then displaces them individually. And another that just blurs a texture. I want to combine them. But I want to be able to only blur the channel im displacing. So, for instance I might want to blur the red channel in the rgbShift function.

Problem is that the red channel is a single float and the blur function expects a full sample2D image so it can apply UV and stuff. I guess I need a way to blur just a single float? Im not very experienced with GLSL and ive been trying to figure this out for a few days now. Ill be very thankfull for any pointers or suggestions at all.

The GLSL functions can be viewed below.

vec4 blur5(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {
  vec4 color = vec4(0.0);
  vec2 offset = (vec2(1.3333333333333333) * direction) / resolution;
  color += texture2D(image, uv) * 0.29411764705882354;
  color += texture2D(image, uv + offset) * 0.35294117647058826;
  color += texture2D(image, uv - offset) * 0.35294117647058826;
  return color;
}
vec3 rgbShift(sampler2D textureimage, vec2 uv, float offset) {
  float displace = sin(PI*vUv.y) * offset;
  float r = texture2D(textureimage, uv + displace).r;
  float g = texture2D(textureimage, uv).g;
  float b = texture2D(textureimage, uv + -displace).b;
  return vec3(r, g, b);
}

Heres me thinking out loud:

I guess I want to do something like this:

vec4 blurredTexture = blur5(textureImage);
float red = texture2D(blurredTexture, uv + displace).r;

Or this:

float redChannel = texture2D(blurredTexture, uv + displace).r; 
vec4 blurredRedChannel = blur5(redChannel );

But neither will work because I cant figure out how to convert the types. I either need to convert the blurred vec4 into a sample2D for the rgbShift function. Or the red channel float into a sample2D for the blur function. Is it even possible to convert a value into a sample2D one way or another?

Maybe I need some other solution where I dont need to convert sample2D at all.


Solution

  • Is it even possible to convert a value into a sample2D one way or another?

    Sort-of. You'll need to write that value to a temporary texture. Then you can bind that texture and run a 2nd pass that will sample from that texture. That's probably an overkill for the simple filtering you're trying to do.

    Maybe I need some other solution where I dont need to convert sample2D at all.

    A simpler solution is to combine those two functions into one:

    vec3 shiftAndBlur(sampler2D image, vec2 uv, float offset, vec2 resolution, vec2 direction) {
      vec2 offset = (vec2(1.3333333333333333) * direction) / resolution;
      float displace = sin(PI*vUv.y) * offset;
      float r = texture2D(image, uv + displace).r * 0.29411764705882354
          + texture2D(image, uv + displace + offset).r * 0.35294117647058826
          + texture2D(image, uv + displace - offset).r * 0.35294117647058826;
      float g = texture2D(image, uv).g;
      float b = texture2D(image, uv - displace).b;
      return vec3(r,g,b);
    }