Performant open-source OpenXR, Vulkan, ECS, C++. A boilerplate -> framework -> mini "game engine" to quickly make an actual playable modern royalty-free XR game.
Demystifies ECS / Memory Management, Single Pass Rendering, XR Input, and XR gamedev fundamentals, on top of @janhsimon's excellent timesaving khronos setup openxr-vulkan-example.
[Note: you can leave github comments over on my blog post version 😉]
snowglobe_openxr_vulkan_framework_30crf_800x800_github.webm
Demo video, summer 2025. (There's also a youtube hq 1600x1600/1440p 60fps version.)
*Trey Parker voice* Vulkan has a rich body of work, and many strengths as a people; but lack hoo-man compatibility. I've managed to translate their stack, for hoo-mans, whose lifetimes may otherwise be too short to first decipher the khronos lunar manuals for hope of achieving even the most basic useful contact.
It didn't help that they don't want to touch Single-Pass rendering (the performant & industry-standard linchpin of rendering).
In any case, thanks to open-source you can now build something pretty good the right way, without worrying about mighty morphing license agreements or wetting the beaks of people with golden parachutes.
-
See Build-ProjectSetup.Readme.md or just be lazy and run the windows build in
./out/(or the github Release). -
"Recommended Specs and Minimum Requirements": The scene runs on a RTX 4070 mobile at 90FPS (the refresh rate of the headset) with 8 (animated) tube lights and 2 directional lights, and a lot of transparent objects overdraw. It also runs on a RTX 2060 mobile with a bit of lag spikes if you have too much overdraw right on your face.
(sections ordered from high-level to low-level)
- Rotating and (accelerated) Panning of the scene by grabbing with both hands, retreating into a non-euclideanly warped pocket dimension (pushing the world away from you non-linearly) and seeing a "tunnelvision" portal-style chaperone. Highest effectiveness and lowest sickness (carefully tweaked and tested across dozens of different people).
- Uses state machines for movement and for visuals. Supports animated teleportation with targets.

- Mechanics system based on a list of
GameBehaviours set up as FSMs. - Each behaviour is Created (with its own required references), Updated (with frame & input data etc), and Destroyed.
- Mechanics for locomotion, hands, XR Input testing, world objects.
- Any
GameComponenthas one or moreGameEntityparents and manual or automatic cleanup (and preventing dangling components when all owners are freed). But there's no parenting between different game entities / objects, so manipulate groups of matrixes yourself.TODO:add a parenting system that processes the chain of Transform matrixes.
- There's support for running jobs on
Boundscomponents (generated at model load time), with proper functions for AABB intersection or enclosure tests, plane tests, rectangular selection (even at non-Axis-Aligned angles) / frustum casting, raycasting. - There's a concept of ground in the locomotion system.
- But
TODO:no actual Physics library added.
- *crickets*
TODO:just add it via full/extended gltf support. TODO:find something open-source for: IK, gpu-skinning, and LoDs.
- *crickets*
TODO:add Audio component, and threaded spatial sound library with audio queueing.
- *crickets*
TODO:vector or sdf text, and just textures. Then use previously made ui code. TODO:main menu, in-game hands inventory- (I'm certainly not implementing a scene-graph management system (game editor))
- The objects and memory is set up in a spanned ECS manner but
TODO:no job system / threading example (there's only sequentially updatedGameBehaviours / state machines on the main thread). TODO:add a simple chunking concept, run jobs in parallel on chunks.
- Everything is set in generic memory-span pools, by type. You set up a game world with maximum allocated memory for each pool, then during gameplay you can request to use a free object, or mark a used one as free and reusable. There's no need for defragmenting, or swap-and-pop (would be slower in average-case) ("ted talk" in
GameDataPool.h). - Enities and components are based on
GameDataId(serving as a weak reference):[globalUIDSeed][index][version]and a top-level[typeIndex]for convenience. - Everything is easy to request and keep track of through various means, even by name in hash maps for light scripting purposes.
- Cleanup is either manual (and cache coherent) or automated via (cache-missing) awareness of component dependencies.
GameEntityandGameEntityObjectGameComponent:Material,Model,Transform,Bounds,Light.- Properties:
isVisible,isEnabled,name, some events etc. PlayerObjects {GameEntityObjects,PlayerActiveStates}.Materials {Shader, Descriptor-setUniformData, instancing, optional/sharedPipeline(for e.g blend ops)}
- Implemented the most high quality e.g. Disney BRDF lighting equations for diffuse, specular and MRP based (Most Representative Point) shape lights. There's a blog post on correct tube lights:

TODO:does not include clearcoat.TODO:does not include subsurface scattering,TODO:does not include shadows,TODO:no per-pixel transparent object sorting,- ^, ^^, ^^^: but, I'll someday add in raytracing into some form of nanite clumps or other semi-volumetric discrete mesh data, instead of going through the legacy shading/sorting timesinks again.
- Per-material, per-model, per-pipeline properties. Easily create a material e.g. transparent, doublesided; add new
shaderswith all the static and dynamic uniform data you need, instance geometry etc. - Render pipeline knows if you modified any default properties and creates pipelines from unique materials. Tries its best to batch per unique material and per model to minimise GPU-CPU communication, and has instancing, but it's not Indirect Rendering.
- Expanded, added to, and explained Khronos' & JanhSimon's
Headset,Context,Renderer/Pipelineetc, and the easily misleading & hard to customize khronos vulkan <-> openxr implementation. Especially regarding multipass vs singlepass & multiview, and what it takes if you want to use your own renderer or a diffrent API likewebgpu. (look for"// [tdbe]")
- A 'proper' universal xr input class, supporting (probably) all controllers/headsets, with customizable binding paths and action sets.
- Nicely accessible data through
InputDataandInputHaptics, including matrixes and other tracked XR positional data. - Poses for controllers and for head.
- Actions (buttons, sticks, triggers, pressure, proximity etc).
- User presence / headset activity state.
- Haptic feedback output.
- Exposes action state data (e.g.
lastChangeTime,isActive,changedSinceLastSync)
- Utils and math for XR, input, general gamedev.
- Debugging.
TODO:Bring in gizmos, e.g. debug lines, wireframes for lights etc.
- Game world load, setup, updates & render loops, unload and exit. TypicalRunLogSample.md
| Asset | Title | Author | License |
|---|---|---|---|
models/SuzanneHighQuality20k.obj |
Suzanne | Blender (but mesh smoothed and subdivided by tdbe) | GNU GPL 2+ |
models/SudaBeam.obj |
SudaBeam | tdbe, a simplified version of Suda 51's parody of a light saber | GNU GPL 3+ |
models/Squid_Happy_Grumpy.obj |
Happy Grumpy Squid | tdbe | CC BY 4.0 |
models/ground_displaced_*.obj |
demo ground | tdbe | CC BY 4.0 |
models/icosphere_*.obj |
utility (ico)spheres | tdbe | CC BY 4.0 |
models/quad_*.obj |
utility quad | tdbe | CC BY 4.0 |
models/capsule_*.obj |
utility capsule | tdbe | CC BY 4.0 |
models/text_*.obj |
various texts | tdbe | CC BY 4.0 |
⠀
⠀
This project demonstrates how you can write your own VR application using OpenXR 1.1 and Vulkan 1.3. These are its main features:
- Basic rendering of example scene to the headset and into a resizeable mirror view on your desktop monitor.
- Focus on easy to read and understand C++ without smart pointers, inheritance, templates, etc.
- Usage of the Vulkan
multiviewextension for extra performance. - Warning-free code base spread over a small handful of classes.
- No OpenXR or Vulkan validation errors or warnings.
- CMake project setup for easy building.
Integrating both OpenXR and Vulkan yourself can be a daunting and painfully time-consuming task. Both APIs are very verbose and require the correct handling of countless minute details. This is why there are two main use cases where this project comes in handy:
- Fork the repository and use it as a starting point to save yourself weeks of tedious integration work before you get to the juicy bits of VR development.
- Reference the code while writing your own implementation from scratch, to help you out if you are stuck with a problem, or simply for inspiration.
- Download the latest release or build the project yourself with the steps below.
- Make sure your headset is connected to your computer.
- Run the program!
- Install the Vulkan SDK version 1.3 or newer.
- Install CMake version 3.1 or newer.
- Clone the repository and generate build files.
- Build!
The repository includes binaries for all dependencies except the Vulkan SDK on Windows. These can be found in the external folder. You will have to build these dependencies yourself on other platforms. Use the address and version tag or commit hash in version.txt to ensure compatibility. Please don't hesitate to open a pull request if you have built dependencies for previously unsupported platforms.
| Asset | Title | Author | License |
|---|---|---|---|
models/Beetle.obj |
Car Scene | toivo | CC BY 4.0 |
models/Bike.obj |
Sci-fi Hover Bike 04 | taktelon | CC BY 4.0 |
models/Car.obj |
GAZ-21 | Ashkelon | CC BY 4.0 |
models/Hand.obj |
Hand Anatomy Reference | Ant B-D | CC BY 4.0 |
models/Ruins.obj |
Ancient Ruins Pack | Toni García Vilche | CC BY 4.0 |
