# Niagara: a Vulkan renderer written from scratch on stream

> Niagara is a C++ Vulkan renderer whose README states that it is written on stream from scratch, without third party code that is Vulkan specific. It exists to try modern techniques such as GPU culling, cone culling, automatic occlusion culling and task and mesh shading, and it is built against the Vulkan 1.4 SDK with CMake. The trade-off is that it is a teaching and experimentation codebase with no releases, no documentation beyond a video playlist, and a hardware appetite that recent NVIDIA features impose.

**zeux/niagara** — A Vulkan renderer written from scratch on stream

- Repository: https://github.com/zeux/niagara
- Stars: 1,792 · Forks: 95
- Language: C++
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/zeux-niagara

## A renderer whose purpose is the experiments, not the product

Niagara is described in the README as a Vulkan renderer written on stream from scratch, without using any third party code that is Vulkan specific. Non-Vulkan-specific third party libraries are used, and the distinction is the point: the Vulkan layer is the part under study, so it is hand written.

The stated goal is to experiment with modern Vulkan rendering techniques, and the README names them. GPU culling and scene submission, cone culling, automatic occlusion culling, task and mesh shading, and whatever else comes up along the way. That last clause is revealing about the shape of the project. It is a working laboratory, not a library with a feature list.

The subject matter is the current generation of GPU driven rendering. In the classical model the CPU walks the scene, culls it, sorts it and issues draw calls, and the GPU is told what to draw. The techniques Niagara works on move that work onto the GPU: the GPU culls, the GPU builds the draw list, the GPU decides what to render, and the CPU mostly uploads buffers and waits.

The one-line repository description says it all: a Vulkan renderer written from scratch on stream. The code will be written on stream, the README says, and the project history is the proof, since the same README lists thirty three numbered episodes that map directly onto the feature list in the source.

## What the thirty three stream episodes actually built

The playlist is the closest thing this project has to documentation, and reading it in order is a reasonable map of modern Vulkan work.

The first three episodes are the foundation: setting up the instance and device and filling the screen with a solid colour, then rendering a triangle, then cleaning up validation errors and implementing swapchain resize. Episode three is the one that sets the tone for the whole project, since the renderer is developed with the validation layers active and the errors fixed rather than suppressed.

From there the work moves into the modern pipeline. Episode four renders a mesh using shader storage buffers and int8, episode five uses the NVIDIA RTX mesh shading pipeline, episode six optimises GPU time by using device-local memory and parallelising the mesh shader, and episode seven moves to descriptor update templates and SPIR-V parsing to extract reflection data. Episode eight is cluster cone culling using task shaders and subgroup operations, and episode nine tunes the mesh shading pipeline for performance.

Later episodes extend the range. There is a depth buffer with perspective projection and multi draw indirect, GPU frustum culling, draw call compaction using KHR_draw_indirect_count with LOD support, depth pyramid construction, automatic occlusion culling, and then an upgrade path through Vulkan 1.2 with GPU buffer pointers to Vulkan 1.3. Meshlet occlusion culling, task command submission and cluster compute culling follow, then glTF scene loading, bindless textures, ray tracing, materials and shadows, transparent shadows, moving objects, performance insights work, a simplification of the synchronisation, geometry cooking, descriptor heaps and opacity micromaps.

Two details stand out. The renderer reached glTF loading in episode twenty two and bindless textures in episode twenty three, so the scene handling came late in the sequence, after the GPU pipeline was already in place.

## Building it: Vulkan 1.4, CMake and recursive submodules

The requirements section is short and specific. The renderer was originally written using Visual Studio and targeted Windows desktops with modern Vulkan drivers, and the development platform has since switched to Linux, though it can still be built and run on Windows via CMake.

The clone has to be recursive, because the repository carries a .gitmodules file and an extern/ directory.

```bash
git clone https://github.com/zeux/niagara --recursive
```

You need the Vulkan 1.4 SDK and drivers installed. On Windows you open the folder in Visual Studio as a CMake project and build it, and on Linux you use CMake with the build generator of choice. The root CMakeLists.txt is the entry point for both, and the .clang-format file at the root tells you the project follows clang-format conventions if you want to match the existing style.

One version detail to note. A renderer that leans on the NVIDIA RTX mesh shading pipeline, on task and mesh shaders, and on KHR_draw_indirect_count is written against a specific Vulkan generation, and the stated requirement is the 1.4 SDK. If your driver is older, the code will not run, and that is a hardware and driver question rather than a build problem.

The absence of a package manifest, a container image or a documented dependency list is worth noting. There is no conan, no vcpkg and no fetchcontent list in the README, so the build depends on what the submodules provide and on the SDK you already have.

## Running the renderer with an obj file or a glTF scene

The command line takes paths to.obj files or a.gltf scene, and the repository ships a test asset so you have something to point it at immediately.

```bash
git clone https://github.com/zeux/niagara_bistro
```

The README names the test model as kitten.obj in the data/ folder, and the data/ directory at the repository root is where it lives. For a heavier scene, the Amazon Lumberyard Bistro scene is the standard stress test for a renderer of this kind, and it is not in this repository. You clone the separate niagara_bistro repository and pass the path to bistro.gltf instead.

That split is a design decision worth understanding. The Bistro scene is a large, well known sample, and keeping it out of the main repository keeps the clone small. The cost is that a full test of the GPU driven path requires a second download.

The running state of the renderer is also worth knowing, because it affects how you read the source. The renderer is a work in progress at the level of individual techniques, and the stream order is the order in which features arrived. If you are looking for occlusion culling, the relevant code is what episode fourteen produced, and the episodes after it refactored around that code.

## Bug reports to Khronos, Intel, NVIDIA and AMD as a real output

The issues section of the README is unusual and worth reading on its own. It records bugs the project found in the Vulkan stack during development, with a marker for the ones that have been fixed and a question mark for one that has not.

The list spans the whole stack. A crash in vkAcquireNextImageKHR in the validation layers when vkGetSwapchainImagesKHR has not been called, reported against the Vulkan-ValidationLayers repository. A wrong format count from vkGetPhysicalDeviceSurfaceFormatsKHR, reported to Intel's driver forum. A NonWritable check that fires even when vertexPipelineStoresAndAtomics is not enabled. Two glslang issues, one about an implicit int8 to float cast adding the Int8 capability to a shader, one about reading uint8_t from a storage buffer adding a UniformAndStorageBuffer8BitAccess capability it should not need.

The NVIDIA and Intel driver bugs are the interesting ones for a reader. vkCmdDrawIndexedIndirect rendering fewer draw calls than requested on Intel, and vkCmdDrawIndexedIndirectCountKHR causing a GPU crash on Intel, both come with a specific commit to reproduce. An NVidia GTX 10xx series GPU returning VK_ERROR_DEVICE_LOST when drawCount is 1,000,000 does too. An AMD driver build from 18.11.2 mishandling specialization constants, where using LATE in a draw culling shader causes nothing to render after the first frame, is a more subtle one.

This is a real contribution stream projects rarely produce. A renderer developed with the validation layers and with real drivers under load finds bugs in the layers below it, and the fixes land upstream in Khronos repositories and in vendor driver releases.

## Where Niagara is the wrong tool

The first limitation is that it is not a product. There are no GitHub releases, so there is no version to depend on, and the README gives no semantic version policy. You build from a commit, and the code changes weekly while the streams are running.

The second limitation is the documentation. There is no API documentation, no architecture document and no wiki. The video episodes are the design record, and reading thirty three videos to learn a codebase is a large investment for anything that is not a learning exercise.

The third limitation is the hardware appetite. Mesh shading, task shaders, subgroup operations, cluster culling and compute based culling are extension and feature dependent. A machine without the NVIDIA mesh shading extension, or an AMD or Intel GPU, gets a subset of what the stream demonstrates at best. The renderer is written against Vulkan 1.4, which narrows the set of drivers that will run it.

The fourth limitation is the scope of what it draws. It is a renderer for one scene in one window with a command line argument for the model. There is no camera system worth the name, no material authoring, no asset pipeline, no editor and no framework. Comparing it to a game engine is not a meaningful exercise.

The fifth limitation is the schedule. The development is streamed on YouTube on Saturdays at 11 AM PST with a somewhat irregular schedule, which means the pace of feature work is tied to a broadcast calendar rather than to a roadmap.

## Niagara next to Filament, the Khronos samples and a hand rolled engine

The realistic alternatives split into teaching material and production material, and Niagara sits between them.

The Khronos Vulkan Samples are the direct comparison on the teaching side. Each sample is smaller and more isolated, which makes them faster to read and easier to lift a technique from. Niagara differs in that it is one integrated renderer where the features interact, so the mesh shading work, the culling work and the descriptor work are in the same codebase and build on each other. If you want to understand how a technique behaves inside a real renderer rather than in isolation, that integration is the reason to look at Niagara.

Filament is the production comparison. If you need to ship a game or an application, Filament is the tool and Niagara is not a substitute for it.

The third option is writing your own on top of a thin layer, using something like volk for function loading and a small helper library. The difference there is scope discipline, where a general engine is built for many applications, while this renderer is built for one question at a time.

What nobody else offers in this set is the recording. A renderer whose entire development is public, with the reasoning visible in the episodes and the bug reports filed upstream as a by-product, is closer to a laboratory notebook than to a product, and that is its actual value.

## Conclusion

Adopt Niagara if you are learning modern Vulkan or need a working reference for mesh shading, cluster culling and GPU driven scene submission, and if you are willing to read the stream episodes as the documentation. Skip it if you need a production engine with releases, documentation and a stable API, since the repository ships no tagged versions. Before building, clone with the recursive flag so the extern/ submodules arrive, and confirm your driver supports Vulkan 1.4 and the NVIDIA mesh shading extension the renderer relies on.

## FAQ

### What is the Niagara Vulkan renderer?

It is a C++ Vulkan renderer written from scratch on stream, with no third party code that is Vulkan specific, created to experiment with GPU culling, cone culling, automatic occlusion culling and task and mesh shading.

### How do you build Niagara?

Clone the repository with the recursive flag so the extern submodules are fetched, install the Vulkan 1.4 SDK and drivers, then build with CMake, either through Visual Studio on Windows or with your generator of choice on Linux.

### What scene can I test Niagara with?

The repository ships kitten.obj in the data folder, and for a larger test you clone the separate niagara_bistro repository and pass the path to bistro.gltf.

### Does Niagara have releases or version tags?

No. The repository has no GitHub releases, so a consumer builds from a commit, and the stream runs on Saturdays at 11 AM PST with an irregular schedule.

### What licence is Niagara released under?

MIT, with the licence text in the LICENSE.md file at the repository root.

## Sources

- [Issues](https://github.com/zeux/niagara/issues)
- [License: MIT](https://github.com/zeux/niagara/blob/master/LICENSE)
- [README](https://github.com/zeux/niagara/blob/master/README.md)
- [zeux/niagara on GitHub](https://github.com/zeux/niagara)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/zeux-niagara
