diff --git a/src/graphics/render/Emitter.cpp b/src/graphics/render/Emitter.cpp index 82848a63..09e1ddc8 100644 --- a/src/graphics/render/Emitter.cpp +++ b/src/graphics/render/Emitter.cpp @@ -23,8 +23,9 @@ Emitter::Emitter( texture(texture), count(count), preset(std::move(preset)) { + random.setSeed(rand()); this->prototype.emitter = this; - timer = preset.spawnInterval; + timer = preset.spawnInterval * random.randFloat(); } const Texture* Emitter::getTexture() const { @@ -83,6 +84,10 @@ void Emitter::update( Particle particle = prototype; particle.emitter = this; particle.random = random.rand32(); + if (glm::abs(preset.angleSpread) >= 0.005f) { + particle.angle = + random.randFloat() * preset.angleSpread * glm::pi() * 2; + } glm::vec3 spawnOffset = generate_coord(preset.spawnShape); spawnOffset *= preset.spawnSpread; diff --git a/src/graphics/render/Emitter.hpp b/src/graphics/render/Emitter.hpp index c1d6c168..0ad34053 100644 --- a/src/graphics/render/Emitter.hpp +++ b/src/graphics/render/Emitter.hpp @@ -27,6 +27,8 @@ struct Particle { float lifetime; /// @brief UV region UVRegion region; + /// @brief Current rotation angle + float angle; }; class Texture; @@ -39,7 +41,7 @@ class Emitter { EmitterOrigin origin; /// @brief Particle prototype Particle prototype; - /// @brief Particle + /// @brief Particle texture const Texture* texture; /// @brief Number of particles should be spawned before emitter deactivation. /// -1 is infinite. diff --git a/src/graphics/render/ParticlesRenderer.cpp b/src/graphics/render/ParticlesRenderer.cpp index 0e2292a5..71ec24c5 100644 --- a/src/graphics/render/ParticlesRenderer.cpp +++ b/src/graphics/render/ParticlesRenderer.cpp @@ -91,10 +91,23 @@ void ParticlesRenderer::renderParticles(const Camera& camera, float delta) { } float scale = 1.0f + ((particle.random ^ 2628172) % 1000) * 0.001f * preset.sizeSpread; + + glm::vec3 localRight = right; + glm::vec3 localUp = preset.globalUpVector ? glm::vec3(0, 1, 0) : up; + float angle = particle.angle; + if (glm::abs(angle) >= 0.005f) { + glm::vec3 rotatedRight(glm::cos(angle), -glm::sin(angle), 0.0f); + glm::vec3 rotatedUp(glm::sin(angle), glm::cos(angle), 0.0f); + + localRight = right * rotatedRight.x + localUp * rotatedRight.y + + camera.front * rotatedRight.z; + localUp = right * rotatedUp.x + localUp * rotatedUp.y + + camera.front * rotatedUp.z; + } batch->quad( particle.position, - right, - preset.globalUpVector ? glm::vec3(0, 1, 0) : up, + localRight, + localUp, preset.size * scale, light, glm::vec3(1.0f), diff --git a/src/presets/ParticlesPreset.cpp b/src/presets/ParticlesPreset.cpp index 181dbeb5..27274442 100644 --- a/src/presets/ParticlesPreset.cpp +++ b/src/presets/ParticlesPreset.cpp @@ -43,6 +43,7 @@ dv::value ParticlesPreset::serialize() const { root["explosion"] = dv::to_value(explosion); root["size"] = dv::to_value(size); root["size_spread"] = sizeSpread; + root["angle_spread"] = angleSpread; root["spawn_spread"] = dv::to_value(size); root["spawn_shape"] = to_string(spawnShape); root["random_sub_uv"] = randomSubUV; @@ -58,6 +59,7 @@ void ParticlesPreset::deserialize(const dv::value& src) { src.at("spawn_interval").get(spawnInterval); src.at("lifetime").get(lifetime); src.at("lifetime_spread").get(lifetimeSpread); + src.at("angle_spread").get(angleSpread); src.at("random_sub_uv").get(randomSubUV); if (src.has("velocity")) { dv::get_vec(src["velocity"], velocity); diff --git a/src/presets/ParticlesPreset.hpp b/src/presets/ParticlesPreset.hpp index f8d5f2b4..67c6c91b 100644 --- a/src/presets/ParticlesPreset.hpp +++ b/src/presets/ParticlesPreset.hpp @@ -44,6 +44,8 @@ struct ParticlesPreset : public Serializable { glm::vec3 size {0.1f}; /// @brief Particles size spread float sizeSpread = 0.2f; + /// @brief Random initial angle spread + float angleSpread = 0.0f; /// @brief Spawn spread shape ParticleSpawnShape spawnShape = BALL; /// @brief Spawn spread