Mi udało się osiągnąć coś takiego (plus link do filmu). Kod:
#include <iostream>
#include <vector>
#include <SFML/Graphics.hpp>
#include <random>
#include <type_traits>
namespace hip
{
template<typename T>
T random(const T& begin, const T& end)
{
using rand_distrib = std::conditional
<
std::is_floating_point<T>::value,
std::uniform_real_distribution<T>,
std::uniform_int_distribution<T>
>::type;
static std::random_device rd;
static std::mt19937_64 gen(rd());
rand_distrib dis(begin, end);
return dis(gen);
}
}
struct CirclesPack
{
std::vector<sf::CircleShape> circles;
sf::BlendMode blendMode;
public:
void add(sf::Vector2f pos, float rad)
{
sf::CircleShape bufor;
bufor.setRadius(rad);
bufor.setOrigin(rad, rad);
int r = hip::random(0, 255);
int g = hip::random(0, 255);
int b = hip::random(0, 255);
bufor.setFillColor(sf::Color(r, g, b));
bufor.setPosition(pos);
circles.push_back(bufor);
}
void setBlendMode(const sf::BlendMode blendMode)
{
this->blendMode = blendMode;
}
void draw(sf::RenderWindow& window)
{
for (auto& i: circles) window.draw(i, blendMode);
}
};
int main()
{
sf::Clock clock;
sf::RenderWindow window(sf::VideoMode(800, 600), "My window");
CirclesPack circles;
circles.setBlendMode(
sf::BlendMode
(
sf::BlendMode::Factor::OneMinusDstAlpha,
sf::BlendMode::Factor::OneMinusDstAlpha,
sf::BlendMode::Equation::Add
)
);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
if (event.type == sf::Event::MouseButtonPressed)
{
float radius = hip::random<float>(10, 100);
sf::Vector2f where(sf::Mouse::getPosition(window));
circles.add(where, radius);
}
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
circles.add(sf::Vector2f(sf::Mouse::getPosition(window)), 100);
if (clock.getElapsedTime() > sf::milliseconds(200))
{
clock.restart();
float radius = hip::random<float>(10, 100);
circles.add(
sf::Vector2f(
hip::random<float>(0, window.getSize().x),
hip::random<float>(0, window.getSize().y)
),
radius
);
}
window.clear(sf::Color::Black);
circles.draw(window);
window.display();
}
}
Rzeczywiście jest bardzo mało źródeł jak stosować sf::Blend. Jednak z pomocą przychodzi plik "BlendMode.hpp", który można znaleźć w folderze z biblioteką SFML. Zacytuję zawartość bez części komentarzy w wersji 2.4.2:
#ifndef SFML_BLENDMODE_HPP
#define SFML_BLENDMODE_HPP
#include <SFML/Graphics/Export.hpp>
namespace sf
{
struct SFML_GRAPHICS_API BlendMode
{
enum Factor
{
Zero, ///< (0, 0, 0, 0)
One, ///< (1, 1, 1, 1)
SrcColor, ///< (src.r, src.g, src.b, src.a)
OneMinusSrcColor, ///< (1, 1, 1, 1) - (src.r, src.g, src.b, src.a)
DstColor, ///< (dst.r, dst.g, dst.b, dst.a)
OneMinusDstColor, ///< (1, 1, 1, 1) - (dst.r, dst.g, dst.b, dst.a)
SrcAlpha, ///< (src.a, src.a, src.a, src.a)
OneMinusSrcAlpha, ///< (1, 1, 1, 1) - (src.a, src.a, src.a, src.a)
DstAlpha, ///< (dst.a, dst.a, dst.a, dst.a)
OneMinusDstAlpha ///< (1, 1, 1, 1) - (dst.a, dst.a, dst.a, dst.a)
};
enum Equation
{
Add, ///< Pixel = Src * SrcFactor + Dst * DstFactor
Subtract, ///< Pixel = Src * SrcFactor - Dst * DstFactor
ReverseSubtract ///< Pixel = Dst * DstFactor - Src * SrcFactor
};
BlendMode();
BlendMode(Factor sourceFactor, Factor destinationFactor, Equation blendEquation = Add);
BlendMode(Factor colorSourceFactor, Factor colorDestinationFactor,
Equation colorBlendEquation, Factor alphaSourceFactor,
Factor alphaDestinationFactor, Equation alphaBlendEquation);
Factor colorSrcFactor; ///< Source blending factor for the color channels
Factor colorDstFactor; ///< Destination blending factor for the color channels
Equation colorEquation; ///< Blending equation for the color channels
Factor alphaSrcFactor; ///< Source blending factor for the alpha channel
Factor alphaDstFactor; ///< Destination blending factor for the alpha channel
Equation alphaEquation; ///< Blending equation for the alpha channel
};
SFML_GRAPHICS_API bool operator ==(const BlendMode& left, const BlendMode& right);
SFML_GRAPHICS_API bool operator !=(const BlendMode& left, const BlendMode& right);
SFML_GRAPHICS_API extern const BlendMode BlendAlpha; ///< Blend source and dest according to dest alpha
SFML_GRAPHICS_API extern const BlendMode BlendAdd; ///< Add source to dest
SFML_GRAPHICS_API extern const BlendMode BlendMultiply; ///< Multiply source and dest
SFML_GRAPHICS_API extern const BlendMode BlendNone; ///< Overwrite dest with source
} // namespace sf
#endif // SFML_BLENDMODE_HPP
Po paru innych plikach doszedłem do wniosku, że blendować można też tekstury. Stwierdziłem, że fajnym doświadczeniem byłoby wygenerowanie tekstury światła. Zrobiłem też jakieś nałożenie blendem, ale nie mam pomysłu jak zrobić to prawidłowo. Teraz wygląda to trochę śmiesznie:
#include <SFML/Graphics.hpp>
int main()
{
sf::Clock clock;
float dt = 0;
sf::RenderWindow window(sf::VideoMode(800, 600), "My window");
sf::Texture texture;
std::string light_path = "light.png";
int radius = 100;
sf::Vector2i image_size(2*radius, 2*radius);
bool jeszcze_nie_mam_zdjyncia = true;
if (jeszcze_nie_mam_zdjyncia)
{
sf::Image image;
image.create(image_size.x, image_size.y);
for (int x = -image_size.x/2; x < image_size.x/2; x++)
{
for (int y = -image_size.y/2; y < image_size.y/2; y++)
{
if (x*x + y*y < radius*radius)
{
int r = std::hypot(x, y); // r bedzie od 0 do max 50, a rr (wartosc A) chce by była od 0 do 255 wiec trzeba przeliczyc:
int rr = 255 - int( (float) r*255.f / radius );
image.setPixel(radius + x, radius + y, sf::Color(255, 255, 0, rr));
}
else image.setPixel(radius + x, radius + y, sf::Color::Transparent);
}
}
image.saveToFile(light_path);
texture.loadFromImage(image);
jeszcze_nie_mam_zdjyncia = false;
}
else
{
texture.loadFromFile(light_path);
}
sf::Sprite circle1;
circle1.setTexture(texture);
circle1.setOrigin(image_size.x, image_size.y);
circle1.setPosition(sf::Vector2f(window.getSize() / 2u));
sf::Sprite circle2;
circle2.setTexture(texture);
circle2.setOrigin(image_size.x, image_size.y);
circle2.setPosition(sf::Vector2f(window.getSize() / 2u));
circle1.move({ 30, 30 });
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
float speed = 200;
sf::Vector2f velocity;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) velocity.y -= speed;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) velocity.y += speed;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) velocity.x -= speed;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) velocity.x += speed;
dt = clock.restart().asSeconds();
circle1.move(velocity*dt);
window.clear(sf::Color::Black);
auto factor1 = sf::BlendMode::Factor::SrcAlpha;
auto blend = sf::BlendMode // jeszcze jest BlendMode z 6 argumentami
(
factor1,
factor1,
sf::BlendMode::Equation::Add
);
window.draw(circle1, blend);
window.draw(circle2, blend);
window.display();
}
}
Może chociaż troszkę Ci to pomoże - sam chciałbym wiedzieć więcej. Jeżeli jednak nie to przynajmniej odkopię Twój temat i może ktoś inny coś napisze ;)