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

Author Topic: Unintuitive default BlendMode for Sprites [solved]  (Read 1349 times)

0 Members and 2 Guests are viewing this topic.

Afrodeity

  • Newbie
  • *
  • Posts: 3
    • View Profile
Unintuitive default BlendMode for Sprites [solved]
« on: March 14, 2020, 09:27:00 pm »
Please take a look at the attached image of three circles, which is the output of the code below.
The left circle is the result of drawing the circle to a RenderTexture, texturing a sprite with it and drawing the sprite. It does not appear as intended.
The middle is the same sprite drawn with a modified blend mode. It appears as intended.
The right circle is drawn directly to the window without a modified blend mode. It also appears as intended.

My question is: Why does drawing the circle directly work as intended, while drawing a sprite of it requires a custom blend mode?

#include <SFML/Graphics.hpp>

int main() {
    sf::CircleShape circle(100.f);
    // Give the circle a texture so we can use a shader on it.
    sf::RenderTexture fallback;
    fallback.create(1, 1);
    fallback.clear(sf::Color::White);
    fallback.display();
    circle.setTexture(&fallback.getTexture());
    // Define a shader that goes from transparent on the left to red on the right.
    const std::string shaderCode = R"*(
        void main() {
            gl_FragColor = vec4(1,0,0,gl_TexCoord[0].x);
        }
    )*"
;
    sf::Shader shader;
    shader.loadFromMemory(shaderCode, sf::Shader::Fragment);
    // Draw the circle onto a RenderTexture.
    sf::RenderTexture canvas;
    canvas.create(200u, 200u);
    canvas.clear(sf::Color::Transparent);
    canvas.draw(circle, &shader);
    canvas.display();
    // Create a sprite from the RenderTexture.
    sf::Sprite circleSprite(canvas.getTexture());
    circleSprite.setPosition(50.f, 50.f);
    // Create a white window to draw the sprite on.
    sf::RenderWindow window(sf::VideoMode(800, 300), "Test");
    window.clear(sf::Color::White);
    //This appears red and gray because of the blend mode. That's unintuitive.
    window.draw(circleSprite);
    // Move the sprite and draw it again. This time with a modified blend mode.
    circleSprite.move(250.f, 0.f);
    sf::BlendMode intuitiveBlendMode;
    intuitiveBlendMode.colorSrcFactor = sf::BlendMode::One;
    window.draw(circleSprite, intuitiveBlendMode);
    // Drawing the shape directly to the window doesn't have this problem.
    circle.setPosition(550.f, 50.f);
    window.draw(circle, &shader);

    window.display();

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

    return 0;
}
 
« Last Edit: March 15, 2020, 04:59:13 pm by Afrodeity »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Unintuitive default BlendMode for Sprites
« Reply #1 on: March 15, 2020, 09:37:11 am »
Everything works as expected, what might be confusing you is that sf::Color::Transparent is in fact black with alpha = 0. So you're blending your circle with black color, when drawing to the render texture with default blending.

To preserve transparency (alpha) when using an intermediate render-texture, do a direct pixel copy, don't blend it (use sf::Blend::None).
Laurent Gomila - SFML developer

Afrodeity

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Unintuitive default BlendMode for Sprites
« Reply #2 on: March 15, 2020, 04:58:58 pm »
Ah, I understand. This has helped me greatly. Thank you.