Lets Get Physical

I’ve been quite busy in the last couple of weeks, my MacBook tells me that I had an increase of 46% in screen-time, which is a bit scary. In my last devlog I had turned my sights from shadows to shaders and had implemented a Blinn shader. The next logical step was PBR materials. Change Log Static Rectangle V.10 ✦Implemented PBR material ✦Implemented EnvLight and HDR image-based lighting [1] ✦Added an optional 'skybox' render pass ✦Added a final composite pass for tone-mapping etc. ✕Removed AmbientLight (superceded by EnvLight) [2] ~Refactored lights to descriptor-based approach ✦Implemented screenspace reflections ✕Fixed race conditions in pipeline creation of the LineRenderer ✦Improved materials to support UV properties (scale, offset, tiling etc.) ~Refactored UI controls [1] I’ll briefly touch on this but it really deserves it’s own post which I’ll do next time. Same goes for Screenspace Reflections (SSR) [2] I had only just added this when I was working on the Blinn shader. I also just finished refactoring the Light too, these things happen. ...

February 20, 2026 · 4 min

Ooh Shiny

So shadows… What?! Shadows again? Yep, I’m sure you’re getting tired of hearing about it, I’m getting tired of thinking about them… But here is what I’ve done in the last few weeks. Static Rectangle V.09 ~Decoupled the filter radius from the SpotLight penumbra [1] ~Optimised shadow sampling by adding early out [2] ✦Increased sample count for shadow edges from 16 to 32 ✦Implemented "Randomly Rotated" poisson disk sampling to address some banding/muddy shadows [3] ✕Fixed pervasive SSAO issue where samples were flipping at face boundaries [4] ✦Added a simple AmbientLight that supports just colour and intensity ~Refactored Light class to support the AmbientLight ✦Added a ShadowCasterLight extension that both SpotLight and DirectionalLight extend ✦Added a Shader DAG node to the SceneGraph ✦Added the Picker pass for rendering selectable objects for user interaction ✦Added Outline renderer that renders outlines around selected objects ✦Added SelectionManager to manage selection state [1] I moved shadow softness to an explicit property on the light itself. In retrospect, this wasn’t the good idea I thought it was, it meant lights without penumbras could only have hard shadows without coming up with some other solution. Dumb. [2] I now do 4 samples first to check if the fragment is in shadow. Most fragments are either fully lit or fully in shadow, so those now only need 4 samples instead of 16. [3] The first fix was randomly rotating the sample kernel, which helped but introduced noise. So I swapped to using a blue noise (ironic) texture to drive the rotation instead. [4] The samples flipping directions at face boundaries was causing hard edges/obvious faceting. It was most obvious on curved objects and I had noticed it on the AT-ST model but shrugged it off. When I dropped a sphere into the scene I couldn’t ignore it. Shader Time After putting shadows to bed (for now…) I turned my attention to shaders. ...

February 13, 2026 · 4 min

Shadows: Redux

I’m at a point where I’m doing a lot of work, but the progress seems minimal. This happens often and is not at all unusual, especially projects like this that develop somewhat organically. You’ll often find yourself working on a component only to rework it when you look at an adjacent component or even the same component with fresh eyes. While this isn’t unusual, it does make blogging work in progress difficult. I’ll either have non-functional code or some simple test scene which isn’t interesting or difficult to explain out of context. ...

January 28, 2026 · 6 min

More Render Passes

Life got in my way a wee bit lately (a trip back to New Zealand, a Windows 11 update bricking an SSD and finishing up the work year to name a few recent events), though I have been tapping away at StaticRectangle. SSAO I decided to tackle SSAO (screen space ambient occlusion) after reading through the learnopengl SSAO article, it didn’t seem like too much extra work on top of what I had just completed for shadows. ...

December 23, 2025 · 3 min

Casting Shadows (...And Self Doubt)

I struggled getting shadows working, there was a real moment where I wanted to cut my losses and give up. It was particularly frustrating because shadow mapping itself isn’t a difficult concept to comprehend. You render a depth map from your shadow-casting light’s perspective, capturing what the light sees–and equally importantly, what it doesn’t. Then, while rendering pixels (fragments technically) during the main render pass, you check if that pixel falls within the light’s bounds (based on clipping, range, falloff, etc.). If it does, you transform that fragment’s world position into the light’s space and sample the shadow map. You compare the fragment’s depth (from the light’s perspective) against the stored depth in the shadow map–if the stored depth is less, something closer to the light is blocking it, so that pixel is in shadow. ...

November 20, 2025 · 3 min

Line Rendering

OK, so drawing lines is hard. Well maybe not hard per se, but certainly tedious. Looking into it (starting with Matt DesLauriers’ infamous ‘drawing lines is hard’ article linked above), I had the general gist. To draw the lines I want, the way I want, I need to segment them and render triangles. Like this, kind of… No real surprise there, honestly. Your GPU is a super-powered triangle crunching machine. While line primatives (line-list, line-strip) do exist, they’re not very useful–as far as I can tell. They’re typically aliased, hardware dependent and 1px wide. ...

November 10, 2025 · 6 min

Lights, Camera, Action!

Before we move on, in my last post I took a detour from the lighting/texturing pipeline to fix some issues in my Transform implementation. The debug scene was helpful for finding and fixing issues with transformations and it inadvertently highlighted a different issue. Multi-Sample Anti-Aliasing Without a technique known as ‘anti-aliasing’ edges can look jagged/stair-stepped because each pixel is either fully inside or fully outside the triangle you’re rendering with no in-between. ...

November 2, 2025 · 5 min

A Slight Detour

Far from the first and unlikely the last, I’ve taken a slight development detour. Firstly, I have migrated this dev blog from WordPress hosted by my web host to this statically generated one hosted on GitHub. I won’t bang on about it, but I was finding WordPress quite cumbersome and exceptionally slow—not just to load on the client side, but to do anything with it. It made the blogging process quite frustrating for me. ...

October 28, 2025 · 3 min

So long, Cube

It’s time to look into getting different geometry into our scene. In the Vulkan version of StaticRectangle, I was using OBJ files for meshes and a 3rd party library called tinyobjloader to load them. This was fine for that application because the size of the files wasn’t much of a concern. I mean it’s always a concern, but it wasn’t as much of a concern in the early stages. It’s something that can be optimised later.1 ...

October 23, 2025 · 14 min

A Conscious Decoupling

At the end of my last blog post StaticRectangle was rendering ‘the illustrious spinning cube’. We had a bunch new components, like the camera controller, input / resource manager as well as a top level Application that took ownership of some processes away from the Renderer. The next thing to tackle was splitting up the Renderer further, it was still doing more than just rendering. In fact it was the render function of the renderer that was animating the cube! certainly overstepping its responsibilities as a renderer. ...

October 20, 2025 · 8 min