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
- ΠΠΎΡΡΡΠΈΠ΅ ΠΏΡΡΠΈ (Hot Paths) β ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡ ΡΡΠ½ΠΊΡΠΈΠΉ, Π·Π°Π½ΠΈΠΌΠ°ΡΡΠΈΡ Π½Π°ΠΈΠ±ΠΎΠ»ΡΡΠ΅Π΅ Π²ΡΠ΅ΠΌΡ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ
- Π§Π°ΡΡΠΎΡΠ° Π²ΡΠ·ΠΎΠ²ΠΎΠ² β Π°Π½Π°Π»ΠΈΠ· ΡΡΠ½ΠΊΡΠΈΠΉ, Π²ΡΠ·ΡΠ²Π°Π΅ΠΌΡΡ ΡΠ»ΠΈΡΠΊΠΎΠΌ ΡΠ°ΡΡΠΎ
- ΠΡΠ΅ΠΌΡ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ β ΠΈΠ·ΠΌΠ΅ΡΠ΅Π½ΠΈΠ΅ Π²ΡΠ΅ΠΌΠ΅Π½ΠΈ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ ΠΎΡΠ΄Π΅Π»ΡΠ½ΡΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΉ
ΠΠ½Π°Π»ΠΈΠ· ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ GPU
- GPU Profiler β Π°Π½Π°Π»ΠΈΠ· Π²ΡΠ΅ΠΌΠ΅Π½ΠΈ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ ΡΠ΅ΠΉΠ΄Π΅ΡΠΎΠ² ΠΈ ΡΠ΅Π½Π΄Π΅ΡΠΈΠ½Π³Π°
- Π‘ΡΠ΅ΡΡΠΈΠΊΠΈ ΠΎΡΡΠΈΡΠΎΠ²ΠΊΠΈ β ΠΌΠΎΠ½ΠΈΡΠΎΡΠΈΠ½Π³ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²Π° Π²ΡΠ·ΠΎΠ²ΠΎΠ² ΠΎΡΡΠΈΡΠΎΠ²ΠΊΠΈ ΠΈ ΡΡΠ΅ΡΠ³ΠΎΠ»ΡΠ½ΠΈΠΊΠΎΠ²
- ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΏΠ°ΠΌΡΡΠΈ 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);
}
}
};
ΠΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΡ ΡΠ΅ΠΉΠ΄Π΅ΡΠΎΠ²
Π‘ΠΎΠ²Π΅ΡΡ ΠΏΠΎ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ ΡΠ΅ΠΉΠ΄Π΅ΡΠΎΠ²:
- ΠΠΈΠ½ΠΈΠΌΠΈΠ·Π°ΡΠΈΡ ΡΠ΅ΠΊΡΡΡΡΠ½ΡΡ Π²ΡΠ±ΠΎΡΠΎΠΊ β ΠΎΠ±ΡΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠ΅ ΡΠ΅ΠΊΡΡΡΡ Π² Π°ΡΠ»Π°ΡΡ
- Π£ΠΏΡΠΎΡΠ΅Π½ΠΈΠ΅ Π²ΡΡΠΈΡΠ»Π΅Π½ΠΈΠΉ β ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΏΡΠ΅Π΄Π²Π°ΡΠΈΡΠ΅Π»ΡΠ½ΡΡ Π²ΡΡΠΈΡΠ»Π΅Π½ΠΈΠΉ ΠΈ LUT
- Π£ΡΠ»ΠΎΠ²Π½ΡΠ΅ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΡ β ΠΌΠΈΠ½ΠΈΠΌΠΈΠ·Π°ΡΠΈΡ Π²Π΅ΡΠ²Π»Π΅Π½ΠΈΠΉ Π² ΡΠ΅ΠΉΠ΄Π΅ΡΠ°Ρ
ΠΡΠΈΠΌΠ΅Ρ ΠΎΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ ΡΠ΅ΠΉΠ΄Π΅ΡΠ°:
// Π€ΡΠ°Π³ΠΌΠ΅Π½ΡΠ½ΡΠΉ ΡΠ΅ΠΉΠ΄Π΅Ρ Ρ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠ΅ΠΉ
#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);
}
};
ΠΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΡ Π΄Π»Ρ ΡΠ°Π·Π»ΠΈΡΠ½ΡΡ ΠΏΠ»Π°ΡΡΠΎΡΠΌ
ΠΠΎΠ±ΠΈΠ»ΡΠ½ΡΠ΅ ΡΡΡΡΠΎΠΉΡΡΠ²Π°
Π‘ΠΏΠ΅ΡΠΈΡΠΈΡΠ΅ΡΠΊΠΈΠ΅ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ Π΄Π»Ρ ΠΌΠΎΠ±ΠΈΠ»ΡΠ½ΡΡ ΠΏΠ»Π°ΡΡΠΎΡΠΌ:
- Π£ΠΌΠ΅Π½ΡΡΠ΅Π½ΠΈΠ΅ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²Π° Π²ΡΠ·ΠΎΠ²ΠΎΠ² ΠΎΡΡΠΈΡΠΎΠ²ΠΊΠΈ β Π°Π³ΡΠ΅ΡΡΠΈΠ²Π½ΡΠΉ Π±Π°ΡΡΠΈΠ½Π³
- ΠΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΡ ΡΠ΅ΠΉΠ΄Π΅ΡΠΎΠ² β ΡΠΏΡΠΎΡΠ΅Π½ΠΈΠ΅ Π²ΡΡΠΈΡΠ»Π΅Π½ΠΈΠΉ, ΠΌΠ΅Π½ΡΡΠ΅ ΡΠ΅ΠΊΡΡΡΡΠ½ΡΡ Π²ΡΠ±ΠΎΡΠΎΠΊ
- Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΡΠ½Π΅ΡΠ³ΠΎΠΏΠΎΡΡΠ΅Π±Π»Π΅Π½ΠΈΠ΅ΠΌ β Π°Π΄Π°ΠΏΡΠΈΠ²Π½ΠΎΠ΅ ΠΊΠ°ΡΠ΅ΡΡΠ²ΠΎ Π³ΡΠ°ΡΠΈΠΊΠΈ
// Π‘ΠΈΡΡΠ΅ΠΌΠ° Π°Π΄Π°ΠΏΡΠΈΠ²Π½ΠΎΠ³ΠΎ ΠΊΠ°ΡΠ΅ΡΡΠ²Π° Π΄Π»Ρ ΠΌΠΎΠ±ΠΈΠ»ΡΠ½ΡΡ
ΡΡΡΡΠΎΠΉΡΡΠ²
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;
// Π ΡΠ°ΠΊ Π΄Π°Π»Π΅Π΅ Π΄Π»Ρ Π΄ΡΡΠ³ΠΈΡ
ΡΡΠΎΠ²Π½Π΅ΠΉ ΠΊΠ°ΡΠ΅ΡΡΠ²Π°
}
}
};
ΠΠΎΠ½ΡΠΎΠ»ΠΈ
ΠΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ Π΄Π»Ρ ΠΈΠ³ΡΠΎΠ²ΡΡ ΠΊΠΎΠ½ΡΠΎΠ»Π΅ΠΉ:
- ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠΏΠ΅ΡΠΈΡΠΈΡΠ½ΡΡ API β ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΡ ΠΏΠΎΠ΄ ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΠΎΠ΅ ΠΆΠ΅Π»Π΅Π·ΠΎ
- ΠΡΠΈΠ½Ρ ΡΠΎΠ½Π½ΡΠ΅ Π²ΡΡΠΈΡΠ»Π΅Π½ΠΈΡ β ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ Π°ΡΠΈΠ½Ρ ΡΠΎΠ½Π½ΡΡ Π²ΡΡΠΈΡΠ»Π΅Π½ΠΈΠΉ GPU
- ΠΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΡ ΠΏΠ°ΠΌΡΡΠΈ β ΡΡΠ΅Ρ ΠΎΡΠΎΠ±Π΅Π½Π½ΠΎΡΡΠ΅ΠΉ ΠΏΠ°ΠΌΡΡΠΈ ΠΊΠΎΠ½ΡΠΎΠ»Π΅ΠΉ
ΠΠ
ΠΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ Π΄Π»Ρ ΠΠ:
- ΠΠ°ΡΡΡΠ°Π±ΠΈΡΡΠ΅ΠΌΠΎΡΡΡ β Π½Π°ΡΡΡΠΎΠΉΠΊΠΈ Π΄Π»Ρ ΡΠ°Π·Π»ΠΈΡΠ½ΡΡ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΠΉ
- ΠΠ½ΠΎΠ³ΠΎΠΏΠΎΡΠΎΡΠ½ΠΎΡΡΡ β ΡΡΡΠ΅ΠΊΡΠΈΠ²Π½ΠΎΠ΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΌΠ½ΠΎΠ³ΠΎΡΠ΄Π΅ΡΠ½ΡΡ ΠΏΡΠΎΡΠ΅ΡΡΠΎΡΠΎΠ²
- ΠΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠ° ΡΠ°Π·Π»ΠΈΡΠ½ΡΡ 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);
}
Π§ΡΠΎ Π΄Π°Π»ΡΡΠ΅?
- ΠΠ·ΡΡΠΈΡΠ΅ ΡΠ΅ΡΠ΅Π²ΠΎΠ΅ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ Π΄Π»Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΡ ΠΈΠ³Ρ
- ΠΠ·Π½Π°ΠΊΠΎΠΌΡΡΠ΅ΡΡ Ρ ΡΠ°ΡΡΠΈΡΠ΅Π½Π½ΠΎΠΉ ΡΠ°Π±ΠΎΡΠΎΠΉ Ρ ΡΠ΅ΡΡΡΡΠ°ΠΌΠΈ Π΄Π»Ρ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ Π·Π°Π³ΡΡΠ·ΠΊΠΈ ΠΈ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΠΈΠ³ΡΠΎΠ²ΡΠΌΠΈ ΡΠ΅ΡΡΡΡΠ°ΠΌΠΈ
- ΠΡΡΠ»Π΅Π΄ΡΠΉΡΠ΅ ΠΎΡΠ»Π°Π΄ΠΊΡ ΠΈ ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ Π΄Π»Ρ Π±ΠΎΠ»Π΅Π΅ Π³Π»ΡΠ±ΠΎΠΊΠΎΠ³ΠΎ Π°Π½Π°Π»ΠΈΠ·Π° ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ
ΠΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΡ β ΡΡΠΎ ΠΈΡΠ΅ΡΠ°ΡΠΈΠ²Π½ΡΠΉ ΠΏΡΠΎΡΠ΅ΡΡ. Π Π΅Π³ΡΠ»ΡΡΠ½ΠΎ ΠΏΡΠΎΡΠΈΠ»ΠΈΡΡΠΉΡΠ΅ Π²Π°ΡΡ ΠΈΠ³ΡΡ Π½Π° ΡΠ°Π·Π»ΠΈΡΠ½ΡΡ ΡΡΡΡΠΎΠΉΡΡΠ²Π°Ρ ΠΈ ΠΏΠΎΡΡΠΎΡΠ½Π½ΠΎ ΠΈΡΠΈΡΠ΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ Π΄Π»Ρ ΡΠ»ΡΡΡΠ΅Π½ΠΈΡ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ.