Optimize M2 update loop: skip static doodads, incremental spatial index
Some checks failed
Build / Build (arm64) (push) Has been cancelled
Build / Build (x86-64) (push) Has been cancelled
Build / Build (macOS arm64) (push) Has been cancelled
Build / Build (windows-arm64) (push) Has been cancelled
Build / Build (windows-x86-64) (push) Has been cancelled
Security / CodeQL (C/C++) (push) Has been cancelled
Security / Semgrep (push) Has been cancelled
Security / Sanitizer Build (ASan/UBSan) (push) Has been cancelled

- Split M2 instances into fast-path index lists (animated, particle-only,
  particle-all, smoke) to avoid iterating all 46K instances per frame
- Cache model flags (hasAnimation, disableAnimation, isSmoke, etc.) on
  M2Instance struct to eliminate per-frame hash lookups
- Replace full rebuildSpatialIndex on position/transform updates with
  incremental grid cell remove+add, preventing 8.5ms/frame rebuild cost
- Advance animTime for all instances (texture UV animation) but only
  compute bones and particles for the ~3K that need it

M2_UPDATE: 10.7ms → 2.0ms, FPS: 35 → 55-59
This commit is contained in:
Kelsi 2026-03-02 14:45:49 -08:00
parent 7535084652
commit 3482dacea8
4 changed files with 177 additions and 62 deletions

View file

@ -174,6 +174,13 @@ struct M2Instance {
std::vector<float> emitterAccumulators; // fractional particle counter per emitter
std::vector<M2Particle> particles;
// Cached model flags (set at creation to avoid per-frame hash lookups)
bool cachedHasAnimation = false;
bool cachedDisableAnimation = false;
bool cachedIsSmoke = false;
bool cachedHasParticleEmitters = false;
float cachedBoundRadius = 0.0f;
// Frame-skip optimization (update distant animations less frequently)
uint8_t frameSkipCounter = 0;
@ -451,8 +458,14 @@ private:
std::vector<std::future<void>> animFutures_; // Reused each frame
bool spatialIndexDirty_ = false;
// Fast-path instance index lists (rebuilt in rebuildSpatialIndex / on create)
std::vector<size_t> animatedInstanceIndices_; // hasAnimation && !disableAnimation
std::vector<size_t> particleOnlyInstanceIndices_; // !hasAnimation && hasParticleEmitters
std::vector<size_t> particleInstanceIndices_; // ALL instances with particle emitters
// Smoke particle system
std::vector<SmokeParticle> smokeParticles;
std::vector<size_t> smokeInstanceIndices_; // Indices into instances[] for smoke emitters
static constexpr int MAX_SMOKE_PARTICLES = 1000;
float smokeEmitAccum = 0.0f;
std::mt19937 smokeRng{42};