Problem making a horizontal gaussian blur

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Raxe88
Prole
Posts: 15
Joined: Mon Jul 29, 2013 11:14 pm

Problem making a horizontal gaussian blur

Post by Raxe88 » Sat Sep 02, 2017 3:18 pm

Hello! I've been messing with shaders these days and I wanted to make a blur, starting by a horizontal one. I understand the concept behind it and I've seen multiple people's code. I've made my own code and also tried someone else's but I get the same problem every time.
This is the image without altering:
Image

Here's using the code I ported from https://vvvv.org/documentation/tutorial ... ing-pixels:
Image

As you can see, it's not blurring. It looks like it's adding pixels all over the place. Both my shader using a kernel and the one I ported from the internet are doing these weird renders. Here's my code:

Code: Select all

function love.load()
  deus_ex = love.graphics.newImage("deus_ex.png")

  shaderBlur = love.graphics.newShader([[
    extern number texture_width;
    extern number texture_height;
    vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords ){
      vec4 pixel = Texel(texture, texture_coords );//This is the current pixel color
      vec4 sum;
      number pixel_size = 1.0 / (texture_width/texture_height);
      sum += Texel(texture, vec2(texture_coords.x + (pixel_size * (-3)), texture_coords.y)) *0.00598;
      sum += Texel(texture, vec2(texture_coords.x + (pixel_size * (-2)), texture_coords.y)) *0.060626;
      sum += Texel(texture, vec2(texture_coords.x + (pixel_size * (-1)), texture_coords.y)) *0.241843;
      sum += Texel(texture, vec2(texture_coords.x + (pixel_size * (0)), texture_coords.y))  *0.383103;
      sum += Texel(texture, vec2(texture_coords.x + (pixel_size * (+1)), texture_coords.y)) *0.241843;
      sum += Texel(texture, vec2(texture_coords.x + (pixel_size * (+2)), texture_coords.y)) *0.060626;
      sum += Texel(texture, vec2(texture_coords.x + (pixel_size * (+3)), texture_coords.y)) *0.00598;
      return sum;
      //return Texel(texture, texture_coords.xy);
    }
  ]])

  shaderBlur2 = love.graphics.newShader([[
    extern number texture_width;
    extern number texture_height;
    vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords ){
      vec4 sum = vec4 (0.0, 0.0, 0.0, 0.0);
      number weightSum = 0.0;
      int weights[15] = {1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1};
      number pixel_size = 1.0 / (texture_width/texture_height);
      for (int i = 0; i < 15; i++)
      {
        vec2 cord = vec2 (texture_coords.x + pixel_size.x * (i-7), texture_coords.y);
        sum += Texel(texture, cord) * weights[i];
        weightSum += weights[i];
      }
      sum /= weightSum;
      return vec4(sum.rgb, 1.0);
    }
  ]])

  shaderBlur2:send("texture_width", deus_ex:getWidth())
  shaderBlur2:send("texture_height", deus_ex:getHeight())
end
function love.draw()
  love.graphics.setShader(shaderBlur2)
  love.graphics.draw(deus_ex)
  love.graphics.setShader()
end
I've tried with LÖVE 0.9.2 and 0.10.2. Any help would be appreciated!
Attachments
problemShader.love
(30.67 KiB) Downloaded 33 times

User avatar
Luke100000
Party member
Posts: 231
Joined: Mon Jul 22, 2013 9:17 am
Location: Austria
Contact:

Re: Problem making a horizontal gaussian blur

Post by Luke100000 » Sat Sep 02, 2017 4:12 pm

shaderBlur2 crashed on my PC:
Error: Cannot compile pixel shader code:
Line 6: error: OpenGL does not allow C style initializers
Line 10: error: OpenGL does not allow swizzles on scalar expressions

Use the first shader (shaderBlur).

Code: Select all

number pixel_size = 1.0 / (texture_width/texture_height);
is the error, you divided 1.0 twice, just write:

Code: Select all

number pixel_size = 1.0 / texture_width;
Also, here is the shader I always use. It is similar to yours, but you can send the direction of blurring.

Code: Select all

extern vec2 size;
extern float hstep;
extern float vstep;

vec4 effect(vec4 color, Image texture, vec2 tc, vec2 sc) {
	vec4 sum = vec4(0.0);
	
	sum += Texel(texture, tc - vec2(4.0*hstep, 4.0*vstep) / size) * 0.0162162162;
	sum += Texel(texture, tc - vec2(3.0*hstep, 3.0*vstep) / size) * 0.0540540541;
	sum += Texel(texture, tc - vec2(2.0*hstep, 2.0*vstep) / size) * 0.1216216216;
	sum += Texel(texture, tc - vec2(1.0*hstep, 1.0*vstep) / size) * 0.1945945946;
	
	sum += Texel(texture, tc) * 0.2270270270;
	
	sum += Texel(texture, tc + vec2(1.0*hstep, tc.y + 1.0*vstep) / size) * 0.1945945946;
	sum += Texel(texture, tc + vec2(2.0*hstep, tc.y + 2.0*vstep) / size) * 0.1216216216;
	sum += Texel(texture, tc + vec2(3.0*hstep, tc.y + 3.0*vstep) / size) * 0.0540540541;
	sum += Texel(texture, tc + vec2(4.0*hstep, tc.y + 4.0*vstep) / size) * 0.0162162162;
	
	return sum;
}

Raxe88
Prole
Posts: 15
Joined: Mon Jul 29, 2013 11:14 pm

Re: Problem making a horizontal gaussian blur

Post by Raxe88 » Sun Sep 03, 2017 1:51 pm

First of all, thanks for answering! You helped a lot already :D. In regards of the crashes I am not too sure why they happen, I can run the code without problems. Maybe different versions do different things?

What is the logic behind dividing 1.0/width instead of 1.0/(witdh/height)? From what I'm gathering looking at your code, I should divide by width when doing a horizontal blur and divide by height when doing a vertical blur. Changing this I correctly get a nice blur using shaderBlur2, but with shaderBlur I have the same problem as before:

shadeBlur2
Image
shaderBlur
Image

I don't really understand why it keeps happening since my own code (shaderBlur) is basically the same as yours. I tested your code and it works fine too.

Edit: Got some new problems. When trying to blur something I've filtered (brightness is what I'm looking after) it keeps repeating the process of blurring so I end up with something really weird. It's got to have a really easy solution I am not seeing. Here's the code:

Code: Select all

function love.load()
  deus_ex = love.graphics.newImage("deus_ex.png")

  canvas = love.graphics.newCanvas()

  shaderBrightness = love.graphics.newShader([[
    vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords ){
      vec4 pixel = Texel(texture, texture_coords );//This is the current pixel color
      float brightness = (pixel.r + pixel.g + pixel.b)/3.0;
      if(brightness > 0.7){
        return pixel;
      }
    }
  ]])

  shaderBlur = love.graphics.newShader([[
    extern number texture_width;
    //extern number texture_height;
    vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords ){
      vec4 pixel = Texel(texture, texture_coords );//This is the current pixel color
      vec4 sum;
      number pixel_size = 1.0 / (texture_width);
      sum += Texel(texture, vec2(texture_coords.x + (pixel_size * (-3)), texture_coords.y)) *0.00598;
      sum += Texel(texture, vec2(texture_coords.x + (pixel_size * (-2)), texture_coords.y)) *0.060626;
      sum += Texel(texture, vec2(texture_coords.x + (pixel_size * (-1)), texture_coords.y)) *0.241843;
      sum += Texel(texture, vec2(texture_coords.x + (pixel_size * (0)), texture_coords.y))  *0.383103;
      sum += Texel(texture, vec2(texture_coords.x + (pixel_size * (+1)), texture_coords.y)) *0.241843;
      sum += Texel(texture, vec2(texture_coords.x + (pixel_size * (+2)), texture_coords.y)) *0.060626;
      sum += Texel(texture, vec2(texture_coords.x + (pixel_size * (+3)), texture_coords.y)) *0.00598;
      return sum;
      //return Texel(texture, texture_coords.xy);
    }
  ]])

  shaderBlur2 = love.graphics.newShader([[
    extern number texture_width;
    //extern number texture_height;
    vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords ){
      vec4 sum = vec4 (0.0, 0.0, 0.0, 0.0);
      number weightSum = 0.0;
      int weights[15] = {1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1};
      number pixel_size = 1.0 / (texture_width);
      for (int i = 0; i < 15; i++)
      {
        vec2 cord = vec2 (texture_coords.x + pixel_size.x * (i-7), texture_coords.y);
        sum += Texel(texture, cord) * weights[i];
        weightSum += weights[i];
      }
      sum /= weightSum;
      return vec4(sum.rgb, 1.0);
    }
  ]])

  shaderBlur2:send("texture_width", deus_ex:getWidth())
end
function love.draw()
  love.graphics.setCanvas(canvas)
  love.graphics.setShader(shaderBrightness)
  love.graphics.draw(deus_ex)
  love.graphics.setShader(shaderBlur2)
  love.graphics.draw(canvas)
  love.graphics.setShader()
  love.graphics.setCanvas()
  love.graphics.draw(canvas)
  love.graphics.setShader()
end
What it ends up looking like:
Image

User avatar
Nuthen224
Citizen
Posts: 50
Joined: Sun Jul 28, 2013 9:40 pm

Re: Problem making a horizontal gaussian blur

Post by Nuthen224 » Mon Sep 04, 2017 12:33 am

It appears that you're drawing a canvas to itself. No bueno. I suggest adding another canvas.

User avatar
Luke100000
Party member
Posts: 231
Joined: Mon Jul 22, 2013 9:17 am
Location: Austria
Contact:

Re: Problem making a horizontal gaussian blur

Post by Luke100000 » Mon Sep 04, 2017 8:47 am

Ok, let's start with shaderBlur2: I do not know why the first error happens but after changing the weights array to this:

Code: Select all

int weights[15] = int[15](1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1);
it works fine. The second error is because you want to get x of a number value. This only works on some systems. Changing number pixel_size to a vector OR removing .x at vec2 cord= will fix it.
Maybe different versions do different things?
Yes, sadly :(
What is the logic behind dividing 1.0/width instead of 1.0/(witdh/height)?
The texture coordinates reach from 0 to 1. "i" is a int. If you want one real pixel you have to divide the int by the textures dimensions. 1.0/(width/height) makes no sense, you blur the X axis and then the y-axis, not both at once.

The code crashes, as Nuthen224 said, because you try to draw a canvas to itself which is impossible. You need two canvases, or in our example, just render the canvas using the blur shader directly to the screen. If you need to blur (or use any other shader multiply times) you need two canvases of the same size and switch them every time.

Code: Select all

ove.graphics.setCanvas(canvas)
  love.graphics.setShader(shaderBrightness)
  love.graphics.draw(deus_ex)
  love.graphics.setCanvas()
  love.graphics.setShader(shaderBlur2)
  love.graphics.draw(canvas)
  love.graphics.setShader()
Now, shaderBlur2: Are you sure you included it into the file you gave me? It's working fine!

I hope my explanations are correct, I'm not a shader expert either :) But as long as it works it should be good.

Post Reply

Who is online

Users browsing this forum: No registered users and 5 guests