From 1974298c8243e01640f59aea77bc4032a7525c9b Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 2 Nov 2024 22:15:26 +0300 Subject: [PATCH] update particles garbage collection scheme --- src/graphics/render/Emitter.cpp | 1 + src/graphics/render/Emitter.hpp | 12 ++++++ src/graphics/render/ParticlesRenderer.cpp | 46 ++++++++++++++--------- src/graphics/render/ParticlesRenderer.hpp | 7 +++- src/graphics/render/WorldRenderer.cpp | 5 ++- 5 files changed, 50 insertions(+), 21 deletions(-) diff --git a/src/graphics/render/Emitter.cpp b/src/graphics/render/Emitter.cpp index 5ccd62e1..58f9c809 100644 --- a/src/graphics/render/Emitter.cpp +++ b/src/graphics/render/Emitter.cpp @@ -16,6 +16,7 @@ Emitter::Emitter( texture(texture), spawnInterval(spawnInterval), count(count) { + this->prototype.emitter = this; } const Texture* Emitter::getTexture() const { diff --git a/src/graphics/render/Emitter.hpp b/src/graphics/render/Emitter.hpp index aa2a27e5..6a1dc06c 100644 --- a/src/graphics/render/Emitter.hpp +++ b/src/graphics/render/Emitter.hpp @@ -8,10 +8,19 @@ #include "maths/UVRegion.hpp" +class Emitter; + 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; + /// @brief Linear velocity glm::vec3 velocity; + /// @brief Remaining life time float lifetime; + /// @brief UV region UVRegion region; }; @@ -43,6 +52,7 @@ public: int count ); + /// @return Emitter particles texture const Texture* getTexture() const; /// @brief Update emitter and spawn particles @@ -50,7 +60,9 @@ public: /// @param particles destination particles vector void update(float delta, std::vector& particles); + /// @brief Set initial random velocity magitude void setExplosion(const glm::vec3& magnitude); + /// @return true if the emitter has spawned all particles bool isDead() const; }; diff --git a/src/graphics/render/ParticlesRenderer.cpp b/src/graphics/render/ParticlesRenderer.cpp index 7f0b67f5..065eebb3 100644 --- a/src/graphics/render/ParticlesRenderer.cpp +++ b/src/graphics/render/ParticlesRenderer.cpp @@ -15,24 +15,24 @@ ParticlesRenderer::ParticlesRenderer(const Assets& assets) auto region = util::get_texture_region(assets, "blocks:grass_side", ""); Emitter emitter(glm::vec3(0, 100, 0), Particle { - glm::vec3(), glm::vec3(), 5.0f, region.region - },region.texture, 0.001f, -1); - emitters.push_back(std::move(emitter)); + nullptr, glm::vec3(), glm::vec3(), 5.0f, region.region + },region.texture, 0.001f, 1000); + emitters.push_back(std::make_unique(emitter)); } ParticlesRenderer::~ParticlesRenderer() = default; -void ParticlesRenderer::render( - const Assets& assets, const Camera& camera, float delta -) { +void ParticlesRenderer::renderParticles(const Camera& camera, float delta) { const auto& right = camera.right; const auto& up = camera.up; - batch->begin(); - - aliveEmitters = emitters.size(); - visibleParticles = 0; + std::vector unusedTextures; + for (auto& [texture, vec] : particles) { + if (vec.empty()) { + unusedTextures.push_back(texture); + continue; + } batch->setTexture(texture); visibleParticles += vec.size(); @@ -62,24 +62,36 @@ void ParticlesRenderer::render( } } 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(); while (iter != emitters.end()) { - auto& emitter = *iter; + auto& emitter = **iter; auto texture = emitter.getTexture(); const auto& found = particles.find(texture); std::vector* vec; 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]; } else { vec = &found->second; } emitter.update(delta, *vec); - - if (emitter.isDead()) { - iter = emitters.erase(iter); - } else { - iter++; - } + iter++; } } diff --git a/src/graphics/render/ParticlesRenderer.hpp b/src/graphics/render/ParticlesRenderer.hpp index c7bca3fb..0ca55123 100644 --- a/src/graphics/render/ParticlesRenderer.hpp +++ b/src/graphics/render/ParticlesRenderer.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include "Emitter.hpp" @@ -12,13 +13,15 @@ class MainBatch; class ParticlesRenderer { std::unordered_map> particles; - std::vector emitters; + std::vector> emitters; std::unique_ptr batch; + + void renderParticles(const Camera& camera, float delta); public: ParticlesRenderer(const Assets& assets); ~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 aliveEmitters; diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 12a2c798..c1e85451 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -203,7 +203,8 @@ void WorldRenderer::renderLevel( auto assets = engine->getAssets(); bool culling = engine->getSettings().graphics.frustumCulling.get(); - float fogFactor = 15.0f / ((float)settings.chunks.loadDistance.get() - 2); + float fogFactor = + 15.0f / static_cast(settings.chunks.loadDistance.get() - 2); auto entityShader = assets->get("entity"); setupWorldShader(entityShader, camera, settings, fogFactor); @@ -216,7 +217,7 @@ void WorldRenderer::renderLevel( delta, pause ); - particles->render(*assets, camera, delta * !pause); + particles->render(camera, delta * !pause); modelBatch->render(); auto shader = assets->get("main");