1
\$\begingroup\$

I want to simulate a night and day cycle with SFML (plain 2D, no shadows). What I want is to get a smooth transition from day to night, and during night having some lights "on".

So the approach I've thought is adding a black layer on top and change its transparency with time, that gives the effect I'm looking for. For adding lights I can crop out circles out of that layer

sf::CircleShape lightCircle(200);
lightCircle.setFillColor(sf::Color(255, 255, 255, 1));

sf::RenderTexture renderTexture;
renderTexture.create(/* view size */);

while (window.isOpen()) {
  // ...

  // update light
  renderTexture.clear(sf::Color::Black);
  renderTexture.draw(lightCircle, sf::BlendNone);
  renderTexture.display();

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

Now, what I would like to do is use my own image instead of a CircleShape. Say a circle or a cone with fading borders, some more realistic than just a circle. Like

enter image description here

I have tried with sf::Image and createMaskFromColor but I'm not able to handle the fading edges.

How can I get that?

Am I in the right path or is there a simpler approach?

\$\endgroup\$
  • \$\begingroup\$ So is your issue that using your own image creates hard edges, instead of smooth, anti-aliased edges? \$\endgroup\$ – Tyyppi_77 Oct 2 '16 at 13:54
  • \$\begingroup\$ My image has some transparency (see updated post), my issue is that I don't know how to subtract that image from the renderTexture \$\endgroup\$ – nsubiron Oct 2 '16 at 14:28
  • 1
    \$\begingroup\$ I wrote up a general description of how I did this in xna including handling multiple light sources. Might be helpful: gamedev.stackexchange.com/a/22163/5060 \$\endgroup\$ – Richard Marskell - Drackir Oct 3 '16 at 0:01
  • \$\begingroup\$ Would it make sense if you drew all lights to a second render target at first (using your first image, but white instead of black) and then mutipying the color of your scene by the r, g or b value of your second render target? \$\endgroup\$ – Peethor Oct 3 '16 at 4:28
2
\$\begingroup\$

The trick is defining a custom blend mode that substract the alpha pattern of the image from the render target

sf::BlendMode blendMode(
    sf::BlendMode::Factor::Zero,              // color src
    sf::BlendMode::Factor::DstColor,          // color dst
    sf::BlendMode::Equation::Add,             // color eq
    sf::BlendMode::Factor::Zero,              // alpha src
    sf::BlendMode::Factor::OneMinusSrcAlpha,  // alpha dst
    sf::BlendMode::Equation::Add);            // alpha eq

There might be a more straight forward way of doing this, but this one does the trick.

enter image description here

The code looks something like this

sf::RenderTexture renderTexture;
renderTexture.create(/* view size */);

sf::Texture lightTexture;
if (!lightTexture.loadFromFile("light.png")) {
return 1;
}
sf::Sprite light0(lightTexture);
sf::Sprite light1(lightTexture);

while (window.isOpen()) {
  // ...

  // update light
  renderTexture.clear();
  renderTexture.draw(light0, blendMode);
  renderTexture.draw(light1, blendMode);
  renderTexture.display();
  sf::Sprite night(renderTexture.getTexture());

  float luminosity = 200.0f;
  night.setColor(sf::Color(10.0f, 10.0f, 10.0f, luminosity));

  // draw
  window.clear();
  window.draw(background);
  window.draw(night);
  window.display();
}
|improve this answer|||||
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.