feat(lighting): seed estable per emissor (no deriva pel moviment)

This commit is contained in:
JailDesigner committed 2026-05-12 22:37:27 +02:00
1 parent 0046d526b0
commit 5cc8e349a5
5 files changed
+35 -15

No files matched your search

+9 -9
View File
@@ -50,14 +50,14 @@ namespace Lighting {
}
// Modula el radi base d'un emissor amb la suma de dues sinusoides
// (`wave` + `noise`) i una fase derivada de la posició. Per a dos
// antorxes diferents (cx, cy) les fases queden incommensurables
// entre si, així que mai oscil·len al unison — patró típic de
// foc. Multipliquem cx i cy per constants irracionals petites
// per evitar fases "rodones" quan la posició és múltiple de 16.
auto computeFlickerRadius(int base_radius, float cx, float cy, float t_s, const FlickerConfig& fc) -> int {
// (`wave` + `noise`) i una fase derivada de `seed`. La seed és un
// identificador estable de l'emissor (no canvia amb la posició) —
// així el patró no "deriva" quan l'emissor es mou. El factor
// ~φ (golden ratio) dispersa les fases per a seeds consecutives.
auto computeFlickerRadius(int base_radius, int seed, float t_s, const FlickerConfig& fc) -> int {
constexpr float TWO_PI = 2.0F * std::numbers::pi_v<float>;
const float PHASE = (cx * 0.0731F) + (cy * 0.1373F);
constexpr float GOLDEN_FRACTION = 0.6180339F;
const float PHASE = static_cast<float>(seed) * GOLDEN_FRACTION;
const float W1 = std::sin((TWO_PI * fc.wave_frequency_hz * t_s) + PHASE);
const float W2 = std::sin((TWO_PI * fc.noise_frequency_hz * t_s) + (PHASE * 2.7F));
const float DELTA = (fc.wave_amplitude_px * W1) + (fc.noise_amplitude_px * W2);
@@ -217,14 +217,14 @@ namespace Lighting {
for (const auto& e : emitters) {
if (e.radius <= 0) { continue; }
const int R_EFF = e.flicker
? computeFlickerRadius(e.radius, e.cx, e.cy, T_S, fc)
? computeFlickerRadius(e.radius, e.seed, T_S, fc)
: e.radius;
const auto RINGS = computeRings(R_EFF, cfg);
// El rasteritzador llegeix el radi de l'`Emitter` per al
// càlcul de la bounding box, així que li passem un emissor
// "patxat" amb el radi efectiu d'aquest frame. Mantenim el
// valor original al `Emitter` del caller intacte.
const Emitter EFF{.cx = e.cx, .cy = e.cy, .radius = R_EFF, .flicker = e.flicker};
const Emitter EFF{.cx = e.cx, .cy = e.cy, .radius = R_EFF, .seed = e.seed, .flicker = e.flicker};
rasterizeEmitter(EFF, RINGS, lum.data(), width, height);
}
+5 -4
View File
@@ -27,14 +27,15 @@ namespace Lighting {
// Posició al canvas (en píxels, mateixa unitat que la resta del
// motor) i radi efectiu de l'emissor. El centre és el del sprite
// visible: és l'entitat qui sap on cau (veure `Entity::getLightCenter`).
// `flicker` activa la modulació del radi per frame (només antorxes
// avui): el radi base es queda al YAML, l'oscil·lació en viu surt
// dels paràmetres globals i de la posició per generar fases
// distintes a cada emissor.
// `flicker` activa la modulació del radi per frame; `seed` és un
// identificador estable per emissor (no canvia amb la posició) del
// qual es deriva la fase del flicker — així els emissors mòbils
// mantenen un patró propi que no "deriva" pel moviment.
struct Emitter {
float cx{0.0F};
float cy{0.0F};
int radius{0};
int seed{0};
bool flicker{false};
};