Learning OpenGL 4+
—At the end of my third year at HTL I wanted to build something proper with OpenGL. Inspired by javidx9's work I set out to write something similar to his olcPixelGameEngine, a minimal self-contained framework for 2D rendering, in Go.
It never reached a finished state, but it got further than most of my abandoned projects. The text side was the most developed part: MSDF font rendering handled glyph rendering with wrapping and kerning support, and a 2D sprite and layout system sat on top. The most unusual piece was a 3D text generator. Marching squares extracted glyph outlines, Connected-Component Labeling identified which regions were interior faces, and earcut triangulated everything into a renderable mesh. Eventually it became clear that building a framework without a concrete use case to drive it would not lead anywhere. But it was a good learning exercise. The source is on GitHub.
Deferred Renderer
In the summer of 2022, shortly before starting at TU Wien, I began a new project and returned to 3D rendering for the first time since a simple forward renderer I had written in Java years earlier, when I barely had any idea what I was doing. The goal this time was to implement deferred rendering properly, starting from the learnopengl.com deferred shading guide and rendering a customized version of the Sponza scene. The source for this project and the PBR renderer below is on GitHub.
The G-buffer stored rgb8 albedo, rg16_snorm view space normals, rgb16f view space position, and an r8 AO channel. I was not trying to be efficient with the layout, and it shows. Shading was diffuse only and supported point, spot, and directional lights. Each light was rendered by drawing a bounding mesh covering its area of influence, which caused many fragments to be shaded multiple times and was quite wasteful in practice. Scene data was loaded using a custom format exported from Blender via a small export plugin I wrote.
I added SSAO for the first time, following the learnopengl guide. For shadows there was a single shadow map with PCF filtering based on the GPU Gems chapter 11.4 technique. Bloom was implemented from the Call of Duty: Advanced Warfare post-processing presentation, which describes the dual-filter pyramid approach, and this happened to be before the equivalent learnopengl article was published.
PBR and Image-Based Lighting
Once I was satisfied with the deferred renderer in spring 2023 I started a follow-up project. The goal this time was physically based rendering, for which deferred rendering offered no particular advantage, so I switched back to a simpler forward pipeline and built on a large amount of code carried over from the first project. I started with basic PBR shading following the learnopengl PBR series and the Filament documentation, then layered on IBL with diffuse irradiance and specular radiance. I even wrote my own cubemap convolver with OpenCL. Last came parallax corrected cubemaps, which fix the directional inaccuracy of environment reflections in enclosed spaces by reprojecting the sample direction against a local bounding volume. The implementation drew on writing by Sébastien Lagarde, Angelo Pesce, and Kostas Anagnostou.
Looking Back
These two projects are where I became genuinely comfortable with modern OpenGL. Working through deferred rendering, shadow maps, SSAO, PBR, IBL, and parallax corrected cubemaps gave me a solid enough foundation that I felt confident taking on something much more ambitious. That confidence carried directly into Ascent. In October 2023 I started the Fundamentals of Computer Graphics bachelor's course at TU Wien, where I first encountered Vulkan and C++. Ascent came the semester after that.