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.

2D text layout with MSDF font rendering
2D text layout with MSDF font rendering and kerning.
3D text generated from glyph outlines
3D text generated using marching squares, Connected-Component Labeling, and earcut triangulation.

Deferred Renderer

Customized Sponza scene rendered with the deferred renderer
The customized Sponza scene rendered with the 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.

Parallax corrected cubemap reflections
Parallax corrected cubemap reflections
Parallax corrected cubemap reflections
Parallax corrected cubemap reflections

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.