Shaders that reload themselves
Watch shader sources, recompile to SPIR-V, and swap pipelines without restarting. File watching at the imperative shell, idempotent pipeline rebuild, and surviving a failed compile without dropping the frame.
Build in public
A rendering laboratory, content platform, and public learning journey.
Experiments in modern rendering: Vulkan via Silk.NET, a functional core, and an imperative shell. Every technique ships as working code and a companion post that explains why it exists.
Every confirmed post, in order. Status reflects the current state of the draft, not a promise of when it will ship.
From a blank window to a composed frame.
Motivation and context. Limitations of existing engines, friction with OOP, rendering as data transformation, and the Functional Core + Imperative Shell pattern.
Read post →A minimal modern rendering pipeline in C# and Vulkan. Device, swapchain, shaders, handles, descriptors, and the first render command, explained from the ground up.
Read post →The G-Buffer and the geometry pass. Why deferred over forward, multi-render-target setup, G-Buffer layout, and writing scene data without a single light.
Read post →The lighting pass, the tonemap pass, and the render graph. Composing passes as pure data, compiling order and barriers from declarations, and testing a frame without a GPU. Closes the introduction.
Read draft →A scene runner grows into an interactive testbed.
Watch shader sources, recompile to SPIR-V, and swap pipelines without restarting. File watching at the imperative shell, idempotent pipeline rebuild, and surviving a failed compile without dropping the frame.
The scene panel grows into a real inspector: edit transforms, lights, and material parameters live, with the pure Scene snapshot as the source of truth. Elm-style Model/Msg/Update keeps the renderer a pure consumer.
glTF and OBJ instead of hardcoded geometry. The import boundary as a pure transformation from file bytes to immutable Mesh records, and why the lab treats assets as data rather than engine objects.
A plausible guess gives way to a physical model.
Swapping the Blinn-Phong lobe for a Cook-Torrance metallic-roughness BRDF: GGX distribution, Smith geometry, Schlick Fresnel, and what energy conservation actually buys you. The G-Buffer's two spare scalar slots become roughness and metallic, so the whole change is a shader plus a material record.
Per-pixel normals perturbed from a texture, faking high-frequency surface detail without geometry. Tangent space and the TBN basis, why this is the change that finally grows the vertex layout, and deriving tangents at import when the file does not ship them.
Retiring the hemispheric ambient constant for a real environment. The split-sum approximation: irradiance convolution, a prefiltered mip chain, and a BRDF integration LUT, plus the render graph's first precompute passes.
Infrastructure decisions and architecture records.
Field note. Why the engine centralized its own allocator instead of adopting VMA. Only one of VMA's three benefits was actually about allocation, and that was the one with no evidence behind it.
Read draft →Field note. Why the lab uses FIFO_RELAXED with MinImageCount instead of the AAA Mailbox default: honest frame-time signal over smoothed presentation.
Read draft →Field note. The pipeline shift where the scene stops being the swapchain target and becomes an image a panel draws. Covers the UI backend you have to write yourself, input-capture gating, and why swapping the UI library later cost so little.