I'm currently trying to make a simple bullet hell game, and I've noticed that a single draw call slows things down a lot if there's a lot of vertices, and I'm not sure how to fix it.
I've made this simple sample version, to illustrate the issue.
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <chrono>
#include <iostream>
#include <memory>
static const sf::IntRect rect = {0,0,64,64};
static const sf::Vector2f initPos = {400,150};
class Bullet {
public:
Bullet(sf::Vector2f vel_) : velocity{vel_} {
vertices[0].texCoords = sf::Vector2f{0,0};
vertices[1].texCoords = sf::Vector2f{64,0};
vertices[2].texCoords = sf::Vector2f{64,64};
vertices[3].texCoords = sf::Vector2f{0,64};
for(size_t i=0; i<4; ++i)
vertices[i].position = initPos + vertices[i].texCoords;
vertices[4] = vertices[0];
vertices[5] = vertices[2];
}
void update() {
for(size_t i=0; i<6; ++i) {
vertices[i].position += velocity;
}
}
sf::Vertex* getVertices() {
return vertices;
}
private:
sf::Vertex vertices[6];
sf::Vector2f velocity;
};
int main() {
constexpr size_t TOTAL_BULLETS = 20000;
constexpr float pi = 4*std::atan(1);
std::unique_ptr<Bullet> bullets[TOTAL_BULLETS];
sf::VertexArray bulletVertices{sf::Triangles,TOTAL_BULLETS*6};
sf::Texture tex;
//tex.loadFromFile("bullets.png");
for(size_t i=0; i<TOTAL_BULLETS; ++i) {
float angle = 2*pi * static_cast<float>(i)/TOTAL_BULLETS;
auto vel = sf::Vector2f{std::cos(angle),std::sin(angle)} * 1.0f;
bullets[i] = std::make_unique<Bullet>(vel);
}
sf::RenderWindow window(sf::VideoMode(800,600), "Test");
while( window.isOpen() ) {
auto tp = std::chrono::steady_clock::now();
sf::Event event;
while( window.pollEvent(event) ) {
switch(event.type) {
case sf::Event::Closed:
window.close();
break;
default:
break;
}
}
for(size_t j=0; j<TOTAL_BULLETS; ++j) {
bullets[j]->update();
auto vertice = bullets[j]->getVertices();
for(size_t i=0; i<6; ++i)
bulletVertices[j*6+i] = vertice[i];
}
window.clear();
window.draw(bulletVertices,&tex); //This line slows things down a lot
window.display();
auto dur = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now()-tp);
std::cout<<"Frame takes: "<< dur.count() <<"microseconds.\n";
}
return 0;
}
The main point of interest is line 64, which is:
window.draw(bulletVertices,&tex); //This line slows things down a lot
This draws 120,000 vertices, or 40,000 triangles. By commenting it out, I've noticed that the program becomes a lot faster. (When uncommented, the frame time is about 45,000 microseconds, and commenting makes it becomes about 5,000 microseconds.)