Skip to content

Pompeii

...is a Vulkan-based Graphics Renderer written in C++. It is a learning project to explore the Vulkan API.

Active Development

This project is in active development, meaning it is actively evolving and being worked on, as there is always something new to add, tweak, or improve!
Look around here, or at the code on GitHub to see what Pompeii has become so far!

Main Features

Dynamic Rendering
Bindless Rendering
Deferred Rendering
Physically Based Rendering (PBR)
Image Based Lighting (IBL)
Auto-Exposure
Tone Mapping
Shadow Mapping
Alpha Cutout
Mipmap Generation
Debug Utils
Interactable Camera
Hover over an item

Description will appear here.

Render Passes

Depth Pre-Pass
G-Buf Albedo
G-Buf Normals
G-Buf Rough-Metal
Light Pass (HDR)
Blit Pass (LDR)

Process

Early Graphics Experience

I already had some graphics programming experience, mainly with my Software Ray-Tracer and Rasterizer. From these, I learned the fundamentals of the graphics pipeline and how the GPU works, though everything was implemented on the CPU.
Later, I explored hardware rendering by adding DirectX 11 support to my rasterizer, which was a great way to understand working with the GPU through an API. However, I wanted to dive into something more modern, which led me to discover Vulkan.

Learning Vulkan

I started out by following the Vulkan tutorial, which was great. It taught me how to work with Vulkan and explained how the API worked. Although at the end of the tutorial, you end up with 1 main file with all your code which is over 1000 lines long. This was far from ideal for what I wnated to achieve.
The next step was to refactor all that code into something more useable and reuseable. I created my own wrapper around Vulkan with classes, helper functions, builder pattern, and more, aiming for a structure that made it easier to extend and maintain.

Adding Advanced Features

One I completed the main ideas of my refactor, I started working on adding new features such as dynamic and bindless rendering, switching from forward to deferred rendering, and even adding shadowmapping and Image Based Lighting, as well as more features. At this stage, I had a fully functional Vulkan 3D rasterizer, but it still wasn’t exactly what I envisioned.

The Future

I wanted to add more to Pompeii, expand it further, make a user interface to control objects in the scene, add logic to objects, and slowly turn it into a useable engine of sorts. That's where I am today, working on splitting rendering from logic, and making Pompeii into a useable framework.

Auto Exposure

Automatic adjustment of the Exposure Value based on the average luminance, which is computed using compute shaders.

User Interface

As I am trying to turn Pompeii into something easy to work with, and something I can use to make stuff in, one of the first steps was providing a user interface to manipulate objects.

How did we get here?

Enjoy these interesting bugs and errors I got while experimenting and messing around!

Vertices collapsing
Normal Image Format Mismatch
A mismatch in the normal image format
Garbage Normals
Everything is purple
Zebra Effect
I call this one the zebra shader
Toon Effect
Unintentionally made a toon-like shader

Post-Processing

This is the fragment shader in the Blit Pass. Here I receive the HDR Image produced by the lighting pass, and I apply (auto) exposure and tonemapping to convert the image back to LDR, ready for presentation.

glsl
#version 450 core
#extension GL_GOOGLE_include_directive : require

// -- Includes --
#include "helpers_exposure.glsl"

// -- Data --
layout(set = 0, binding = 0) uniform sampler2D Render;
layout(set = 0, binding = 1) uniform CameraSettings
{
	float aperture;
	float shutterspeed;
	float iso;
} camSettings;
layout(set = 0, binding = 2) uniform sampler2D AverageLum;

// -- Input --
layout(location = 0) in vec2 fragTexCoord;

// -- Output --
layout(location = 0) out vec4 outColor;

// -- Shader --
void main()
{
	// -- Base Color --
	vec3 hdrColor = texture(Render, fragTexCoord).rgb;
	
	// -- Camera Exposure --
	const float EV100 = CalculateEV100(camSettings.aperture, camSettings.shutterspeed, camSettings.iso);
	const float exposure = EV100ToExposure(EV100);

	float averageLum = texelFetch(AverageLum, ivec2(0,0), 0).x;
	const float autoEV100 = AverageLuminanceToEV100(averageLum);
	const float autoExposure = EV100ToExposure(autoEV100);
	hdrColor = hdrColor * autoExposure;

	// -- Tone Mapping (WIP to switch dynamically) --
	const vec3 aces = ACESFilmToneMapping(hdrColor);
	const vec3 reinhard = ReinhardToneMapping(hdrColor);
	const vec3 uncharted2 = Uncharted2ToneMapping(hdrColor);
	vec3 ldrColor = reinhard;

	// -- Output --
	outColor = vec4(ldrColor, 1.0);
}

Resources

Third-Party Libraries

Vulkan API
Vulkan Memory Allocator (VMA)
GLFW
glm
stb
Open Asset Import Library (Assimp)
Hover over an item

Description will appear here.