Documentation

Performance Optimization

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ β€” ΠΊΠ»ΡŽΡ‡Π΅Π²ΠΎΠΉ аспСкт Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΈΠ³Ρ€, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰ΠΈΠΉ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΏΠ»Π°Π²Π½Ρ‹Π΅ ΠΈ ΠΎΡ‚Π·Ρ‹Π²Ρ‡ΠΈΠ²Ρ‹Π΅ ΠΈΠ³Ρ€ΠΎΠ²Ρ‹Π΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Ρ‹.

Π’Π²Π΅Π΄Π΅Π½ΠΈΠ΅ Π² ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡŽ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Π² Wudgine β€” это процСсс ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΡ эффСктивности вашСй ΠΈΠ³Ρ€Ρ‹ для достиТСния ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½ΠΎΠΉ частоты ΠΊΠ°Π΄Ρ€ΠΎΠ² ΠΈ ΠΎΡ‚Π·Ρ‹Π²Ρ‡ΠΈΠ²ΠΎΠ³ΠΎ ΠΈΠ³Ρ€ΠΎΠ²ΠΎΠ³ΠΎ процСсса. Π’ этом Ρ€Π°Π·Π΄Π΅Π»Π΅ ΠΌΡ‹ рассмотрим Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ ΠΈ инструмСнты для выявлСния ΠΈ устранСния ΡƒΠ·ΠΊΠΈΡ… мСст ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ.

ΠŸΡ€ΠΎΡ„ΠΈΠ»ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈ выявлСниС ΡƒΠ·ΠΊΠΈΡ… мСст

ВстроСнныС инструмСнты профилирования

Wudgine прСдоставляСт ΠΌΠΎΡ‰Π½Ρ‹Π΅ инструмСнты профилирования для Π°Π½Π°Π»ΠΈΠ·Π° ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ вашСй ΠΈΠ³Ρ€Ρ‹:

#include "Wudgine/Core/Profiler.hpp"

void GameLoop() {
    // Начало профилирования сСкции
    WG_PROFILE_BEGIN("Game Loop");
    
    // Код ΠΈΠ³Ρ€ΠΎΠ²ΠΎΠ³ΠΎ Ρ†ΠΈΠΊΠ»Π°
    Update();
    Render();
    
    // Π—Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠ΅ профилирования сСкции
    WG_PROFILE_END();
}

void Update() {
    // АвтоматичСскоС ΠΏΡ€ΠΎΡ„ΠΈΠ»ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ
    WG_PROFILE_FUNCTION();
    
    // Код обновлСния ΠΈΠ³Ρ€Ρ‹
}

Визуализация Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ² профилирования

Wudgine Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ Π²ΠΈΠ·ΡƒΠ°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€ профилирования, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΠΎΠΆΠ½ΠΎ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ Π² Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΎΡ€Π΅:

// Π’ ΠΊΠΎΠ΄Π΅ рСдакторского инструмСнта
void RenderProfilerWindow() {
    if (ImGui::Begin("Profiler")) {
        Wudgine::Core::Profiler::RenderImGuiWindow();
    }
    ImGui::End();
}

Анализ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ CPU

  1. ГорячиС ΠΏΡƒΡ‚ΠΈ (Hot Paths) β€” идСнтификация Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, Π·Π°Π½ΠΈΠΌΠ°ΡŽΡ‰ΠΈΡ… наибольшСС врСмя выполнСния
  2. Частота Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² β€” Π°Π½Π°Π»ΠΈΠ· Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, Π²Ρ‹Π·Ρ‹Π²Π°Π΅ΠΌΡ‹Ρ… слишком часто
  3. ВрСмя выполнСния β€” ΠΈΠ·ΠΌΠ΅Ρ€Π΅Π½ΠΈΠ΅ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ выполнСния ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ

Анализ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ GPU

  1. GPU Profiler β€” Π°Π½Π°Π»ΠΈΠ· Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ выполнСния ΡˆΠ΅ΠΉΠ΄Π΅Ρ€ΠΎΠ² ΠΈ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°
  2. Π‘Ρ‡Π΅Ρ‚Ρ‡ΠΈΠΊΠΈ отрисовки β€” ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠ½Π³ количСства Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² отрисовки ΠΈ Ρ‚Ρ€Π΅ΡƒΠ³ΠΎΠ»ΡŒΠ½ΠΈΠΊΠΎΠ²
  3. ИспользованиС памяти GPU β€” Π°Π½Π°Π»ΠΈΠ· использования видСопамяти

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°

Π£Ρ€ΠΎΠ²Π½ΠΈ Π΄Π΅Ρ‚Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ (LOD)

БистСма LOD позволяСт ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠ΅Π½Π΅Π΅ Π΄Π΅Ρ‚Π°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Π΅ ΠΌΠΎΠ΄Π΅Π»ΠΈ для ΡƒΠ΄Π°Π»Π΅Π½Π½Ρ‹Ρ… ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ²:

// ΠšΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ LOD
struct LODComponent {
    std::vector<Wudgine::Resources::MeshHandle> meshLevels;
    float[] distanceThresholds;
    
    void UpdateLOD(const Wudgine::Math::Vector3& cameraPosition, 
                   Wudgine::ECS::Entity entity,
                   Wudgine::ECS::Registry& registry) {
        auto& transform = registry.get<TransformComponent>(entity);
        float distance = (transform.position - cameraPosition).Length();
        
        // Π’Ρ‹Π±ΠΎΡ€ подходящСго уровня Π΄Π΅Ρ‚Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ
        int lodLevel = 0;
        for (size_t i = 0; i < distanceThresholds.size(); i++) {
            if (distance > distanceThresholds[i]) {
                lodLevel = i + 1;
            }
        }
        
        // ΠŸΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π²Ρ‹Π±Ρ€Π°Π½Π½ΠΎΠ³ΠΎ уровня Π΄Π΅Ρ‚Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ
        if (lodLevel < meshLevels.size()) {
            auto& renderer = registry.get<MeshRendererComponent>(entity);
            renderer.mesh = meshLevels[lodLevel];
        }
    }
};

Окклюзия ΠΈ отсСчСниС

Wudgine прСдоставляСт ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌΡ‹ для отсСчСния Π½Π΅Π²ΠΈΠ΄ΠΈΠΌΡ‹Ρ… ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ²:

// БистСма отсСчСния
class CullingSystem : public Wudgine::ECS::System {
public:
    void Update(float deltaTime) override {
        auto& camera = GetWorld()->GetMainCamera();
        auto frustum = camera.GetFrustum();
        
        auto view = GetWorld()->GetRegistry().view<MeshRendererComponent, TransformComponent>();
        view.each([&frustum](auto entity, MeshRendererComponent& renderer, TransformComponent& transform) {
            // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° видимости ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°
            Wudgine::Math::BoundingBox worldBounds = transform.TransformBoundingBox(renderer.mesh->GetBoundingBox());
            renderer.visible = frustum.Intersects(worldBounds);
        });
    }
};

Π‘Π°Ρ‚Ρ‡ΠΈΠ½Π³ ΠΈ инстансинг

ОбъСдинСниС ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹Ρ… ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² для ΡƒΠΌΠ΅Π½ΡŒΡˆΠ΅Π½ΠΈΡ количСства Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² отрисовки:

// БистСма Π±Π°Ρ‚Ρ‡ΠΈΠ½Π³Π°
class BatchingSystem : public Wudgine::ECS::System {
public:
    void Initialize() override {
        // Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ систСмы Π±Π°Ρ‚Ρ‡ΠΈΠ½Π³Π°
    }
    
    void Update(float deltaTime) override {
        // Π“Ρ€ΡƒΠΏΠΏΠΈΡ€ΠΎΠ²ΠΊΠ° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² ΠΏΠΎ ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Π°ΠΌ ΠΈ мСшам
        std::unordered_map<MaterialMeshPair, std::vector<Wudgine::Math::Matrix4x4>> instanceGroups;
        
        auto view = GetWorld()->GetRegistry().view<MeshRendererComponent, TransformComponent>();
        view.each([&instanceGroups](auto entity, MeshRendererComponent& renderer, TransformComponent& transform) {
            if (renderer.visible) {
                MaterialMeshPair key{renderer.material, renderer.mesh};
                instanceGroups[key].push_back(transform.GetWorldMatrix());
            }
        });
        
        // ΠžΡ‚Ρ€ΠΈΡΠΎΠ²ΠΊΠ° сгруппированных ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ²
        for (const auto& [key, matrices] : instanceGroups) {
            Wudgine::Rendering::RenderInstanced(key.mesh, key.material, matrices);
        }
    }
};

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€ΠΎΠ²

Π‘ΠΎΠ²Π΅Ρ‚Ρ‹ ΠΏΠΎ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€ΠΎΠ²:

  1. ΠœΠΈΠ½ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ тСкстурных Π²Ρ‹Π±ΠΎΡ€ΠΎΠΊ β€” объСдинСниС тСкстур Π² атласы
  2. Π£ΠΏΡ€ΠΎΡ‰Π΅Π½ΠΈΠ΅ вычислСний β€” использованиС ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… вычислСний ΠΈ LUT
  3. УсловныС ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Ρ‹ β€” минимизация Π²Π΅Ρ‚Π²Π»Π΅Π½ΠΈΠΉ Π² ΡˆΠ΅ΠΉΠ΄Π΅Ρ€Π°Ρ…

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€Π°:

// Π€Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π½Ρ‹ΠΉ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€ с ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠ΅ΠΉ
#version 330 core

in vec2 TexCoord;
in vec3 Normal;
in vec3 FragPos;

uniform sampler2D albedoMap;
uniform sampler2D normalMap;
uniform sampler2D roughnessMetallicMap; // ОбъСдинСнная тСкстура для roughness ΠΈ metallic

out vec4 FragColor;

void main() {
    // Одна Π²Ρ‹Π±ΠΎΡ€ΠΊΠ° вмСсто Π΄Π²ΡƒΡ… ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ…
    vec4 roughnessMetallic = texture(roughnessMetallicMap, TexCoord);
    float roughness = roughnessMetallic.r;
    float metallic = roughnessMetallic.g;
    
    // ΠžΡΡ‚Π°Π»ΡŒΠ½ΠΎΠΉ ΠΊΠΎΠ΄ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€Π°
    // ...
}

Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΠ°ΠΌΡΡ‚ΡŒΡŽ

ΠŸΡƒΠ»Ρ‹ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ²

ИспользованиС ΠΏΡƒΠ»ΠΎΠ² ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² для ΡƒΠΌΠ΅Π½ΡŒΡˆΠ΅Π½ΠΈΡ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ памяти ΠΈ Π½Π°ΠΊΠ»Π°Π΄Π½Ρ‹Ρ… расходов Π½Π° Π²Ρ‹Π΄Π΅Π»Π΅Π½ΠΈΠ΅/освобоТдСниС:

#include "Wudgine/Core/ObjectPool.hpp"

// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΏΡƒΠ»Π° для частиц
Wudgine::Core::ObjectPool<ParticleData, 1000> particlePool;

// ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° ΠΈΠ· ΠΏΡƒΠ»Π°
ParticleData* particle = particlePool.Allocate();

// Настройка частицы
particle->position = position;
particle->velocity = velocity;
particle->lifetime = 2.0f;

// Π’ΠΎΠ·Π²Ρ€Π°Ρ‚ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Π² ΠΏΡƒΠ» послС использования
particlePool.Free(particle);

ΠšΡΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠ΅ использованиС

Π‘Ρ‚Ρ€Π°Ρ‚Π΅Π³ΠΈΠΈ ΠΊΡΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΡ для ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΡ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ:

class ResourceCache {
public:
    // ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ рСсурса ΠΈΠ· кэша ΠΈΠ»ΠΈ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ°, Ссли Π΅Π³ΠΎ Π½Π΅Ρ‚
    template<typename T>
    std::shared_ptr<T> GetResource(const std::string& key) {
        auto it = m_Cache.find(key);
        if (it != m_Cache.end()) {
            // РСсурс Π½Π°ΠΉΠ΄Π΅Π½ Π² кэшС
            return std::static_pointer_cast<T>(it->second);
        }
        
        // Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ° рСсурса
        std::shared_ptr<T> resource = LoadResource<T>(key);
        m_Cache[key] = resource;
        return resource;
    }
    
    // ΠžΡ‡ΠΈΡΡ‚ΠΊΠ° Π½Π΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Ρ… рСсурсов
    void CleanupUnused() {
        for (auto it = m_Cache.begin(); it != m_Cache.end();) {
            if (it->second.use_count() == 1) {
                // Волько кэш Π²Π»Π°Π΄Π΅Π΅Ρ‚ рСсурсом, ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ
                it = m_Cache.erase(it);
            } else {
                ++it;
            }
        }
    }
    
private:
    std::unordered_map<std::string, std::shared_ptr<void>> m_Cache;
    
    template<typename T>
    std::shared_ptr<T> LoadResource(const std::string& key);
};

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ структур Π΄Π°Π½Π½Ρ‹Ρ…

Π’Ρ‹Π±ΠΎΡ€ подходящих структур Π΄Π°Π½Π½Ρ‹Ρ… для ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹Ρ… Π·Π°Π΄Π°Ρ‡:

// ΠŸΡ€ΠΈΠΌΠ΅Ρ€ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠΉ структуры Π΄Π°Π½Π½Ρ‹Ρ… для пространствСнного поиска
class SpatialHashGrid {
public:
    SpatialHashGrid(float cellSize, int maxEntities)
        : m_CellSize(cellSize), m_InvCellSize(1.0f / cellSize) {
        // ΠŸΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ Π²Ρ‹Π΄Π΅Π»Π΅Π½ΠΈΠ΅ памяти для ΡƒΠΌΠ΅Π½ΡŒΡˆΠ΅Π½ΠΈΡ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ
        m_Grid.reserve(1000);
        m_EntityCells.resize(maxEntities);
    }
    
    void InsertEntity(int entityId, const Wudgine::Math::BoundingBox& bounds) {
        // ВычислСниС ячССк, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π·Π°Π½ΠΈΠΌΠ°Π΅Ρ‚ ΡΡƒΡ‰Π½ΠΎΡΡ‚ΡŒ
        std::vector<GridCell> cells = GetCellsForBounds(bounds);
        
        // Π‘ΠΎΡ…Ρ€Π°Π½Π΅Π½ΠΈΠ΅ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ ΠΎ ячСйках для быстрого удалСния
        m_EntityCells[entityId] = cells;
        
        // Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ сущности Π² ячСйки
        for (const auto& cell : cells) {
            m_Grid[cell].push_back(entityId);
        }
    }
    
    void RemoveEntity(int entityId) {
        // БыстроС ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠ΅ ΠΈΠ· всСх ячССк
        for (const auto& cell : m_EntityCells[entityId]) {
            auto& entities = m_Grid[cell];
            entities.erase(std::remove(entities.begin(), entities.end(), entityId), entities.end());
        }
        
        m_EntityCells[entityId].clear();
    }
    
    std::vector<int> GetNearbyEntities(const Wudgine::Math::Vector3& position, float radius) {
        std::vector<int> result;
        std::unordered_set<int> uniqueEntities;
        
        // ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ячССк Π² радиусС
        std::vector<GridCell> cells = GetCellsForSphere(position, radius);
        
        // Π‘Π±ΠΎΡ€ сущностСй ΠΈΠ· ячССк
        for (const auto& cell : cells) {
            auto it = m_Grid.find(cell);
            if (it != m_Grid.end()) {
                for (int entityId : it->second) {
                    uniqueEntities.insert(entityId);
                }
            }
        }
        
        result.assign(uniqueEntities.begin(), uniqueEntities.end());
        return result;
    }
    
private:
    using GridCell = std::tuple<int, int, int>;
    
    float m_CellSize;
    float m_InvCellSize;
    std::unordered_map<GridCell, std::vector<int>, GridCellHash> m_Grid;
    std::vector<std::vector<GridCell>> m_EntityCells;
    
    // Π’ΡΠΏΠΎΠΌΠΎΠ³Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹
    std::vector<GridCell> GetCellsForBounds(const Wudgine::Math::BoundingBox& bounds);
    std::vector<GridCell> GetCellsForSphere(const Wudgine::Math::Vector3& position, float radius);
};

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ Ρ„ΠΈΠ·ΠΈΠΊΠΈ ΠΈ ΠΊΠΎΠ»Π»ΠΈΠ·ΠΈΠΉ

ΠŸΡ€ΠΎΡΡ‚Ρ€Π°Π½ΡΡ‚Π²Π΅Π½Π½ΠΎΠ΅ Ρ€Π°Π·Π΄Π΅Π»Π΅Π½ΠΈΠ΅

ИспользованиС пространствСнных структур Π΄Π°Π½Π½Ρ‹Ρ… для ускорСния поиска ΠΊΠΎΠ»Π»ΠΈΠ·ΠΈΠΉ:

// БистСма Ρ„ΠΈΠ·ΠΈΠΊΠΈ с пространствСнным Ρ€Π°Π·Π΄Π΅Π»Π΅Π½ΠΈΠ΅ΠΌ
class OptimizedPhysicsSystem : public Wudgine::ECS::System {
public:
    void Initialize() override {
        m_SpatialGrid = std::make_unique<SpatialHashGrid>(10.0f, 10000);
    }
    
    void Update(float deltaTime) override {
        // ОбновлСниС пространствСнной сСтки
        UpdateSpatialGrid();
        
        // ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ΠΊΠΎΠ»Π»ΠΈΠ·ΠΈΠΉ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΏΠΎΡ‚Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎ ΠΏΠ΅Ρ€Π΅ΡΠ΅ΠΊΠ°ΡŽΡ‰ΠΈΠΌΠΈΡΡ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌΠΈ
        auto view = GetWorld()->GetRegistry().view<ColliderComponent, TransformComponent>();
        view.each([this, deltaTime](auto entity, ColliderComponent& collider, TransformComponent& transform) {
            // ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ Π±Π»ΠΈΠΆΠ°ΠΉΡˆΠΈΡ… ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ²
            auto nearbyEntities = m_SpatialGrid->GetNearbyEntities(transform.position, collider.boundingSphere.radius);
            
            // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΊΠΎΠ»Π»ΠΈΠ·ΠΈΠΉ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ с блиТайшими ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌΠΈ
            for (int otherEntity : nearbyEntities) {
                if (otherEntity != entity) {
                    CheckCollision(entity, otherEntity);
                }
            }
        });
    }
    
private:
    std::unique_ptr<SpatialHashGrid> m_SpatialGrid;
    
    void UpdateSpatialGrid() {
        // ОбновлСниС полоТСния всСх ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Π² сСткС
        auto view = GetWorld()->GetRegistry().view<ColliderComponent, TransformComponent>();
        view.each([this](auto entity, ColliderComponent& collider, TransformComponent& transform) {
            // ОбновлСниС полоТСния Π² сСткС
            m_SpatialGrid->RemoveEntity(entity);
            
            // ВычислСниС ΠΌΠΈΡ€ΠΎΠ²ΠΎΠ³ΠΎ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡ΠΈΠ²Π°ΡŽΡ‰Π΅Π³ΠΎ объСма
            Wudgine::Math::BoundingBox worldBounds = transform.TransformBoundingBox(collider.boundingBox);
            
            m_SpatialGrid->InsertEntity(entity, worldBounds);
        });
    }
    
    void CheckCollision(int entityA, int entityB) {
        // Π”Π΅Ρ‚Π°Π»ΡŒΠ½Π°Ρ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΊΠΎΠ»Π»ΠΈΠ·ΠΈΠΈ ΠΌΠ΅ΠΆΠ΄Ρƒ двумя сущностями
    }
};

Π£ΠΏΡ€ΠΎΡ‰Π΅Π½Π½Ρ‹Π΅ ΠΊΠΎΠ»Π»Π°ΠΉΠ΄Π΅Ρ€Ρ‹

ИспользованиС ΡƒΠΏΡ€ΠΎΡ‰Π΅Π½Π½Ρ‹Ρ… ΠΊΠΎΠ»Π»Π°ΠΉΠ΄Π΅Ρ€ΠΎΠ² для быстрых ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΎΠΊ:

// ΠšΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ с ΡƒΠΏΡ€ΠΎΡ‰Π΅Π½Π½Ρ‹ΠΌΠΈ ΠΊΠΎΠ»Π»Π°ΠΉΠ΄Π΅Ρ€Π°ΠΌΠΈ
struct OptimizedColliderComponent {
    // Π’ΠΎΡ‡Π½Ρ‹ΠΉ ΠΊΠΎΠ»Π»Π°ΠΉΠ΄Π΅Ρ€ для Ρ„ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠΉ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ
    Wudgine::Physics::Collider preciseCollider;
    
    // Π£ΠΏΡ€ΠΎΡ‰Π΅Π½Π½Ρ‹ΠΉ ΠΊΠΎΠ»Π»Π°ΠΉΠ΄Π΅Ρ€ для быстрой ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ
    Wudgine::Math::BoundingSphere boundingSphere;
    Wudgine::Math::BoundingBox boundingBox;
    
    // Двухэтапная ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΊΠΎΠ»Π»ΠΈΠ·ΠΈΠΈ
    bool CheckCollision(const OptimizedColliderComponent& other, 
                        const Wudgine::Math::Matrix4x4& thisTransform,
                        const Wudgine::Math::Matrix4x4& otherTransform) {
        // Быстрая ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° с использованиСм ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡ΠΈΠ²Π°ΡŽΡ‰ΠΈΡ… объСмов
        if (!boundingSphere.Intersects(other.boundingSphere, thisTransform, otherTransform)) {
            return false; // Быстрый ΠΎΡ‚ΠΊΠ°Π·
        }
        
        if (!boundingBox.Intersects(other.boundingBox, thisTransform, otherTransform)) {
            return false; // Π’Ρ‚ΠΎΡ€ΠΎΠΉ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ быстрого ΠΎΡ‚ΠΊΠ°Π·Π°
        }
        
        // Вочная ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΊΠΎΠ»Π»ΠΈΠ·ΠΈΠΈ
        return preciseCollider.CheckCollision(other.preciseCollider, thisTransform, otherTransform);
    }
};

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ для Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌ

ΠœΠΎΠ±ΠΈΠ»ΡŒΠ½Ρ‹Π΅ устройства

БпСцифичСскиС ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ для ΠΌΠΎΠ±ΠΈΠ»ΡŒΠ½Ρ‹Ρ… ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌ:

  1. УмСньшСниС количСства Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² отрисовки β€” агрСссивный Π±Π°Ρ‚Ρ‡ΠΈΠ½Π³
  2. ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€ΠΎΠ² β€” ΡƒΠΏΡ€ΠΎΡ‰Π΅Π½ΠΈΠ΅ вычислСний, мСньшС тСкстурных Π²Ρ‹Π±ΠΎΡ€ΠΎΠΊ
  3. Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ энСргопотрСблСниСм β€” Π°Π΄Π°ΠΏΡ‚ΠΈΠ²Π½ΠΎΠ΅ качСство Π³Ρ€Π°Ρ„ΠΈΠΊΠΈ
// БистСма Π°Π΄Π°ΠΏΡ‚ΠΈΠ²Π½ΠΎΠ³ΠΎ качСства для ΠΌΠΎΠ±ΠΈΠ»ΡŒΠ½Ρ‹Ρ… устройств
class AdaptiveQualitySystem : public Wudgine::ECS::System {
public:
    void Update(float deltaTime) override {
        // Π˜Π·ΠΌΠ΅Ρ€Π΅Π½ΠΈΠ΅ FPS
        m_FrameTimeAccumulator += deltaTime;
        m_FrameCount++;
        
        if (m_FrameTimeAccumulator >= 1.0f) {
            float averageFPS = m_FrameCount / m_FrameTimeAccumulator;
            m_FrameTimeAccumulator = 0.0f;
            m_FrameCount = 0;
            
            // Адаптация качСства Π² зависимости ΠΎΡ‚ FPS
            if (averageFPS < 30.0f) {
                DecreaseQuality();
            } else if (averageFPS > 55.0f && m_QualityLevel < m_MaxQualityLevel) {
                IncreaseQuality();
            }
        }
    }
    
private:
    float m_FrameTimeAccumulator = 0.0f;
    int m_FrameCount = 0;
    int m_QualityLevel = 2;
    int m_MaxQualityLevel = 4;
    
    void DecreaseQuality() {
        if (m_QualityLevel > 0) {
            m_QualityLevel--;
            ApplyQualitySettings();
        }
    }
    
    void IncreaseQuality() {
        if (m_QualityLevel < m_MaxQualityLevel) {
            m_QualityLevel++;
            ApplyQualitySettings();
        }
    }
    
    void ApplyQualitySettings() {
        // ΠŸΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ настроСк качСства
        auto& renderer = GetWorld()->GetSystem<RenderSystem>();
        
        switch (m_QualityLevel) {
            case 0: // ΠžΡ‡Π΅Π½ΡŒ Π½ΠΈΠ·ΠΊΠΎΠ΅
                renderer.SetShadowQuality(0);
                renderer.SetTextureQuality(0.25f);
                renderer.SetMaxLights(4);
                renderer.SetPostProcessingEnabled(false);
                break;
            case 1: // НизкоС
                renderer.SetShadowQuality(1);
                renderer.SetTextureQuality(0.5f);
                renderer.SetMaxLights(8);
                renderer.SetPostProcessingEnabled(false);
                break;
            // И Ρ‚Π°ΠΊ Π΄Π°Π»Π΅Π΅ для Π΄Ρ€ΡƒΠ³ΠΈΡ… ΡƒΡ€ΠΎΠ²Π½Π΅ΠΉ качСства
        }
    }
};

Консоли

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ для ΠΈΠ³Ρ€ΠΎΠ²Ρ‹Ρ… консолСй:

  1. ИспользованиС спСцифичных API β€” оптимизация ΠΏΠΎΠ΄ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠ΅ ΠΆΠ΅Π»Π΅Π·ΠΎ
  2. АсинхронныС вычислСния β€” использованиС асинхронных вычислСний GPU
  3. ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ памяти β€” ΡƒΡ‡Π΅Ρ‚ особСнностСй памяти консолСй

ПК

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ для ПК:

  1. ΠœΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΡƒΠ΅ΠΌΠΎΡΡ‚ΡŒ β€” настройки для Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΉ
  2. ΠœΠ½ΠΎΠ³ΠΎΠΏΠΎΡ‚ΠΎΡ‡Π½ΠΎΡΡ‚ΡŒ β€” эффСктивноС использованиС многоядСрных процСссоров
  3. ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… API β€” DirectX, Vulkan, OpenGL

Π›ΡƒΡ‡ΡˆΠΈΠ΅ ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠΈ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ

Π˜Π·ΠΌΠ΅Ρ€ΡΠΉΡ‚Π΅ ΠΏΠ΅Ρ€Π΅Π΄ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠ΅ΠΉ

ВсСгда ΠΏΡ€ΠΎΡ„ΠΈΠ»ΠΈΡ€ΡƒΠΉΡ‚Π΅ ΠΊΠΎΠ΄ ΠΏΠ΅Ρ€Π΅Π΄ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠ΅ΠΉ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²Ρ‹ΡΠ²ΠΈΡ‚ΡŒ Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Π΅ ΡƒΠ·ΠΊΠΈΠ΅ мСста:

void OptimizeGame() {
    // ΠŸΡ€ΠΎΡ„ΠΈΠ»ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΏΠ΅Ρ€Π΅Π΄ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠ΅ΠΉ
    Wudgine::Core::Profiler::BeginSession("Before Optimization");
    RunBenchmark();
    Wudgine::Core::Profiler::EndSession();
    
    // Анализ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ² ΠΈ выявлСниС ΡƒΠ·ΠΊΠΈΡ… мСст
    auto hotspots = Wudgine::Core::Profiler::GetHotspots();
    
    // ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ выявлСнных ΡƒΠ·ΠΊΠΈΡ… мСст
    // ...
    
    // ΠŸΡ€ΠΎΡ„ΠΈΠ»ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ послС ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ для ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ²
    Wudgine::Core::Profiler::BeginSession("After Optimization");
    RunBenchmark();
    Wudgine::Core::Profiler::EndSession();
    
    // Π‘Ρ€Π°Π²Π½Π΅Π½ΠΈΠ΅ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ²
    CompareProfilingResults("Before Optimization", "After Optimization");
}

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΡƒΠΉΡ‚Π΅ Π΄Π°Π½Π½Ρ‹Π΅, Π° Π½Π΅ ΠΊΠΎΠ΄

Часто оптимизация структур Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ ΠΈΡ… размСщСния Π² памяти Π΄Π°Π΅Ρ‚ больший эффСкт, Ρ‡Π΅ΠΌ оптимизация Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠΎΠ²:

// ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ структуры Π΄Π°Π½Π½Ρ‹Ρ… для Π»ΡƒΡ‡ΡˆΠ΅ΠΉ Π»ΠΎΠΊΠ°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ кэша
struct OptimizedEntityData {
    // Π“Ρ€ΡƒΠΏΠΏΠΈΡ€ΠΎΠ²ΠΊΠ° часто ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Ρ… вмСстС Π΄Π°Π½Π½Ρ‹Ρ…
    struct TransformData {
        Wudgine::Math::Vector3 position;
        Wudgine::Math::Quaternion rotation;
        Wudgine::Math::Vector3 scale;
    };
    
    struct RenderData {
        Wudgine::Resources::MeshHandle mesh;
        Wudgine::Resources::MaterialHandle material;
        bool visible;
    };
    
    // ΠœΠ°ΡΡΠΈΠ²Ρ‹ структур вмСсто структур массивов для Π»ΡƒΡ‡ΡˆΠ΅ΠΉ Π»ΠΎΠΊΠ°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ кэша
    std::vector<TransformData> transforms;
    std::vector<RenderData> renderData;
    
    // ΠœΠ΅Ρ‚ΠΎΠ΄Ρ‹ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ
};

Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΈΠ½ΠΊΡ€Π΅ΠΌΠ΅Π½Ρ‚Π°Π»ΡŒΠ½Ρ‹Π΅ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΡƒΠΉΡ‚Π΅ постСпСнно, измСряя Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ измСнСния:

void IncrementalOptimization() {
    // Π˜ΡΡ…ΠΎΠ΄Π½ΠΎΠ΅ ΠΏΡ€ΠΎΡ„ΠΈΠ»ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅
    float baselinePerformance = MeasurePerformance();
    
    // ΠŸΠ΅Ρ€Π²Π°Ρ оптимизация
    OptimizeRenderingPipeline();
    float performance1 = MeasurePerformance();
    LogPerformanceImprovement("Rendering Pipeline", baselinePerformance, performance1);
    
    // Вторая оптимизация
    OptimizePhysics();
    float performance2 = MeasurePerformance();
    LogPerformanceImprovement("Physics", performance1, performance2);
    
    // Π’Ρ€Π΅Ρ‚ΡŒΡ оптимизация
    OptimizeMemoryUsage();
    float performance3 = MeasurePerformance();
    LogPerformanceImprovement("Memory Usage", performance2, performance3);
    
    // ΠžΠ±Ρ‰Π΅Π΅ ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΠ΅
    LogPerformanceImprovement("Total", baselinePerformance, performance3);
}

Π§Ρ‚ΠΎ дальшС?

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ β€” это ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΉ процСсс. РСгулярно ΠΏΡ€ΠΎΡ„ΠΈΠ»ΠΈΡ€ΡƒΠΉΡ‚Π΅ Π²Π°ΡˆΡƒ ΠΈΠ³Ρ€Ρƒ Π½Π° Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… устройствах ΠΈ постоянно ΠΈΡ‰ΠΈΡ‚Π΅ возмоТности для ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΡ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ.

Wudgine β€’ Β© 2025