-
So, I am facing this problem:
(https://i.imgur.com/in3NOrT.gif)
Basically, I have 2 rectangles ( body shadow and gun shadow ), each one having a black texture with 40% opacity that goes up to 80% in the place where they intersect. Is there a way to make the shadows appear as a single shape?
Thanks in advance !
-
This is probably not the only option, but you can draw all the shadows to a sf::RenderTexture without applying alpha blending ("None" blend mode), and then draw your render-texture with alpha blending enabled.
-
This is probably not the only option, but you can draw all the shadows to an sf::RenderTexture without applying alpha blending ("None" blend mode), and then draw your render-texture with alpha blending enabled.
I've looked at the sf::RenderTexture and sf::BlendMode documentation but I couldn't understand how to do it. I've tried something but I've created a buggy and laggy texture.
Could you help me with the code? Both bodyShadow and gunShadow are rectangles directly drawn on the window.
PS: I didn't set shadows transparency using setFillColor function, but using photoshop to add transparency to the texture (if this matters).
-
I've looked at the sf::RenderTexture and sf::BlendMode documentation but I couldn't understand how to do it. I've tried something but I've created a buggy and laggy texture.
Can you show what you've tried? We prefer to help people understand and fix their code, rather than giving code to copy and paste ;)
-
I deleted what I've done after I saw it doesn't work. I recreated it and I think it's a bit better than before.
So, I have a class called Player. I initialized the texture in Player constructor :
if (!texture.create(100, 100))
std::cout << "error" << std::endl;
And then here is Player draw function :
void Player::draw()
{
texture.clear(sf::Color::White);
//Application::getInstance()->window.draw(shadow); <---- that's the draw call I've been using before
texture.draw(shadow);
Application::getInstance()->window.draw(body); // draw of the body (not the shadow)
//Application::getInstance()->window.draw(gunShadow); <-- draw call used before
texture.draw(gunShadow);
Application::getInstance()->window.draw(gun);
// Some bullets draw thing, not important
for (size_t i = 0; i < bullets.size(); i++)
{
Application::getInstance()->window.draw(bullets.at(i).getBody());
}
texture.display();
sf::Sprite sprite(texture.getTexture());
Application::getInstance()->window.draw(sprite);
}
Right now, it kinda looks like a mask or something, but the problem is obviously still there because I haven't used sf::BlendMode.
That's how it looks :
(https://i.imgur.com/NuU3zfQ.png)
-
Note that shadow and gunShadow should be drawn to the render texture without any transparency. The transparency is added onto the texture when drawn.
On that texture, should be a fully opaque, probably solid colour, mask-type image. However, it's probably better if the render texture is cleared with sf::Transparent.
You can then just use a slightly transparent white colour (white with a non-full alpha channel) for the render sprite to draw it.
-
I see 3 mistakes in your code:
1. The render-texture should be cleared with transparent color, so you don't get that white background in addition to your shadows
2. As I said, the shadows should be drawn to the render-texture without alpha-blending (sf::BlendNone)
3. There should also be some position adjustements, obviously
To avoid having to adjust positions when drawing to the render-texture, you could just have it the same size as the window. This would also allow you to handle shadows of the whole scene, in case there are others to draw.
-
I was aware of the white clear color and later I realized that I should change the size too. I've also changed the textures so they are fully opaque. This is what I have right now:
void Player::draw()
{
texture.clear(sf::Color::Transparent);
texture.draw(shadow, sf::BlendNone);
Application::getInstance()->window.draw(body);
texture.draw(gunShadow, sf::BlendNone);
Application::getInstance()->window.draw(gun);
for (size_t i = 0; i < bullets.size(); i++)
{
Application::getInstance()->window.draw(bullets.at(i).getBody());
}
texture.display();
sf::Sprite sprite(texture.getTexture());
Application::getInstance()->window.draw(sprite);
}
But it still looks weird :
(https://i.imgur.com/uz8XAYo.png)
That's how it looks without BlendNone :
(https://i.imgur.com/TuicsNE.png)
I guess it should work if I would apply a color overlay to the whole texture, without using BlendNone on body and gun textures separately... Is this possible? What should I do next?
-
Ok, then do as Hapax suggested: your shadows should be opaque (you can even use the original textures, with a black color), so you can use regular alpha-blending, and then apply an opacity when you draw your render-texture to the window.
void Player::draw()
{
texture.clear(sf::Color::Transparent);
texture.draw(shadow); // shadow image is opaque black on transparent background
Application::getInstance()->window.draw(body);
texture.draw(gunShadow); // same here
Application::getInstance()->window.draw(gun);
for (size_t i = 0; i < bullets.size(); i++)
{
Application::getInstance()->window.draw(bullets.at(i).getBody());
}
texture.display();
sf::Sprite sprite(texture.getTexture());
sprite.setColor(sf::Color(255, 255, 255, 128)); // make the shadow overlay semi-transparent
Application::getInstance()->window.draw(sprite);
}
-
Damn, I was looking like an idiot for a SetFillColor function lol.
Thanks very much!