Archive for the ‘Game Development’ Category

Homogeneous Coordinates Make for Easy Rays

Monday, August 26th, 2024

This is a bit of a basic observation, but I figured I’d write it down nonetheless.

Suppose you have a transformation matrix in the usual 4×4 form. You transform a point by multiplying the matrix with the vector (in whatever order is conventional for you). Before doing this, you need to convert your point into homogeneous coordinates by adding an extra “1” to the end as the W coordinate. This works great.

But sometimes you need to be able to manipulate pure directions. For example, you’re transforming normal vectors. In this case, you care about rotation and the sign of the scale, but don’t care about the magnitude of the scale, and translation must be excluded. You could do this by first removing the translation from the transformation matrix by changing the last column back to (0, 0, 0, 1)… or, you could do it instead by using 0 as the W coordinate when converting to homogeneous coordinates.

This may seem like a hack, but it’s well-grounded and anything but a hack. 0 as the W coordinate turns the vector into an “infinite-length” vector pointed in a certain direction. Rotations will surely change the direction, as will negative scaling. But scaling infinity by a positive constant still yields infinity, and trying to add any finite value to infinity will be insignificant compared to the infinity, so translations and useless scales naturally fall out.

Fun fact: While projective spaces are quite natural in 3D graphics, I first encountered them when studying elliptic curves. When used in cryptography, there is only one point at infinity, and it functions as the identity element when the curve is interpreted as a group.

Tracking Down a macOS OpenGL Texture Error

Monday, August 12th, 2024

While working on my game, I received this cryptic error, along with no textures visible:

UNSUPPORTED (log once): POSSIBLE ISSUE: unit 0 GLD_TEXTURE_INDEX_2D is unloadable and bound to sampler type (Float) – using zero texture because texture unloadable

There are various mentions of this error around the web. Most of them are random peoples’ bug reports that end up being closed without resolution, but there were a few useful resources I came across.

(more…)

Cross-compiling for Steam Deck from Apple Silicon Mac

Monday, July 15th, 2024

Most of the development of my game has been happening on my M2 MacBook Air. One of the main places I’d like to play the game, though, is on my Steam Deck. In order to play the game on my Steam Deck, I need to compile it for the Steam Deck. There’s a number of ways I could do this, but I wanted a solution that would let me compile on my Mac directly with minimal infrastructure fuss (no VMs, network access, user mode emulation, etc).

SteamOS SDK

Poking around, games can run in one of a number of runtimes, each with a standardized set of libraries available. We’ll be going with the latest, “sniper”. You can find information about it on Valve’s web site.

The file we’re interested in is the developer sysroot (latest version as of writing). This has all the libraries that would be needed at runtime, plus all the header files, library symlinks, static archives, and other files we’d need for development. It also contains a compiler ready for use, except that the compiler is compiled for x86_64, while we’re on AArch64, so we can’t run the compiler directly. Also, it’s compiled for Linux, but we’re on macOS.

(more…)

Color Space Correctness in Alpha Blending

Monday, July 8th, 2024

Take a look at these three grayscale images:

Solid grayscale image with value 128Grayscale checkerboard with values 64 and 192Solid grayscale image with value 146

The left image has a solid luminance of 128. The middle image is a checkerboard alternating between luminances of 64 and 192. The right image has a solid luminance of 146. Squint your eyes. Does the luminance in the middle look closer to the luminance on the left, or on the right?

As a checkerboard, the center image is 50% 64 and 50% 192, so mathematically, it should average out to 128, but instead, there’s a substantial difference in luminance, and 146 is much closer. The reason for this discrepancy: All values in these images are sRGB values. When colors mix in the real world, the absolute amount of light is what’s mixed, but sRGB is a non-linear mapping, so attempting to mix sRGB values directly yields nonphysical results. You can read more about this in Eric Brasseur’s blog post, “Gamma error in picture scaling”.

Eric’s post is all about image scaling, where this definitely matters. But this is far from the only place this matters. Near and dear to our hearts from the previous post, blending in OpenGL also has to mix colors in a way that could be affected by use of the wrong color space for computations. Indeed, the blend formula says nothing about the relatively complicated conversions needed for sRGB. So what happens?

(more…)

Take Care with your Blend Function

Monday, July 1st, 2024

“Everyone” knows that the usual “over” composition operation is as such:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

However, this can in some cases lead to artifacting:

Correct Incorrect
Properly blended black text on orange background Improperly blended black text with white halo on orange background

Observe the halo effect in the “incorrect” image. I observed this effect when using WebGL on a web page, so in this case, the white color of the halo was the white background color of the web page peeking through. But why was the background peeking through?

(more…)

How to Use ANGLE in your SDL Program

Monday, May 27th, 2024

ANGLE is handy. Built to support WebGL in Chromium, it acts as a polyfill for OpenGL ES atop a plethora of other rendering APIs. Since it exposes a single graphics API you can build your application around, you might wonder about how you could use it with SDL, which provides a similarly “single API” experience for windowing and input. The answer is embarrassingly easy.

(more…)

Sky Simulation

Monday, May 13th, 2024

For my game, I would like to have a realistic sky in the background. I have a preference for a procedurally-generated sky over a skybox. But then, I need to learn about different ways of modeling the sky.

I first considered reusing the computations in the sky example from Three.js’s documentation, as it is liberally licensed. However, I decided I’d like to understand more of the theory behind it and use my own implementation instead of copying the Three.js’s example’s code.

The Three.js example’s implementation references the Preetham model. Introduced in 1999, the Preetham model seems to have been the baseline standard for a procedural sky for a long time. The original paper does its best to explain the scientific terminology to graphics practitioners, but there is still enough left unsaid that I found the paper hard to interpret in isolation. The most useful reference I found providing necessary background knowledge is Timothy Kol’s technical report. Kol also implements and compares the newer 2012 Hošek–Wilkie model. The remainder of this post mostly distills information from these three papers.

(more…)

Drawing Rounded Rectangles

Monday, April 29th, 2024

While working on my little game, I’ve iterated through different ways of displaying game state:

  1. Command line
  2. Web page
  3. 2D canvas
  4. 3D canvas

In each port, I preserve some elements and change others out. One of the elements I want to keep from the 2D version in the 3D version is rounded rectangles.

Initially, I used NanoVG to render the 2D elements into 3D. This works, but NanoVG is a lot of code. It’s very general. I don’t need that level of generality. I just want rounded rectangles. So how do we do that?

(more…)