Hello!
First of, I have tried to find the answer to these question in the forums, I can find a lot of people talking around the subject, but no-one that actually answers the questions more then touching the subjects. If there are, please give me the link(s) :-)
I'm playing around with different rendering techniques in SFML and from what I can understand drawing VertexArrays directly would be the most efficient way without resorting to writing yourself in opengl?
When I tried VertexArrays it was a lot quicker than sprites/shapes, but I feel that I cant really grasp what the maximum capability is. So I decided to test this.
Here is my minimal test-code for testing with 1 million particles where each particle is a square or quad:
#include "SFML/Graphics.hpp"
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
//Create objects
sf::RenderWindow window;
window.create(sf::VideoMode(1024, 768), "Test");
//One million rectangle particles are 4 million vertices
sf::VertexArray particles(sf::Quads, 4000000);
sf::Clock clock;
int microsecondsInSecond = 1000000;
sf::Text text;
sf::Font font;
//Change this to an actual font location
font.loadFromFile("content/VeraMono.ttf");
text.setFont(font);
text.setCharacterSize(24);
text.setFillColor(sf::Color::Red);
while (window.isOpen())
{
// handle events
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
//simulate updating the position and color of the particles
for (int i = 0; i < 1000000; i++)
{
particles[i * 4].position = sf::Vector2f(100, 100);
particles[i * 4 + 1].position = sf::Vector2f(200, 100);
particles[i * 4 + 2].position = sf::Vector2f(200, 200);
particles[i * 4 + 3].position = sf::Vector2f(100, 200);
for (int j = i * 4; j < i * 4 + 4; j++)
{
particles[i].color.r = static_cast<sf::Uint8>(255);
particles[i].color.g = static_cast<sf::Uint8>(255);
particles[i].color.b = static_cast<sf::Uint8>(255);
particles[i].color.a = static_cast<sf::Uint8>(255);
}
}
//clear window with black
window.clear(sf::Color::Black);
//Draw
window.draw(particles);
window.draw(text);
window.display();
//Print current aproximate fps
std::string fps("fps: " + std::to_string((microsecondsInSecond / clock.restart().asMicroseconds())));
text.setString(fps);
}
}
On a pretty decent desktop computer this gives me an approximate fps of around 7-8. That seems way to low :-/
With 100 000 particles I get around 70.
So three questions:
- Did I make some mistake in my code that makes it slow?
- Is there some other way in SFML to make it even faster?
- Am I naive to think that a million particles each frame should be doable? (I recall people mentioning "drawing millions of vertices" in other threads, but I could have misunderstood)
- Is one million particles unreasonable in any way? Should I try to rewrite my particle effects so that they use fewer particles?
For a naive example when drawing a circle of light, that could be for example 360 triangles to form up the circle, 360 * 3= 1080. If 100 000 particles is the limit for keeping above 60 fps, that means I could only keep 100 lights on screen at the same time? That seems low...
Thanks for the answer!
You can try sf::VertexBuffer, which is the same as sf::VertexArray but which lives on the GPU. However since you have to reupload the data every frame anyway, I doubt it would make a significant difference.
Ah, I see, looking at the documentation I guess this would be the way to do it for example updating only the first and fourth.
sf::Vertex particles[40000];
sf::VertexBuffer buffer(sf::Quads);
buffer.create(40000);
//Update the first particle
buffer.update(particles,1080,0);
//Update the fourth particle
buffer.update(particles,1080,1080*4);
window.draw(buffer);
One weird thing though, when I set the sf::Vertex particles[size]; to a large enough size the whole program refuse to start Do you have any idea why or is that something compiler dependent?
That sounds really high to me. What kind of environment has 100 different lights in the same area?
Maybe :) I was thinking of some diablo 3 -esque scene where lots of spells are filling up the whole screen ;)
You should first decide what effect(s) you want to implement, and then try to find the most efficient way to do it -- the latter depends on the former ;) Not the other way round
You are right ofc, here are the stuff I was trying to implement.
First I did this fire particle effect:
(https://i.imgur.com/OnSkXSl.gif)
And then I wanted to enhance it a bit with some lighting effects, and I realized that the fps dropped quite a bit compared to the fire. Not unreasonably but I felt that I wanted to know more of that the actual limitations would be, and what was possible.
(https://i.imgur.com/0P8YDPD.gif)
Buffer seems like the way to go. And an adjustment of my expectations ;)
There is always the possibility of pre-rendering some of the stuff as well, but where is the fun in that?