Welcome, Guest. Please login or register. Did you miss your activation email?

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - SteelGiant

Pages: [1]
1
Graphics / Blur shader confusion (Update: full source provided)
« on: March 09, 2018, 01:57:29 am »
I'm trying to repeatedly blur an image to get it to dissolve. I'm doing this by drawing into one sf::RenderTexture and then drawing from that into another sf::RenderTexture with a blur fragment shader, then drawing that image back to the first RenderTexture (with no shader) ready to draw again.


//drawRenderTexture starts off clear at the start of the program

drawRenderTexture.draw(drawVertices, nVertices, sf::PrimitiveType::Points);
drawRenderTexture.display();

blurRenderTexture.clear(sf::Color::Transparent);//Don't need to clear, as when using sf::BlendNone the original is entirely overdrawn
blurRenderTexture.draw(drawSprite, sf::RenderStates(sf::BlendNone, sf::Transform(), NULL, &SFMLBlur));
blurRenderTexture.display();

//Cycle texture back to image:
drawRenderTexture.clear(sf::Color::Transparent);//Don't need to clear, as when using sf::BlendNone the original is entirely overdrawn
drawRenderTexture.draw(blurSprite, sf::RenderStates(sf::BlendNone));
//TODO: Why doesn't it dissipate? Seems to get to a certain distance and minimal density, then neither get more spread out, nor get less dense...??

//Rendering:
window.clear();

window.draw(blurSprite);

window.display();

 

The blur fragment shader here is the one from the SFML shader examples https://github.com/SFML/SFML/blob/master/examples/shader/resources/blur.frag

I have also tried this with a shader I wrote myself, which also behaves the same way.

What I had expected would be that if I drew a white square and then repeatedly applied a blur shader every frame, then the square would spread out and become more transparent until it disappeared.

What I'm actually seeing is that the shape spreads out a bit and then stops spreading out, which really confuses me. Similarly if I draw something every frame moving around the screen, the trail the object leaves only spreads out a finite amount, then stops spreading. Even quite high alpha bits of the trail don't seem to be getting blurred.

This seems very strange, as I would either expect the blur to not work at all, and for no trail to be created, or for it to dissipate the image successfully. This strange inbetween where it manages to blur but only for a while seems insane behaviour.

If in the shader I deliberately set alpha values that are less than about 0.02 to zero then the trail disappears, although it doesn't look great as it doesn't fade out at the edges, but choosing a lower threshold doesn't seem to eliminate any pixels at all (if there was a threshold I would expect it to be at about 1.0/256.0 or something).

It feels like I have forgotten to clear some buffer somewhere, yet as far as I can see I am clearing them all, and if that was the case then chopping low alpha values in the shader would not eliminate things...

Attached png shows two successive screenshots several hundred frames apart. Note how the trail is somehow the same size and intact hundreds of frames later.

Anyone have any ideas?

2
The general idea is to achieve an effect by drawing to an image and then blurring it every frame.

At the moment I have the effect working, but I'm not getting the performance I had hoped for.

The way it works at the moment is to have a cycle of 5 objects that the image goes through:

        sf::Image drawImage;
        drawImage.create(window.getSize().x, window.getSize().y, sf::Color::Transparent);

        sf::Texture drawBufferTexture;
        drawBufferTexture.create(drawImage.getSize().x, drawImage.getSize().y);

        sf::Sprite drawBufferSprite;
        drawBufferSprite.setTexture(drawBufferTexture);

        sf::RenderTexture drawRenderTexture;
        drawRenderTexture.create(drawImage.getSize().x, drawImage.getSize().y);

        sf::Sprite drawSprite;
        drawSprite.setTexture(drawRenderTexture.getTexture());
 

The drawing is done into drawImage, and the image is then rendered to a buffered RenderTexture with a shader to do the blurring, and then the blurred image is fed back from the texture to the original image:

        drawBufferTexture.update(drawImage);

        drawRenderTexture.clear(sf::Color::Transparent);
        drawRenderTexture.draw(drawBufferSprite, &drawBlur);
        drawRenderTexture.display();

        //Cycle texture back to image:
        drawImage = drawRenderTexture.getTexture().copyToImage();
 

and finally the sprite that now contains the blurred image is rendered:

        window.draw(drawSprite);
 

The slow bit seems to be, as expected, the cycling from the RenderTexture back into the image. I need to cycle the blurred image back so that more can be drawn to it next frame, so this needs to be achieved somehow.

Is there something I'm missing here? Is there a much faster way to do this without the copyToImage() step? Is there some way to do this all within one RenderTexture using a shader?

Typically, I would only expect to be drawing into (significantly) less than 10 percent of the image each frame if that helps.

I'm currently managing to get about 70 fps on a 1080px x 1080px image out of this using a GTX 980, and I had hoped to be able to push it to higher resolutions at higher fps. Without the copyToImage step I can easily maintain 144 fps at 2160x2160.

I managed to do this at 800x800 resolution @60fps in flash on my laptop back in ~2012, so I know in principle this effect must be doable efficiently with full access to the GPU, I'm just not sure how to achieve it.

Pages: [1]