A custom 3D action RPG engine built in Odin — cel shaded, procedural-first, Blender-native.
Thor is an attempt to build the game engine I've always wanted: one purpose-built for the kind of games I love. Think Skyrim's sense of open-world exploration fused with the tight, punishing combat of FromSoftware's Souls series — rendered in a striking cel shaded style and powered by procedural systems at every level.
The guiding philosophy is procedural-first. Rather than hand-authoring content, the engine is designed from the ground up to generate it:
- Procedural animation — inverse kinematics, locomotion blending, and foot placement that responds to the world in real time, not canned clips
- Procedural textures — materials generated at runtime, not baked ahead of time
- Procedural terrain — landscapes that emerge from noise and rules rather than heightmap painting
- Procedural enemies and objects — entity variety without exponential asset counts
The other non-negotiable: Blender as a first-class citizen. The engine's coordinate system matches Blender's (Z-up, right-handed, X=right, Y=forward). The long-term goal is a workflow where Blender serves as the live level and asset editor — not a separate tool you round-trip through, but an integrated part of the development loop.
What exists today:
- Language: Odin (nightly build)
- Graphics backend: Vulkan 1.3 — instance, physical device, logical device, swapchain, image views, render pass, framebuffers, graphics pipeline, double-buffered frame loop with semaphore/fence synchronization
- Asset import:
.glbmesh loading for a first Blender-to-engine path — extracts primitive/material structure for static meshes plus skinning data and animation clips from the sample asset - Shaders: GLSL compiled to SPIR-V via glslc at build time
- Windowing & input: SDL2 — keyboard, mouse, and window events (resize, close)
- Game loop: Fixed 60 Hz timestep with accumulator pattern, variable render tick, delta cap at 0.25s
- ECS foundation:
Entity(distinct u64) +Worldtype — spawn/destroy infrastructure, no component storage yet - Rendering: Imported mesh rendering from
examples/assets/with a first cel-shaded forward pass and inverted-hull outlines. Static meshes now draw per imported primitive/material, and examples can override cel settings in code. Dynamic viewport/scissor — survives window resize without pipeline recreation. - Animation playback:
examples/animation_viewerevaluates the sample GLB's skeletal clips on the CPU, skins the mesh every frame, and provides an in-window searchable clip picker with Play and Loop controls.
Honest status: first Blender-exported mesh is on the render path with a stylized first-pass look. Material import, scene traversal, coordinate-bridge cleanup, and richer lighting/shadows are still ahead.
Rough milestone breakdown of what comes next, roughly in order:
| Milestone | Focus |
|---|---|
.glb import path |
|
| M4 | Blender coordinate bridge — Z-up import with no surprises |
| M5 | Material import + richer cel shading render path |
| M6 | ECS component storage + basic transform/render components |
| M7 | Skeletal animation system |
| M8 | IK / reverse IK for procedural locomotion |
| M9 | Procedural texture generation |
| M10 | Procedural terrain |
| M11 | Entity/AI systems — souls-style combat foundation |
| M12 | Blender plugin / live-link for in-engine editing |
Blender integration is a first-class design goal, not an afterthought.
Coordinate system: The engine uses Blender's native coordinate system — X=right, Y=forward, Z=up (right-handed). Assets exported from Blender should require no axis remapping.
Import workflow goal: export from Blender → drop asset in project → it works. Hot-reload when files change.
Long-term goal: Blender as the level editor. Rather than building a proprietary editor, the plan is to drive Blender via a plugin that syncs scene state with the running engine in real time — place objects in Blender, see them in the engine immediately.
| Layer | Tech |
|---|---|
| Language | Odin |
| Graphics API | Vulkan 1.3 |
| Windowing / Input | SDL2 |
| 3D authoring | Blender |
| Build | bash + Odin compiler (nightly) |
Requires:
- Odin nightly compiler
- Vulkan-capable GPU with up-to-date drivers
- SDL2 installed
- glslc (from the Vulkan SDK) on your PATH
# Build example apps (debug mode; validation enabled when installed)
bash build.sh
# Run the desktop examples
./bin/mesh_viewer
./bin/animation_viewer
# Run headless tests + smoke example
bash test.shPress ESC to quit.
examples/mesh_vieweris the current desktop/Vulkan consumer of the engine packages.examples/animation_viewerplays the sample GLB's skeletal clips with a searchable in-window picker, clickable Play and Loop controls, and mouse-wheel scrolling through the clip list.examples/headless_smokeexercises the headless app loop without SDL2 or Vulkan.
The examples import the engine through the local collection:
-collection:thor=.That keeps the repo moving toward a library-style workflow instead of a root executable.