Shader on the whole screen

Hello, hello,

I’ve asked about it a long time ago, but this is now bothering me, for some reason. I’m not the most familiar with shaders, and it’s late, and I can’t figure out what wrong with this simple post processing:

-- Screenbuffer (updated with Ignatz's suggestions)

-- Use this function to perform your initial setup
function setup()
    
    screen = image(WIDTH,HEIGHT)
    
    s = shader("Filters:Blur")
    mesh = mesh()
    rIdx = meshScreen:addRect(0,0,WIDTH,HEIGHT)
    meshScreen:setRect(rIdx,0,0,WIDTH,HEIGHT)

end

-- This function gets called once every frame
function draw()
    
    setContext(screen)
    
    background(40, 40, 50)

    strokeWidth(5)
    fill(178, 178, 178, 255)
    ellipse(WIDTH/2,HEIGHT/2,100)
    
    setContext()
    mesh.shader = s
    mesh.texture = screen
    meshScreen.shader.conPixel=vec2(1/WIDTH,1/HEIGHT)
    meshScreen.shader.conWeight=0.4/9

    mesh:draw()

end

Is their something I’m completely wrong with?

@Rodolphe - you haven’t defined texture coordinates for your mesh, and you haven’t set the two variables required by the shader.

The code below works. I have used setRect rather than triangulate, for my own convenience. To make triangulate work, you will separately need to define texture coordinates. If you’re not sure what that means, have a look at some of the documentation and tutorials on meshes via the wiki.

To see what variables the shader requires, get the shader selection dialog up and press Edit to see the shader code. Look at the Bindings tab to see what variables you need to set. Note that all of them except for texture, need to be assigned to the shader, not the mesh. Read carefully how I do that below, eg for conPixel.

-- Screenbuffer

-- Use this function to perform your initial setup
function setup()
    screen = image(WIDTH,HEIGHT)
    setContext(screen)
    background(40, 40, 50)
    strokeWidth(5)
    fill(178, 178, 178, 255)
    ellipse(WIDTH/2,HEIGHT/2,100)
    setContext()
    
    s = shader("Filters:Blur")
    mesh = mesh()
    mesh:addRect(0,0,WIDTH,HEIGHT)
    mesh.shader = s
    mesh.texture = screen
    mesh.shader.conPixel=vec2(1/WIDTH,1/HEIGHT)
    mesh.shader.conWeight=0.4/9
end

-- This function gets called once every frame
function draw()    
    background(0)
    translate(WIDTH/2,HEIGHT/2)
    mesh:draw()
end

Oh thank you @Ignatz, it works now!

I ported this to the game I’m working on, Churning Seas, with the blur shader from the example files, and I’m kind of sadden (but not very surprised) the fps drops dramatically, from 60 fps to 20 on my ipad retina.

Before I go any further (and try lighter shaders), is there any tricks to know to post-process the whole display in the most efficient way possible?

Cheers!

@Rodolphe - it depends what you are doing. In your original draw function code, you were drawing to an image in memory every time, which is extremely expensive.

You are also blurring the whole screen. If you can find a way to only blur the part you want, or find a simpler visual effect way, it will run faster.

But it’s hard to say without knowing exactly what you are doing.

The FPS drop is partly due to setContext() being optimised for 3d drawing so being slower-even with 2d drawing

Yes, I set setContext(screen) at the very beginning of draw(), then setContext() at the very end, put the “screen” image as a texture to the mesh that is the size of the ipad retina screen, and draw the mesh.

I thought this was the most efficient way to do this, is it not?

As far as expensive shaders go, yes, all I really want to do is desaturate the colours, for now, so that should be less expensive (is it?)…

Oh… thanks @Coder. Is there a better way to do this in 2D then?

I think there will be a setContext2d and 3d sometime in the future

@Rodolphe - what exactly are you drawing on the screen? Why do you need to draw the entire screen in memory all the time? What is changing?

If you are just desaturating the colors, then you could either desaturate the source images, or if you are spriting stuff, do the stuff as a mesh in the first place and desature shader each mesh. Or do I not understand?

I would try creating a translucent blur overlay image, that you can simply sprite on top of everything else

@Ignatz, I’m drawing layers of overlaying images with sprite(), tons of meshes (polygons), lines, circles, etc. (all of this, actually : https://www.youtube.com/watch?v=PW9uI9WoyG4)

So everything the game is about changes 60 times a second, and I need to put everything in memory to perform a true post processing effect. As far as I understand it, there is no way around it, right? Using semi-transparent overlays don’t really cut it for the effect I’m looking for, unfortunately, @KakAttak:frowning:

But, really, I haven’t got the chance to try a desaturating shader yet. I’m still hopping this would be faster than my blur trial… :slight_smile: