update particles garbage collection scheme

This commit is contained in:
MihailRis 2024-11-02 22:15:26 +03:00
parent cee214754b
commit 1974298c82
5 changed files with 50 additions and 21 deletions

View File

@ -16,6 +16,7 @@ Emitter::Emitter(
texture(texture), texture(texture),
spawnInterval(spawnInterval), spawnInterval(spawnInterval),
count(count) { count(count) {
this->prototype.emitter = this;
} }
const Texture* Emitter::getTexture() const { const Texture* Emitter::getTexture() const {

View File

@ -8,10 +8,19 @@
#include "maths/UVRegion.hpp" #include "maths/UVRegion.hpp"
class Emitter;
struct Particle { struct Particle {
/// @brief Pointer used to access common behaviour.
/// Emitter must be utilized after all related particles despawn.
Emitter* emitter;
/// @brief Global position
glm::vec3 position; glm::vec3 position;
/// @brief Linear velocity
glm::vec3 velocity; glm::vec3 velocity;
/// @brief Remaining life time
float lifetime; float lifetime;
/// @brief UV region
UVRegion region; UVRegion region;
}; };
@ -43,6 +52,7 @@ public:
int count int count
); );
/// @return Emitter particles texture
const Texture* getTexture() const; const Texture* getTexture() const;
/// @brief Update emitter and spawn particles /// @brief Update emitter and spawn particles
@ -50,7 +60,9 @@ public:
/// @param particles destination particles vector /// @param particles destination particles vector
void update(float delta, std::vector<Particle>& particles); void update(float delta, std::vector<Particle>& particles);
/// @brief Set initial random velocity magitude
void setExplosion(const glm::vec3& magnitude); void setExplosion(const glm::vec3& magnitude);
/// @return true if the emitter has spawned all particles
bool isDead() const; bool isDead() const;
}; };

View File

@ -15,24 +15,24 @@ ParticlesRenderer::ParticlesRenderer(const Assets& assets)
auto region = util::get_texture_region(assets, "blocks:grass_side", ""); auto region = util::get_texture_region(assets, "blocks:grass_side", "");
Emitter emitter(glm::vec3(0, 100, 0), Particle { Emitter emitter(glm::vec3(0, 100, 0), Particle {
glm::vec3(), glm::vec3(), 5.0f, region.region nullptr, glm::vec3(), glm::vec3(), 5.0f, region.region
},region.texture, 0.001f, -1); },region.texture, 0.001f, 1000);
emitters.push_back(std::move(emitter)); emitters.push_back(std::make_unique<Emitter>(emitter));
} }
ParticlesRenderer::~ParticlesRenderer() = default; ParticlesRenderer::~ParticlesRenderer() = default;
void ParticlesRenderer::render( void ParticlesRenderer::renderParticles(const Camera& camera, float delta) {
const Assets& assets, const Camera& camera, float delta
) {
const auto& right = camera.right; const auto& right = camera.right;
const auto& up = camera.up; const auto& up = camera.up;
batch->begin(); std::vector<const Texture*> unusedTextures;
aliveEmitters = emitters.size();
visibleParticles = 0;
for (auto& [texture, vec] : particles) { for (auto& [texture, vec] : particles) {
if (vec.empty()) {
unusedTextures.push_back(texture);
continue;
}
batch->setTexture(texture); batch->setTexture(texture);
visibleParticles += vec.size(); visibleParticles += vec.size();
@ -62,24 +62,36 @@ void ParticlesRenderer::render(
} }
} }
batch->flush(); batch->flush();
for (const auto& texture : unusedTextures) {
particles.erase(texture);
}
}
void ParticlesRenderer::render(const Camera& camera, float delta) {
batch->begin();
aliveEmitters = emitters.size();
visibleParticles = 0;
renderParticles(camera, delta);
auto iter = emitters.begin(); auto iter = emitters.begin();
while (iter != emitters.end()) { while (iter != emitters.end()) {
auto& emitter = *iter; auto& emitter = **iter;
auto texture = emitter.getTexture(); auto texture = emitter.getTexture();
const auto& found = particles.find(texture); const auto& found = particles.find(texture);
std::vector<Particle>* vec; std::vector<Particle>* vec;
if (found == particles.end()) { if (found == particles.end()) {
if (emitter.isDead()) {
// destruct Emitter only when there is no particles spawned by it
iter = emitters.erase(iter);
continue;
}
vec = &particles[texture]; vec = &particles[texture];
} else { } else {
vec = &found->second; vec = &found->second;
} }
emitter.update(delta, *vec); emitter.update(delta, *vec);
iter++;
if (emitter.isDead()) {
iter = emitters.erase(iter);
} else {
iter++;
}
} }
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include <memory>
#include <unordered_map> #include <unordered_map>
#include "Emitter.hpp" #include "Emitter.hpp"
@ -12,13 +13,15 @@ class MainBatch;
class ParticlesRenderer { class ParticlesRenderer {
std::unordered_map<const Texture*, std::vector<Particle>> particles; std::unordered_map<const Texture*, std::vector<Particle>> particles;
std::vector<Emitter> emitters; std::vector<std::unique_ptr<Emitter>> emitters;
std::unique_ptr<MainBatch> batch; std::unique_ptr<MainBatch> batch;
void renderParticles(const Camera& camera, float delta);
public: public:
ParticlesRenderer(const Assets& assets); ParticlesRenderer(const Assets& assets);
~ParticlesRenderer(); ~ParticlesRenderer();
void render(const Assets& assets, const Camera& camera, float delta); void render(const Camera& camera, float delta);
static size_t visibleParticles; static size_t visibleParticles;
static size_t aliveEmitters; static size_t aliveEmitters;

View File

@ -203,7 +203,8 @@ void WorldRenderer::renderLevel(
auto assets = engine->getAssets(); auto assets = engine->getAssets();
bool culling = engine->getSettings().graphics.frustumCulling.get(); bool culling = engine->getSettings().graphics.frustumCulling.get();
float fogFactor = 15.0f / ((float)settings.chunks.loadDistance.get() - 2); float fogFactor =
15.0f / static_cast<float>(settings.chunks.loadDistance.get() - 2);
auto entityShader = assets->get<Shader>("entity"); auto entityShader = assets->get<Shader>("entity");
setupWorldShader(entityShader, camera, settings, fogFactor); setupWorldShader(entityShader, camera, settings, fogFactor);
@ -216,7 +217,7 @@ void WorldRenderer::renderLevel(
delta, delta,
pause pause
); );
particles->render(*assets, camera, delta * !pause); particles->render(camera, delta * !pause);
modelBatch->render(); modelBatch->render();
auto shader = assets->get<Shader>("main"); auto shader = assets->get<Shader>("main");