Freya¶
A Vulkan-based rendering engine powered by Skirnir for dependency injection.
Features¶
- Vulkan-backed rendering - Modern graphics API with high performance
- Deferred rendering - G-buffer path with SSAO, TAA, bloom, and HDR composite
- Composable frame stages - Insert or replace steps in
Renderer::EndScene - Feature flags - Toggle SSAO / TAA / Bloom and set
shaderRootvia options - Custom render targets - Offscreen composite via
Renderer::SetViewportTarget/ClearOutputTarget, with opaque Vulkan/SDL handles (Renderer::GetImGuiNativeHandles,GetViewportImage) for hosting the scene in an application-level ImGui viewport; quality and vsync viaFreyaOptions - ImGui seam -
Renderer::BeginUI/EndUIopen the swapchain UI pass so apps draw Dear ImGui over an offscreen viewport without leakingvk::/SDL types into public headers - Asset management - Meshes, textures (file or memory), and PBR materials
- Skinned animation - AnimGraph, bake, CPU or GPU skin palettes, LOD (see Animation)
- Event system - Flexible pub/sub event handling for window, keyboard, mouse, and gamepad
- Builder pattern - Fluent API plus
FreyaExtensionconfigure hooks - Skirnir integration - IoC container for dependency injection
Headers¶
See API boundary and Flexibility.
Dependencies¶
- Vulkan SDK
- SDL3
- GLM
- Assimp (for 3D model loading)
- Skirnir (IoC Container)
Quick Start¶
#include <Freya/Freya.hpp>
class MainApp final : public fra::AbstractApplication
{
public:
explicit MainApp(const skr::Arc<skr::ServiceProvider>& serviceProvider)
: AbstractApplication(serviceProvider)
{
mMeshPool = serviceProvider->GetService<fra::MeshPool>();
mTexturePool = serviceProvider->GetService<fra::TexturePool>();
mMaterialPool = serviceProvider->GetService<fra::MaterialPool>();
}
void StartUp() override
{
mRenderer->ClearProjections();
// Initialize your assets here
}
void Update() override
{
mRenderer->BeginFrame();
// Render your scene here
mRenderer->EndFrame();
}
};
int main(int argc, const char** argv)
{
const auto app =
skr::ApplicationBuilder()
.WithExtension<fra::FreyaExtension>([](fra::FreyaExtension& freya) {
freya.WithOptions([](fra::FreyaOptionsBuilder& freyaOptions) {
freyaOptions.SetTitle("My App")
.SetWidth(1920)
.SetHeight(1080)
.SetVSync(false)
.SetSampleCount(8);
});
})
.Build<MainApp>();
app->Run();
return 0;
}
Project Structure¶
Freya/
├── include/Freya/ # Public headers (Freya.hpp, glm/Skirnir types)
├── src/Freya/ # .cpp + internal Vulkan headers + Vendor/
├── Examples/ # Example applications
├── Shaders/ # GLSL/Vulkan shaders
└── docs/ # Documentation
Configuration¶
Configure Freya using the FreyaOptionsBuilder:
freya.WithOptions([](fra::FreyaOptionsBuilder& freyaOptions) {
freyaOptions.SetTitle("My Window")
.SetWidth(1920)
.SetHeight(1080)
.SetVSync(true)
.SetFullscreen(false)
.SetSampleCount(4)
.SetDrawDistance(1000.0f);
});
Available Options¶
| Option | Type | Default | Description |
|---|---|---|---|
title | std::string | "Freya Window" | Window title |
width | std::uint32_t | 800 | Window width |
height | std::uint32_t | 600 | Window height |
vSync | bool | true | Vertical synchronization |
fullscreen | bool | true | Fullscreen mode |
sampleCount | std::uint32_t | 1 | Retained for compatibility (scene path is single-sample) |
frameCount | std::uint32_t | 4 | Number of frames in flight |
drawDistance | float | 1000.0f | Render distance |
maxLights | std::uint32_t | 64 | Max analytical lights (kMaxLights) |
iblIntensity | float | 0.7f | Image-based lighting scale |
exposure | float | 0.7f | HDR exposure before ACES tonemap |
ambientIntensity | float | 0.03f | Flat ambient fill |
environmentMapPath | std::string | ./Resources/Environments/studio_small_09_4k.hdr | Radiance .hdr (empty = procedural sky) |
shadowCascadeCount | std::uint32_t | 4 | Directional CSM cascade count (1–4) |
shadowMapResolution | std::uint32_t | 2048 | Shadow map resolution (square) |
shadowBias | float | 0.002f | Depth bias when sampling shadows |
maxSpotShadows | std::uint32_t | 4 | Max concurrent spot shadow maps |
maxPointShadows | std::uint32_t | 2 | Max concurrent point cube shadows |
shadowSampleCount | std::uint32_t | 16 | Soft-shadow Poisson taps (1–16) |
shaderRoot | std::string | ./Resources/Shaders | SPIR-V directory root |
enableSsao | bool | true | Run SSAO compute pass |
enableTaa | bool | true | Run TAA resolve + jitter |
enableBloom | bool | true | Run bloom extract/blur |
ssaoResolutionDivisor | uint | 2 | SSAO res = full / N (1,2,4) |
taaCurrentWeight | float | 0.1 | TAA blend toward current |
bloomStrength | float | 0.8 | Bloom mix in composite |
Use SetShadowQuality / SetSsaoQuality / SetTaaQuality / SetBloomQuality (Low–Ultra) for presets; runtime mirrors on Renderer.
Use FreyaOptionsBuilder::SetShadowQuality(Low|Medium|High|Ultra) to set resolution, cascades, spot/point slots, and tap count together.
Services¶
Freya provides the following services via Skirnir's service provider:
| Service | Type | Description |
|---|---|---|
Window | skr::Arc<Window> | Window management |
Renderer | skr::Arc<Renderer> | Main renderer |
EventManager | skr::Arc<EventManager> | Event system |
MeshPool | skr::Arc<MeshPool> | Mesh asset management |
TexturePool | skr::Arc<TexturePool> | Texture asset management |
MaterialPool | skr::Arc<MaterialPool> | Material asset management |
LightService | skr::Arc<LightService> | Point / directional / spot / area lights |
IBLService | skr::Arc<IBLService> | Environment / irradiance / BRDF LUT |
ShadowPass | skr::Arc<ShadowPass> | CSM / spot / point shadow maps |