Files
WoWee/include/rendering/celestial.hpp
Kelsi 7d44d2211d Implement WoW-accurate DBC-driven sky system with lore-faithful celestial bodies
Add SkySystem coordinator that follows WoW's actual architecture where skyboxes
are authoritative and procedural elements serve as fallbacks. Integrate lighting
system across all renderers (terrain, WMO, M2, character) with unified parameters.

Sky System:
- SkySystem coordinator manages skybox, celestial bodies, stars, clouds, lens flare
- Skybox is authoritative (baked stars from M2 models, procedural fallback only)
- skyboxHasStars flag gates procedural star rendering (prevents double-star bug)

Celestial Bodies (Lore-Accurate):
- Two moons: White Lady (30-day cycle, pale white) + Blue Child (27-day cycle, pale blue)
- Deterministic moon phases from server gameTime (not deltaTime toys)
- Sun positioning driven by LightingManager directionalDir (DBC-sourced)
- Camera-locked sky dome (translation ignored, rotation applied)

Lighting Integration:
- Apply LightingManager params to WMO, M2, character renderers
- Unified lighting: directional light, diffuse color, ambient color, fog
- Star occlusion by cloud density (70% weight) and fog density (30% weight)

Documentation:
- Add comprehensive SKY_SYSTEM.md technical guide
- Update MEMORY.md with sky system architecture and anti-patterns
- Update README.md with WoW-accurate descriptions

Critical design decisions:
- NO latitude-based star rotation (Azeroth not modeled as spherical planet)
- NO always-on procedural stars (skybox authority prevents zone identity loss)
- NO universal dual-moon setup (map-specific celestial configurations)
2026-02-10 14:36:17 -08:00

143 lines
4.4 KiB
C++

#pragma once
#include <memory>
#include <glm/glm.hpp>
namespace wowee {
namespace rendering {
class Shader;
class Camera;
/**
* Celestial body renderer
*
* Renders sun and moon that move across the sky based on time of day.
* Sun rises at dawn, sets at dusk. Moon is visible at night.
*/
class Celestial {
public:
Celestial();
~Celestial();
bool initialize();
void shutdown();
/**
* Render celestial bodies (sun and moon)
* @param camera Camera for view matrix
* @param timeOfDay Time of day in hours (0-24)
* @param sunDir Optional sun direction from lighting system (normalized)
* @param sunColor Optional sun color from lighting system
* @param gameTime Optional server game time in seconds (for deterministic moon phases)
*/
void render(const Camera& camera, float timeOfDay,
const glm::vec3* sunDir = nullptr,
const glm::vec3* sunColor = nullptr,
float gameTime = -1.0f);
/**
* Enable/disable celestial rendering
*/
void setEnabled(bool enabled) { renderingEnabled = enabled; }
bool isEnabled() const { return renderingEnabled; }
/**
* Update celestial bodies (for moon phase cycling)
*/
void update(float deltaTime);
/**
* Set White Lady phase (primary moon, 0.0 = new, 0.5 = full, 1.0 = new)
*/
void setMoonPhase(float phase);
float getMoonPhase() const { return whiteLadyPhase_; }
/**
* Set Blue Child phase (secondary moon, 0.0 = new, 0.5 = full, 1.0 = new)
*/
void setBlueChildPhase(float phase);
float getBlueChildPhase() const { return blueChildPhase_; }
/**
* Enable/disable automatic moon phase cycling
*/
void setMoonPhaseCycling(bool enabled) { moonPhaseCycling = enabled; }
bool isMoonPhaseCycling() const { return moonPhaseCycling; }
/**
* Enable/disable two-moon rendering (White Lady + Blue Child)
*/
void setDualMoonMode(bool enabled) { dualMoonMode_ = enabled; }
bool isDualMoonMode() const { return dualMoonMode_; }
/**
* Get sun position in world space
*/
glm::vec3 getSunPosition(float timeOfDay) const;
/**
* Get moon position in world space
*/
glm::vec3 getMoonPosition(float timeOfDay) const;
/**
* Get sun color (changes with time of day)
*/
glm::vec3 getSunColor(float timeOfDay) const;
/**
* Get sun intensity (0-1, fades at dawn/dusk)
*/
float getSunIntensity(float timeOfDay) const;
private:
void createCelestialQuad();
void destroyCelestialQuad();
void renderSun(const Camera& camera, float timeOfDay,
const glm::vec3* sunDir = nullptr,
const glm::vec3* sunColor = nullptr);
void renderMoon(const Camera& camera, float timeOfDay); // White Lady (primary)
void renderBlueChild(const Camera& camera, float timeOfDay); // Blue Child (secondary)
float calculateCelestialAngle(float timeOfDay, float riseTime, float setTime) const;
/**
* Compute moon phase from game time (deterministic)
* @param gameTime Server game time in seconds
* @param cycleDays Lunar cycle length in game days
* @return Phase 0.0-1.0 (0=new, 0.5=full, 1.0=new)
*/
float computePhaseFromGameTime(float gameTime, float cycleDays) const;
/**
* Update moon phases from game time (server-driven)
*/
void updatePhasesFromGameTime(float gameTime);
std::unique_ptr<Shader> celestialShader;
uint32_t vao = 0;
uint32_t vbo = 0;
uint32_t ebo = 0;
bool renderingEnabled = true;
// Moon phase system (two moons in Azeroth lore)
float whiteLadyPhase_ = 0.5f; // 0.0-1.0 (0=new, 0.5=full) - primary moon
float blueChildPhase_ = 0.25f; // 0.0-1.0 (0=new, 0.5=full) - secondary moon
bool moonPhaseCycling = true;
float moonPhaseTimer = 0.0f; // Fallback for deltaTime mode (development)
bool dualMoonMode_ = true; // Default: render both moons (Azeroth-specific)
// WoW lunar cycle constants (in game days)
// WoW day = 24 real minutes, so these are ~realistic game-world cycles
static constexpr float WHITE_LADY_CYCLE_DAYS = 30.0f; // ~12 real hours for full cycle
static constexpr float BLUE_CHILD_CYCLE_DAYS = 27.0f; // ~10.8 real hours (slightly faster)
static constexpr float MOON_CYCLE_DURATION = 240.0f; // Fallback: 4 minutes (deltaTime mode)
};
} // namespace rendering
} // namespace wowee