Skip to content

Naughtyusername/odin_vulkan_wrapper

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

VKW — Vulkan Wrapper for Odin

A mid-level Vulkan wrapper library in Odin. Handles the first ~6K lines of Vulkan boilerplate so new 3D projects start productive immediately.

VKW gives you PBR rendering, mesh loading, camera systems, text rendering, and a pipeline builder — without hiding the Vulkan API. You still record command buffers and bind descriptor sets, but the tedious setup is done for you.

Features

  • One-call init/shutdown — Vulkan instance, device, swapchain, render pass, sync objects, VMA allocator
  • PBR rendering — Cook-Torrance BRDF with 5-map materials (albedo, metallic-roughness, normal, occlusion, emissive)
  • glTF model loading — geometry + PBR textures from .glb/.gltf files
  • HDR skybox — equirectangular environment maps
  • Lighting — up to 4 directional lights + 8 point lights with UE4 attenuation
  • Camera systems — FPS (WASD + mouse) and orbit (drag to rotate, scroll to zoom)
  • GPU text rendering — TTF fonts + SVG icons via odin-slug Bezier rendering
  • Pipeline builder — create custom graphics pipelines with a config struct instead of 200 lines of Vulkan boilerplate
  • ACES tone-mapping — filmic HDR-to-LDR in the fragment shader
  • Automatic swapchain recreation on window resize

Quick Start

import vkw "vkw:."

main :: proc() {
    renderer := new(vkw.Renderer)
    defer free(renderer)

    if !vkw.init(renderer) do return
    defer vkw.shutdown(renderer)

    meshes, materials, textures, ok := vkw.load_mesh_from_gltf(renderer, "model.glb")
    defer vkw.destroy_loaded_model(renderer, &meshes, &materials, &textures)

    cam := vkw.create_orbit_camera()
    lighting := vkw.DEFAULT_SCENE_LIGHTING

    for running {
        // ... handle SDL events, update camera ...

        cmd := vkw.begin_frame(renderer)
        if cmd == nil do continue

        vkw.update_camera_ubo_orbit(renderer, &cam)
        vkw.update_lights_ubo(renderer, &lighting)
        vkw.draw_skybox(renderer, cmd)

        vkw.bind_mesh_pipeline(renderer, cmd)
        for &mesh in meshes {
            vkw.draw_mesh(renderer, cmd, &mesh, linalg.MATRIX4F32_IDENTITY)
        }

        vkw.end_frame(renderer)
    }
}

See app/main.odin for the complete working example.

Dependencies

Dependency Purpose How to get it
Odin compiler Language odin-lang.org/docs/install
Vulkan SDK (1.4+) Graphics API + glslc shader compiler See platform instructions below
SDL3 Windowing, input, Vulkan surface creation See platform instructions below
g++ (or MSVC/clang) Compile VMA static lib (one-time) System package manager
git Clone VMA + Vulkan-Headers during VMA build System package manager

Bundled Dependencies (no install needed)

Dependency Location Purpose
odin-vma (Capati/odin-vma) libs/odin-vma/ Vulkan Memory Allocator bindings
VMA pre-built static libs libs/odin-vma/libvma_*.a Pre-compiled for Linux x86_64
odin-slug ../odin-slug (sibling directory) GPU Bezier text/SVG rendering

Setup

Linux

Install dependencies:

# Arch Linux
sudo pacman -S vulkan-devel vulkan-validation-layers sdl3 glslc

# Ubuntu/Debian
sudo apt install libvulkan-dev vulkan-validationlayers libsdl3-dev glslc

# Fedora
sudo dnf install vulkan-devel vulkan-validation-layers SDL3-devel glslc

Clone and build:

git clone https://github.com/Naughtyusername/odin_vulkan_wrapper
cd odin_vulkan_wrapper

# Clone odin-slug next to this project (required for text rendering)
git clone https://github.com/nickel-lang/odin-slug.git ../odin-slug

# Build VMA static lib (one-time, ~30 seconds)
./build.sh vma

# Build and run the demo
./build.sh run

Windows

Install dependencies:

  1. Odin — download from odin-lang.org
  2. Vulkan SDK 1.4+ — download from vulkan.lunarg.com. The installer adds glslc to PATH and sets the %VULKAN_SDK% environment variable — build.bat uses both to find it automatically.
  3. Visual Studio 2019+ or Build Tools for Visual Studio — needed to compile the VMA static library (one-time). Install the "Desktop development with C++" workload. build.bat vma detects VS automatically via vswhere.exe; no Developer Command Prompt needed.
  4. SDL3 — download the development libraries (SDL3-devel-*-VC.zip) from libsdl.org. The demo needs SDL3.dll at runtime. Either:
    • Set SDL3_PATH to the extracted directory (e.g. set SDL3_PATH=C:\SDL3-3.2.0-VC) — build.bat copies SDL3.dll to build\ automatically, or
    • Copy SDL3.dll manually to build\, or
    • Add the directory containing SDL3.dll to your PATH

Clone and build:

git clone https://github.com/Naughtyusername/odin_vulkan_wrapper
cd odin_vulkan_wrapper

:: Clone odin-slug next to this project (required for text rendering)
git clone https://github.com/nickel-lang/odin-slug.git ..\odin-slug

:: Build VMA static lib (one-time, auto-detects MSVC)
build.bat vma

:: Build and run (set SDL3_PATH first if SDL3.dll isn't in build\ or PATH)
set SDL3_PATH=C:\SDL3-3.2.0-VC
build.bat run

macOS (MoltenVK)

Install dependencies:

# Homebrew
brew install molten-vk sdl3 glslc

# Vulkan SDK (alternative) — provides MoltenVK + validation layers
# Download from https://vulkan.lunarg.com/

Clone and build:

git clone https://github.com/Naughtyusername/odin_vulkan_wrapper
cd odin_vulkan_wrapper

git clone https://github.com/nickel-lang/odin-slug.git ../odin-slug

./build.sh vma
./build.sh run

Build Commands

Linux / macOS:

./build.sh vma        # One-time: compile VMA static lib
./build.sh build      # Compile shaders + build demo
./build.sh run        # Build + run
./build.sh check      # Type-check wrapper library only (no binary)
./build.sh shaders    # Compile GLSL -> SPIR-V only
./build.sh clean      # Remove build artifacts + compiled shaders

Windows (from VS Developer Command Prompt):

build.bat vma         :: One-time: compile VMA static lib
build.bat build       :: Compile shaders + build demo
build.bat run         :: Build + run
build.bat check       :: Type-check wrapper library only (no binary)
build.bat shaders     :: Compile GLSL -> SPIR-V only
build.bat clean       :: Remove build artifacts + compiled shaders

Using VKW in Your Own Project

VKW is a collection-based library. Point the Odin compiler at it:

odin build my_game/ \
    -collection:vkw=path/to/vulkan_wrapper/src \
    -collection:vma=path/to/vulkan_wrapper/libs/odin-vma \
    -collection:slug=path/to/odin-slug

Then import in your code:

import vkw "vkw:."

Compiling Shaders

VKW's built-in shaders are embedded at compile time via #load. Your custom shaders need to be compiled to SPIR-V before building:

glslc -fshader-stage=vertex my_shader.vert.glsl -o my_shader.vert.spv
glslc -fshader-stage=fragment my_shader.frag.glsl -o my_shader.frag.spv

Then load them into a custom pipeline:

config := vkw.DEFAULT_PIPELINE_CONFIG
config.vert_spv = #load("my_shader.vert.spv")
config.frag_spv = #load("my_shader.frag.spv")
config.descriptor_set_layouts = { renderer.global_set_layout, my_layout }

pipe, ok := vkw.build_pipeline(renderer, config)
defer vkw.destroy_custom_pipeline(renderer, &pipe)

API Overview

Core

Proc Description
init(r, config) Initialize Vulkan + window
shutdown(r) Destroy everything
begin_frame(r) Acquire image, begin command buffer
end_frame(r) Submit + present
notify_resize(r) Flag swapchain for recreation
wait_idle(r) Block until GPU finishes

Resources

Proc Description
load_mesh_from_gltf(r, path) Load glTF model (meshes + materials + textures)
destroy_loaded_model(r, ...) Clean up everything from load_mesh_from_gltf
create_texture_from_file(r, path) Load image as GPU texture
create_material(r, ...) Create PBR material from textures
load_environment_map(r, path) Load HDR skybox

Rendering

Proc Description
bind_mesh_pipeline(r, cmd) Bind built-in PBR pipeline
draw_mesh(r, cmd, mesh, model_matrix) Draw a mesh instance
draw_mesh_instanced(r, cmd, mesh, models) Draw many instances in one draw call
draw_shadow_pass(r, cmd, meshes, models, light_dir, scene_min, scene_max) Render depth-only shadow map (call before begin_render_pass)
draw_skybox(r, cmd) Draw HDR background
build_pipeline(r, config) Create custom graphics pipeline
bind_custom_pipeline(r, cmd, pipe) Bind a custom pipeline

Camera

Proc Description
create_camera(pos) FPS camera (WASD + mouse)
create_orbit_camera() Orbit camera (drag + scroll)
update_camera(cam, dt, keys, ...) Update FPS camera
update_orbit_camera(cam, ...) Update orbit camera
update_camera_ubo(r, cam) Upload FPS camera matrices to GPU
update_camera_ubo_orbit(r, cam) Upload orbit camera matrices to GPU

Lighting

Proc Description
update_lights_ubo(r, lighting) Upload scene lighting to GPU
add_dir_light(lighting, ...) Add directional light (max 4)
add_point_light(lighting, ...) Add point light (max 8)

Text (optional, requires odin-slug)

Proc Description
init_text_renderer(r) Initialize slug backend
load_text_font(r, slot, path) Load TTF font
load_text_font_with_icons(r, slot, path, icons) Load TTF + SVG icons
text_begin(r) Start text batch
text_flush(r, cmd) Upload + draw text
draw_debug_overlay(r, info) FPS/camera debug text

Project Structure

vulkan_wrapper/
├── src/                    # The wrapper library (import as vkw)
│   ├── wrapper.odin        #   Core types (Renderer, Config) + init/shutdown
│   ├── init.odin           #   Vulkan instance, device, VMA bootstrap
│   ├── swapchain.odin      #   Swapchain, render pass, framebuffers
│   ├── pipeline.odin       #   Pipeline creation + pipeline builder API
│   ├── commands.odin       #   Command buffers, sync, begin/end frame
│   ├── resources.odin      #   Buffers, textures, materials, descriptors
│   ├── mesh.odin           #   Mesh types, camera, lighting, glTF loader
│   └── text.odin           #   Slug text/SVG rendering integration
├── app/                    # Demo / usage reference
│   └── main.odin
├── shaders/                # GLSL source (compiled to .spv at build time)
├── assets/                 # Models, textures, icons (committed — see Demo Assets)
├── libs/odin-vma/          # VMA bindings + pre-built static lib
├── build.sh                # Linux/macOS build script
└── build.bat               # Windows build script

Gotchas

Shadow map boundsdraw_shadow_pass takes scene_min / scene_max parameters that define the orthographic frustum for the shadow map. These default to {-10, -10, -10} / {10, 10, 10}. If your scene is larger than this and shadows disappear or clip, pass your actual scene AABB:

vkw.draw_shadow_pass(renderer, cmd, meshes, models, light_dir,
    scene_min = {-50, -5, -50},
    scene_max = { 50, 20,  50},
)

Renderer is large — the Renderer struct is ~1.3MB (slug's inline vertex arrays). Always heap-allocate it with new(vkw.Renderer), never put it on the stack.

Shader compilation order — VKW's built-in shaders are embedded via #load at compile time. You must run ./build.sh shaders (or ./build.sh build, which does it automatically) before the first Odin build, or you'll get "file not found" compile errors for the .spv files.

Platform Status

Platform Architecture Status
Linux x86_64 Tested (primary dev platform)
Windows x86_64 Tested
macOS ARM64 (Apple Silicon) Build supported via MoltenVK, community-tested

Demo Assets

The demo assets are included in the repo — ./build.sh run works out of the box with no extra downloads.

Asset Source License
assets/DamagedHelmet.glb KhronosGroup/glTF-Sample-Assets CC BY 4.0
assets/BoxTextured.glb KhronosGroup/glTF-Sample-Assets CC BY 4.0
assets/environment.hdr Poly Haven CC0
assets/icons/*.svg Custom MIT

Note: environment.hdr is 24MB. Initial clone will take a moment on slow connections.

License

MIT — Copyright (c) 2026 Naughtyusername

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors