Need help to implement box blur.

NeoDNeoD Posts: 202Member

I want to blur a 2D line so I'm trying to translate the algorythm found on Wikipedia.

This totally naive translation doesn't work, the 2DNode is just colored in full white.

shader_type canvas_item;

void fragment() {
    float kernel_size = 3.0;

    vec4 upperRow = texture(TEXTURE, UV + vec2(- kernel_size, kernel_size)) +
                    texture(TEXTURE, UV + vec2(0, kernel_size)) + 
                    texture(TEXTURE, UV + vec2(kernel_size, kernel_size));

    vec4 centerRow = texture(TEXTURE, UV + vec2(- kernel_size, 0)) +
                     texture(TEXTURE, UV ) + 
                     texture(TEXTURE, UV + vec2(kernel_size, 0));

    vec4 bottomRow = texture(TEXTURE, UV + vec2(- kernel_size, - kernel_size)) +
                     texture(TEXTURE, UV + vec2(0, - kernel_size)) + 
                     texture(TEXTURE, UV + vec2(kernel_size, - kernel_size));

    COLOR = (upperRow + centerRow + bottomRow) / 9.0;
}

Here's the 2D node script who draw the lines.

tool
extends Node2D

export (Color) var linecenter
export (Color) var backline
#
func _draw():
    draw_line(position, Vector2(get_viewport_rect().size.x/2, get_viewport_rect().size.y/2),
                                backline, 10)
    draw_line(position, Vector2(get_viewport_rect().size.x/2, get_viewport_rect().size.y/2), 
                               linecenter, 2)

func _ready():
    pass

Sorry if my misunderstanding is stupid, I'm new on shaders.

Comments

  • TwistedTwiglegTwistedTwigleg Posts: 4,277Admin

    I do not know for sure, but the reason it might not be working is could be because the draw_line function does not supply a texture, so the shader does not have a texture to blur. As a test, I would try the shader on a Sprite with a simple texture, like the Godot logo, and see if the shader works there.

  • MegalomaniakMegalomaniak Posts: 3,549Admin

    You would need a viewport you render the line into then operate on that viewport texture to achieve the blurring, more than likely.

  • NeoDNeoD Posts: 202Member

    When I apply this shader to a Sprite the result is like this.

    Maybe "TEXTURE" variable is always white ?
    How to get the current pixel color ?

  • TwistedTwiglegTwistedTwigleg Posts: 4,277Admin
    edited September 2019

    You can get the current pixel color with the COLOR shader variable, though I don't remember if it has the texture already applied or not.

    Looking at the shader again, I wonder if the issue is the UV coordinates. If I recall correctly, UV coordinates need to be in the 0 to 1 range as that is what OpenGL uses. The range might be -1 to 1, but I think that is for DirectX. I'm wondering if the reason the sprite is so white is because when the UV position goes outside of the range it samples the edges of the texture, hence the white color.

    I'll pull the shader into a test project and see if I can figure out what is going on. I don't know a whole lot about shaders, but maybe I'll stumble across a solution or something.


    Edit: I played around with it a bit and changed the kernel_size so it uses the texture size. Now for sprites it works, though not for the Node2D with the lines. Here is the shader:

    shader_type canvas_item;
    
    uniform float kernel_size = 1.0;
    
    void fragment() {
        float kernel_size_x = kernel_size * TEXTURE_PIXEL_SIZE.x;
        float kernel_size_y = kernel_size * TEXTURE_PIXEL_SIZE.y;
    
    
        vec4 upperRow = texture(TEXTURE, UV + vec2(- kernel_size_x, kernel_size_y)) +
                        texture(TEXTURE, UV + vec2(0, kernel_size_y)) + 
                        texture(TEXTURE, UV + vec2(kernel_size_x, kernel_size_y));
        vec4 centerRow = texture(TEXTURE, UV + vec2(- kernel_size_x, 0)) +
                        texture(TEXTURE, UV ) + 
                        texture(TEXTURE, UV + vec2(kernel_size_x, 0));
        vec4 bottomRow = texture(TEXTURE, UV + vec2(- kernel_size_x, - kernel_size_y)) +
                        texture(TEXTURE, UV + vec2(0, - kernel_size_y)) + 
                        texture(TEXTURE, UV + vec2(kernel_size_x, - kernel_size_y));
    
        COLOR = (upperRow + centerRow + bottomRow) / 9.0;
    
    }
    
  • NeoDNeoD Posts: 202Member
    edited September 2019

    Thank you even if that don't work for drawings.

    @Megalomaniak said:
    You would need a viewport you render the line into then operate on that viewport texture to achieve the blurring, more than likely.

    The lines can be in any position and points in any directions, only the line should glows and not the background. Is it still possible ?

  • MegalomaniakMegalomaniak Posts: 3,549Admin

    depends how you are going about it, if it is 2d could probably render the 2d lines to a canvas layer and separate it that way, if 3d could try to render a mask for them to separate them that way for blurring, or render them in a separate scene where it gets it's own viewport and then overlay the blurred result over your other 3d scene.

    The good thing about viewports is that they have mipmaps so you can just use a lower mip as a blurred result. If the quality of the mip works for you then that is probably the easiest solution.

  • NeoDNeoD Posts: 202Member
    edited September 2019

    I'ts a 2D game with the GLES 2 mode (so there is no glow property).

    I'm trying to achieve the Megalomaniak solution. The example line is displayed in a viewport now but I have hard time to make working all this machinery.

  • MegalomaniakMegalomaniak Posts: 3,549Admin
    edited September 2019

    Right, tested, and seems that textureLOD/mips aren't available on GLES2. I wasn't aware of that, bummer. :(

    The screen-space shaders demo project has the blur working, but only with GLES3 renderer.

  • NeoDNeoD Posts: 202Member

    Hello, I find the beginning of a solution here.
    There is everything, Viewports and also shaders !

    https://docs.godotengine.org/en/3.1/tutorials/viewports/custom_postprocessing.html

    But it's not over, for some reason my viewport has a black background instead of transparent.

  • MegalomaniakMegalomaniak Posts: 3,549Admin
    edited September 2019

    For starters, you have two viewports in there, might it be that one of them still has the transparent bg disabled?

    Also, might be worth experimenting with giving one or both their own worlds and making sure that the world is rendering it's background as transparent.

  • NeoDNeoD Posts: 202Member
    edited September 2019

    Do you think the problem is that these shaders turn any transparent fragment to 0.0 ?

  • TwistedTwiglegTwistedTwigleg Posts: 4,277Admin

    Looking at the shader code, you probably need to add something like this to the shaders:

    COLOR.a = texture(TEXTURE, SCREEN_UV).a;

    Then, hopefully, transparency will be applied. I’m not sure if you will need to account for transparency in all of the samples or not. If the code above does not work, I’ll see if I can get transparency working in a prototype project.

  • NeoDNeoD Posts: 202Member

    Ok, I tried a condition at the begining to save calculations in that full screen texture .
    if (COLOR.a != 0.0)

    But that failed miserably. TwistedTwigleg solution works.

  • NeoDNeoD Posts: 202Member
    edited October 2019

    According to the PR below, GLES2 World Environement may gain the glow property in Godot 3.2 : o

    https://github.com/godotengine/godot/pull/31845

    I hope a better result for my lines !

Leave a Comment

BoldItalicStrikethroughOrdered listUnordered list
Emoji
Image
Align leftAlign centerAlign rightToggle HTML viewToggle full pageToggle lights
Drop image/file