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

Author Topic: Sprite Masking in SFML2  (Read 33132 times)

0 Members and 3 Guests are viewing this topic.

ChonDee

  • Jr. Member
  • **
  • Posts: 62
    • View Profile
Sprite Masking in SFML2
« on: March 30, 2012, 06:00:02 am »
Hi,

I wanted to be able mask sprites such as having a base sprite and a masking sprite. The sprite used for masking is not drawn at all, only the alpha value is used such that the overlapping areas of the base sprite and the masking sprite is not drawn (or rather the masking sprite's alpha value is subtracted from the base sprite's alpha on the overlapping pixels).

I have made a sample demonstrating of what I would like to achieve:


I noticed that there is an entry on SFML Wiki that would allow exactly just that:
http://www.sfml-dev.org/wiki/en/sources/masking_using_alpha_and_blending

Unfortunately it looks like this would only work with SFML1.6 and has been abandoned.

Could someone help me if this could be modified so that it would work with SFML2 textures or rendertargets?
If that is not possible, is this something that could be done with glsl fragment shaders?

I would really appreciate any assistance on how I could achieve masking sprites in SFML2.

Thanks in advance!

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Sprite Masking in SFML2
« Reply #1 on: March 30, 2012, 08:00:14 am »
I don't know if you can easily do something with SFML 2.0. I guess you'll have to wait until render masks are officially implemented.
Laurent Gomila - SFML developer

ChonDee

  • Jr. Member
  • **
  • Posts: 62
    • View Profile
Re: Sprite Masking in SFML2
« Reply #2 on: March 30, 2012, 08:12:43 am »
I don't know if you can easily do something with SFML 2.0. I guess you'll have to wait until render masks are officially implemented.
Thanks for the answer.
I know its hard to know it in advance, but would you have a rough estimate on when might that be implemented, as of possibly in 1-3months, or more likely 6+ or something?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Sprite Masking in SFML2
« Reply #3 on: March 30, 2012, 08:36:04 am »
I have no idea, sorry.
Laurent Gomila - SFML developer

bobingabout

  • Newbie
  • *
  • Posts: 47
    • View Profile
Re: Sprite Masking in SFML2
« Reply #4 on: March 30, 2012, 07:48:41 pm »
I actually have a similar dilemma trying to write a space invaders type game. Bombs cause an explsion, and this explosion mark needs to be removed from the defence bunker sprite.
It is possible to write your own function, that iterates through the pixels, and where they line up, set the new pixel with an colour of alpha 0.

I'm not going to write a sample because:
A. I'm using 1.6, not 2.0, so things might have changed
B. I'm not that good at it anyway.

ChonDee

  • Jr. Member
  • **
  • Posts: 62
    • View Profile
Re: Sprite Masking in SFML2
« Reply #5 on: March 31, 2012, 01:42:06 am »
Well yes, that would work, but if that is dealing with the actual bitmap/image with CPU operations I would assume it would be quite expensive.
If what you said would be possible with a glsl fragment shader I guess it would be faster, but I am just starting to learn GLSL.

In your case however, as you are using SFML1.6, all this is implemented in an SFML wiki entry, that I have linked in the first post, check that out:
http://www.sfml-dev.org/wiki/en/sources/masking_using_alpha_and_blending
I just wanted to get this functionality in 2.0's rendertextures, and received the answer that this is still in development.

ChonDee

  • Jr. Member
  • **
  • Posts: 62
    • View Profile
Re: Sprite Masking in SFML2
« Reply #6 on: March 31, 2012, 04:08:32 am »
Laurent, (or anyone who could help :) )

Would that be possible for achieving something like this, that I draw the base sprite and the masking sprite of a specific color (magenta lets say), then in some way tell the rendertarget (or SFML globally) that magenta = full transparent?


Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Sprite Masking in SFML2
« Reply #7 on: March 31, 2012, 10:16:31 am »
Quote
Would that be possible for achieving something like this, that I draw the base sprite and the masking sprite of a specific color (magenta lets say), then in some way tell the rendertarget (or SFML globally) that magenta = full transparent?
I don't think so.
Laurent Gomila - SFML developer

Dienes

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: Sprite Masking in SFML2
« Reply #8 on: April 11, 2012, 02:54:06 pm »
It is actually possible. I made a small test demonstrating it:



And it works exactly like ChonDee's idea. The trick is to use a RenderTexture, draw the part you want to cut out with a specific color (in my test I draw a CircleShape in Color::Magenta), extract the underlying Texture to a Image, apply a mask and use it for a Sprite (instead of using the RenderTexture's Texture):

Code: [Select]
// renderTex is the sf::RenderTexture
// img is a sf::Image
// tex is a sf::Texture
// spr is a sf::Sprite

// Update RenderTexture
renderTex.display();

// Turn the contents with your magenta shape into an Image and apply mask
img = renderTex.getTexture().copyToImage();
img.createMaskFromColor(sf::Color::Magenta);

// Update Texture from Image
tex.loadFromImage(img);

// Update Sprite from Texture
spr.setTexture(tex);

When drawing, just draw the Sprite.
I wrapped this in a class for easy and automated usage.

It might not be very fast, so just do it when really necessary (i.e. when you updated the content).

ChonDee

  • Jr. Member
  • **
  • Posts: 62
    • View Profile
Re: Sprite Masking in SFML2
« Reply #9 on: April 12, 2012, 08:07:35 am »
Thanks a lot for your reply and code segment, it is very helpful.

I imagine (as you have mentioned too) that dealing with images instead of textures will probably have a noticeable performance impact.

I was actually thinking about replacing what img.createMaskFromColor(sf::Color::Magenta); does with a fragment shader, such that every magenta pixel will be changed to 0.f alpha, that way the image->texture conversion would not be necessary.

I am not sure if this is possible like that though.

I quess it would depend on whether the shader is applied AFTER the image without shader is displayed or BEFORE. If it is after, then even though the magenta will be changed to transparent, whatever used to be in the background is already overwritten. Common sense would tell me that it is applied before, but I don't have experience about it. Could someone perhaps tell me how it works?


Another thing to Dienes:
Did you write your own particle system? Looks like they are checked for collision even between each other, are you doing some tricky optimization for that? Are you using some wider scope physics engine, or just some minimal footprint one for the particles?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Sprite Masking in SFML2
« Reply #10 on: April 12, 2012, 08:48:12 am »
Quote
I am not sure if this is possible like that though.
It is possible, yes. And very easy to implement.

Quote
I quess it would depend on whether the shader is applied AFTER the image without shader is displayed or BEFORE. If it is after, then even though the magenta will be changed to transparent, whatever used to be in the background is already overwritten. Common sense would tell me that it is applied before, but I don't have experience about it. Could someone perhaps tell me how it works?
The pixel shader is not applied before nor after, it is used during the rendering of the sprite/texture. It replaces the pixel operations that the graphics card usually performs when there's no active pixel shader.
Laurent Gomila - SFML developer

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Sprite Masking in SFML2
« Reply #11 on: April 12, 2012, 09:02:35 am »
There's a simpler and more efficient solution to this problem. You can create holes in the render-texture by rendering stuff with alpha = 0 and blend mode set to BlendNone. This way there's no need for a custom pixel shader, transparency is directly and correctly written to the target.

#include <SFML/Graphics.hpp>

int main()
{
    sf::RenderWindow window(sf::VideoMode(800, 600), "SFML holes");
    window.setVerticalSyncEnabled(true);

    sf::RenderTexture target;
    if (!target.create(window.getSize().x, window.getSize().y))
        return -1;

    target.clear(sf::Color::White);
    target.display();

    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
        {
            sf::Vertex point(sf::Vector2f(sf::Mouse::getPosition(window)), sf::Color::Transparent);
            target.draw(&point, 1, sf::Points, sf::BlendNone);
            target.display();
        }

        window.clear();
        window.draw(sf::Sprite(target.getTexture()));
        window.display();
    }

    return 0;
}
Laurent Gomila - SFML developer

Dienes

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: Sprite Masking in SFML2
« Reply #12 on: April 12, 2012, 11:32:59 am »
To Laurent:
This looks interesting. I currently cannot test it, but would this approach allow for alphas between 0 and 255 to correctly make the RenderTexture's content half transparent?

To ChonDee:
They do not collide with each other. Once a particle comes to rest, I draw it onto the RenderTexture and remove it. Live particles do only collide with what's on the RenderTexture (I maintain a separate Bitfield for that). Physics themselves are just a gravity vector and a force I apply when spawning a particle. No physics engine/library behind it.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Sprite Masking in SFML2
« Reply #13 on: April 12, 2012, 11:44:29 am »
Quote
This looks interesting. I currently cannot test it, but would this approach allow for alphas between 0 and 255 to correctly make the RenderTexture's content half transparent?
Yes. But keep this in mind: what you would see semi-transparently from the render-texture is what you draw to create the "hole", not what was originally in the render-texture.
In other words, you can't change only the alpha component of pixels with this technique, you must completely overwrite pixels. That could be done quite easily with OpenGL (either using glBlendFuncSeparate or glColorMask), but SFML doesn't provide this option.
Well, of course you can still do it with a pixel shader.
« Last Edit: April 12, 2012, 11:46:21 am by Laurent »
Laurent Gomila - SFML developer

Dienes

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: Sprite Masking in SFML2
« Reply #14 on: April 12, 2012, 02:45:14 pm »
Okay, this version prevents you from using a texture to cut out areas. It will remove the complete bounding box of the sprite, no matter what the texture contains (I guess due to the BlendNone thing).

I will stick to my version for now, as it seems to work fine if used sparingly. I'd like to try out the pixel shader one, but I have absolutely no clue how to write shaders.