Add mount dust particle effects

Implemented dust cloud particles that spawn at mount feet when running
on the ground, similar to the original WoW. Features:

- Brownish/tan dust particles using point sprite rendering
- Spawn rate proportional to movement speed
- Particles rise up, drift backward, and fade out naturally
- Only active when mounted, moving, and on ground (not flying)
- Smooth particle animation with size growth and alpha fade

Uses similar particle system architecture as swim effects with
GL_POINTS rendering and custom shaders for soft circular particles.
This commit is contained in:
Kelsi 2026-02-09 01:24:17 -08:00
parent c6a915397c
commit c95c3db03a
5 changed files with 299 additions and 0 deletions

View file

@ -13,6 +13,7 @@
#include "rendering/lens_flare.hpp"
#include "rendering/weather.hpp"
#include "rendering/swim_effects.hpp"
#include "rendering/mount_dust.hpp"
#include "rendering/character_renderer.hpp"
#include "rendering/wmo_renderer.hpp"
#include "rendering/m2_renderer.hpp"
@ -295,6 +296,13 @@ bool Renderer::initialize(core::Window* win) {
swimEffects.reset();
}
// Create mount dust effects
mountDust = std::make_unique<MountDust>();
if (!mountDust->initialize()) {
LOG_WARNING("Failed to initialize mount dust effects");
mountDust.reset();
}
// Create character renderer
characterRenderer = std::make_unique<CharacterRenderer>();
if (!characterRenderer->initialize()) {
@ -1251,6 +1259,29 @@ void Renderer::update(float deltaTime) {
swimEffects->update(*camera, *cameraController, *waterRenderer, deltaTime);
}
// Update mount dust effects
if (mountDust) {
mountDust->update(deltaTime);
// Spawn dust when mounted and moving on ground
if (isMounted() && cameraController && !taxiFlight_) {
bool isMoving = cameraController->isMoving();
bool onGround = cameraController->isGrounded();
if (isMoving && onGround) {
// Calculate velocity from camera direction and speed
glm::vec3 forward = camera->getForward();
float speed = cameraController->getMovementSpeed();
glm::vec3 velocity = forward * speed;
velocity.z = 0.0f; // Ignore vertical component
// Spawn dust at mount's feet (slightly below character position)
glm::vec3 dustPos = characterPosition - glm::vec3(0.0f, 0.0f, mountHeightOffset_ * 0.8f);
mountDust->spawnDust(dustPos, velocity, isMoving);
}
}
}
// Update character animations
if (characterRenderer) {
characterRenderer->update(deltaTime);
@ -1650,6 +1681,11 @@ void Renderer::renderWorld(game::World* world) {
swimEffects->render(*camera);
}
// Render mount dust effects
if (mountDust && camera) {
mountDust->render(*camera);
}
// Compute view/projection once for all sub-renderers
const glm::mat4& view = camera ? camera->getViewMatrix() : glm::mat4(1.0f);
const glm::mat4& projection = camera ? camera->getProjectionMatrix() : glm::mat4(1.0f);