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\$
4
  • \$\begingroup\$ So is your issue that using your own image creates hard edges, instead of smooth, anti-aliased edges? \$\endgroup\$
    – user35344
    Commented Oct 2, 2016 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
    Commented Oct 2, 2016 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\$ Commented Oct 3, 2016 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
    Commented Oct 3, 2016 at 4:28

1 Answer 1

1
\$\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();
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .