Richard Meredith's Avatar

Richard Meredith

@rtm223.me.bsky.social

Game developer @foldedfox.games | Previously: Bad North, Little Nightmares, LittleBigPlanet | He/Him http://mastodon.gamedev.place/@rtm223

1,165 Followers  |  670 Following  |  769 Posts  |  Joined: 18.02.2024  |  2.4646

Latest posts by rtm223.me on Bluesky

Bit tough on the teeth, yeah

03.08.2025 17:47 โ€” ๐Ÿ‘ 1    ๐Ÿ” 0    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0

Honestly, immediately after taking this picture I had the same thought!

03.08.2025 16:07 โ€” ๐Ÿ‘ 1    ๐Ÿ” 0    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0

I could do a kintsugi project, but then I'd be back with the problem of 2 enormous pots rather than 1! Have requested a refund though

03.08.2025 13:24 โ€” ๐Ÿ‘ 2    ๐Ÿ” 0    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0
Photo of a a cardboard box, liked with polystyrene. Shards of brown pottery that may have once been a plant pot are piled up in the bottom

Photo of a a cardboard box, liked with polystyrene. Shards of brown pottery that may have once been a plant pot are piled up in the bottom

I accidentally ordered 2 plant pots that are faaaar to big to sensibly fit I'm my apartment. Luckily one of them got smashed in transit so I only need to find use for one of them now

03.08.2025 12:50 โ€” ๐Ÿ‘ 7    ๐Ÿ” 0    ๐Ÿ’ฌ 2    ๐Ÿ“Œ 0
REANIMAL Trailer #2
YouTube video by Tarsier Studios REANIMAL Trailer #2

New REANIMAL trailer just dropped. I'm biassed of course, knowing several people working on this, but it does look pretty cool

youtu.be/ACZL7VziLS8?...

01.08.2025 22:01 โ€” ๐Ÿ‘ 4    ๐Ÿ” 1    ๐Ÿ’ฌ 0    ๐Ÿ“Œ 0
Video thumbnail

Wrapped up my experiments into processing hex tile data on the GPU this week. Mostly it was about learning Niagara features, though 80% of the time was implementing hexagon libraries for materials. Process breakdown below๐Ÿงต
#gamedev #indiedev #ue5 #UnrealEngine

01.08.2025 14:03 โ€” ๐Ÿ‘ 37    ๐Ÿ” 6    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0

I would be interested in trying a more rounded / blobby representation for my outlines though. I'm pretty sure it's possible to do using the neighbourhood data that I bake here, just not 100% on the details

01.08.2025 17:12 โ€” ๐Ÿ‘ 0    ๐Ÿ” 0    ๐Ÿ’ฌ 0    ๐Ÿ“Œ 0
Inigo Quilez :: computer graphics, mathematics, shaders, fractals, demoscene and more Tutorials and articles of Inigo Quilez on computer graphics, fractals, demoscene, shaders and more.

Ah yeah. It's a pretty common problem I imagine. FWIW rather than using blurs for my distance fields I'm calculating them using the hexagon code from here: iquilezles.org/articles/dis...

01.08.2025 17:09 โ€” ๐Ÿ‘ 1    ๐Ÿ” 0    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0

You could also produce the SDF as a texture to reduce complexity in the fragment shader. It would require a much larger render target, maybe 32x32 pixels per tile? So significant memory vs computation considerations there. Probably marginal for most real use cases

01.08.2025 14:03 โ€” ๐Ÿ‘ 2    ๐Ÿ” 0    ๐Ÿ’ฌ 0    ๐Ÿ“Œ 0

Lots of thoughts here.

Converting to rectangular space is kinda pointless, but it seemed like an obvious step when the goal was packing data into a square texture. Some marginal gains to be had by not converting between coordinate spaces

01.08.2025 14:03 โ€” ๐Ÿ‘ 2    ๐Ÿ” 0    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0
A hex grid similar to our original tiles. Instead of each tile being separated, they are merged into groups of contiguous tiles. Each tile has a gentle fade, with a soft white outline that extends slightly beyond the extents of the region (overlapping unfilled hexagons). There is an additional soft dark glow around the regions

A hex grid similar to our original tiles. Instead of each tile being separated, they are merged into groups of contiguous tiles. Each tile has a gentle fade, with a soft white outline that extends slightly beyond the extents of the region (overlapping unfilled hexagons). There is an additional soft dark glow around the regions

With that final distance field it's possible to style up nice outlines, glows etc. on the edges of the regions. I haven't pushed this very far here, but did calculate individual hexagon distance fields for each inner tile as well. Worth noting that outlines / glows can extend out beyond the tiles

01.08.2025 14:03 โ€” ๐Ÿ‘ 1    ๐Ÿ” 0    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0

The total distance field range from (0-1) is equal to the length of a hexagon edge (or distance from center of the hex to the corners). This means it only extends half that either side of the boundaries, which is not a huge distance, but probably good enough for most uses

01.08.2025 14:03 โ€” ๐Ÿ‘ 2    ๐Ÿ” 0    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0
The blurred/smudged pixels are not converted to blurred/smudged hexagons

The blurred/smudged pixels are not converted to blurred/smudged hexagons

The SDF from the hexagon data. This looks like a clean blurring of the raw true/false hexagons from upthread

The SDF from the hexagon data. This looks like a clean blurring of the raw true/false hexagons from upthread

In the material, I'm converting the bitmasks back into hexagon space, which can then be used to create distance fields - comparing current tile bit vs 2 closest neighbour tiles to see how close we are to the edge of a region

01.08.2025 14:03 โ€” ๐Ÿ‘ 2    ๐Ÿ” 0    ๐Ÿ’ฌ 2    ๐Ÿ“Œ 0
The bitmasks packed into the pixel data is hard to read, but it sork of looks as though the previous images has been blurred and smudged upwards a little bit, with some noise added. Not very human readable

The bitmasks packed into the pixel data is hard to read, but it sork of looks as though the previous images has been blurred and smudged upwards a little bit, with some noise added. Not very human readable

That array gets passed into Niagara, which creates an 8bit bitmask for each tile, with bits 0-5 indicating if the 6 neighbour tiles are present are filled, and the 6th bit indicating if the current tile is present. This gets written to an R8 render texture, for use in the material / fragment shader

01.08.2025 14:03 โ€” ๐Ÿ‘ 2    ๐Ÿ” 0    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0
The same hexagons as above, but now just as a solid white/black

The same hexagons as above, but now just as a solid white/black

Pixelated data in white / black, that sort of looks like a distorted version of the hexagons from the previous image

Pixelated data in white / black, that sort of looks like a distorted version of the hexagons from the previous image

First actual step is to pack the gameplay data into a form suitable for processing on the GPU. I'm converting to rectangular space and then packing this all into an array of bools

I realised just now that the rectangular coord conversion is entirely unnecessary, but it is easier to read, so ๐Ÿคท

01.08.2025 14:03 โ€” ๐Ÿ‘ 3    ๐Ÿ” 0    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0
A hex grid with grey background and blue tiles in arbitrary shapes. The blue tiles are rendered as very simple hexagons with a light, hard border

A hex grid with grey background and blue tiles in arbitrary shapes. The blue tiles are rendered as very simple hexagons with a light, hard border

Starting with an arbitrary set of tiles in Hexagon space (axial coordinates). This is the starting point of whatever gameplay data you have. For me that's a TMap of tiles

More info on hexagonal and axial coordinates here www.redblobgames.com/grids/hexago...

01.08.2025 14:03 โ€” ๐Ÿ‘ 3    ๐Ÿ” 0    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0
Video thumbnail

Wrapped up my experiments into processing hex tile data on the GPU this week. Mostly it was about learning Niagara features, though 80% of the time was implementing hexagon libraries for materials. Process breakdown below๐Ÿงต
#gamedev #indiedev #ue5 #UnrealEngine

01.08.2025 14:03 โ€” ๐Ÿ‘ 37    ๐Ÿ” 6    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0

TBH I always forget about the array version. I'm sure there's loads of examples when I have an array and loop through it when I could just do this

31.07.2025 15:01 โ€” ๐Ÿ‘ 1    ๐Ÿ” 0    ๐Ÿ’ฌ 0    ๐Ÿ“Œ 0

You can just plug multiple wires into Target and it will imply an array under the hood

31.07.2025 14:53 โ€” ๐Ÿ‘ 1    ๐Ÿ” 0    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 1

Not hooked up yet, but the idea is that CPU side would just would convert from Axial (hexagon) Coordinates to Offset (rectangular) Coordinates as an array of bools. GPU then computes neighbour info, packs that into bitmasks in an 8bit Render Target, then unpacks in material to draw nice hexes

30.07.2025 13:57 โ€” ๐Ÿ‘ 0    ๐Ÿ” 0    ๐Ÿ’ฌ 0    ๐Ÿ“Œ 0
Video thumbnail

Material turned out to be a complete mess, so needs reworking. But here's a niagara system taking an array of bools, encoding that to hexagon locations and neighbour flags, then back into SDF-based hexagon fields for rendering

30.07.2025 13:57 โ€” ๐Ÿ‘ 1    ๐Ÿ” 0    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0
HLSL code snippet:

static const int directions[2][6][2] =
	{
		{{1, 0}, {0, -1}, {-1, -1}, {-1, 0}, {-1, +1}, {0, +1}},	// EvenRows
		{{1, 0}, {+1, -1}, {0, -1}, {-1, 0}, {0, +1}, {+1, +1}},	// OddRows
	};


int parity = CoordY & 1;

const int selfArrayIndex = CoordX + CoordY * NumCellsX;
bool selfValue = false;
HexagonData.Get(selfArrayIndex, selfValue);

Bitmask = selfValue ? 255 : 0;

for(int i=0; i<6; i++)
{
    const int direction[2] = directions[parity][i];
    const int neighbor[2] = {CoordX + direction[0], CoordY + direction[1]};

    if(neighbor[0] < 0 || neighbor[0] >= NumCellsX)
        continue;
    if(neighbor[1] < 0 || neighbor[1] >= NumCellsY)
        continue;

    const int arrayIndex = neighbor[0] + neighbor[1] * NumCellsX;
    bool value;
    HexagonData.Get(arrayIndex, value);
    Bitmask = max(Bitmask, value ? 16:0);
}

HLSL code snippet: static const int directions[2][6][2] = { {{1, 0}, {0, -1}, {-1, -1}, {-1, 0}, {-1, +1}, {0, +1}}, // EvenRows {{1, 0}, {+1, -1}, {0, -1}, {-1, 0}, {0, +1}, {+1, +1}}, // OddRows }; int parity = CoordY & 1; const int selfArrayIndex = CoordX + CoordY * NumCellsX; bool selfValue = false; HexagonData.Get(selfArrayIndex, selfValue); Bitmask = selfValue ? 255 : 0; for(int i=0; i<6; i++) { const int direction[2] = directions[parity][i]; const int neighbor[2] = {CoordX + direction[0], CoordY + direction[1]}; if(neighbor[0] < 0 || neighbor[0] >= NumCellsX) continue; if(neighbor[1] < 0 || neighbor[1] >= NumCellsY) continue; const int arrayIndex = neighbor[0] + neighbor[1] * NumCellsX; bool value; HexagonData.Get(arrayIndex, value); Bitmask = max(Bitmask, value ? 16:0); }

I'm having to do HLSL code for this, which is well outside of my wheelhouse. People who actually know about shaders, what do we think about these int[2] arrays for int vectors? Should I just do everything as floats, split them into X and Y pairs? What's the preferred way

#gamedev

30.07.2025 11:47 โ€” ๐Ÿ‘ 7    ๐Ÿ” 1    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0
Screenshot of a 16-16 pixel grid. A few pixels are filled in white and for each of those, their 6 hexagonal neighbours are filled grey. For each white pixel this means that either their top/bottom right OR top/bottom left neighbours are left blank

Screenshot of a 16-16 pixel grid. A few pixels are filled in white and for each of those, their 6 hexagonal neighbours are filled grey. For each white pixel this means that either their top/bottom right OR top/bottom left neighbours are left blank

Continuing my Niagara Hexagons dive. Today's goal - encode neighbour data into 8-bit texture channels

I am also being constantly reminded why I don't want to use rectangular coordinates for hex grids - see how the neighbour patterns are different depending on what row you're on? Nightmare
#gamedev

30.07.2025 11:47 โ€” ๐Ÿ‘ 16    ๐Ÿ” 2    ๐Ÿ’ฌ 2    ๐Ÿ“Œ 0

I'd imagine you'd want to try and place a crude mesh over the relevant areas so you aren't paying transparency overdraw for fully transparent pixels everywhere. But effectively yeah

30.07.2025 06:32 โ€” ๐Ÿ‘ 0    ๐Ÿ” 0    ๐Ÿ’ฌ 0    ๐Ÿ“Œ 0

If the basic framework could potentially be used for that with some modification then that's good news to me!

30.07.2025 00:25 โ€” ๐Ÿ‘ 0    ๐Ÿ” 0    ๐Ÿ’ฌ 0    ๐Ÿ“Œ 0

The BBC micro has some wonderful 80s beige going on as well

30.07.2025 00:14 โ€” ๐Ÿ‘ 0    ๐Ÿ” 0    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0
Image of a BBC micro computer from the 80s. It's so very beige. Basically a chonky keyboard that extends out as a brick to hold the actual computer. The logo is an adorable little pixelated owl

Image of a BBC micro computer from the 80s. It's so very beige. Basically a chonky keyboard that extends out as a brick to hold the actual computer. The logo is an adorable little pixelated owl

Never seen one of those, but the form factor is familiar

30.07.2025 00:12 โ€” ๐Ÿ‘ 0    ๐Ÿ” 0    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0

Would this debug draw api work for rendering an arbitrary ui material, maybe via slate brush, as a debug overlay?

30.07.2025 00:02 โ€” ๐Ÿ‘ 0    ๐Ÿ” 0    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0
Scene from sunderfolk - a turn based rpg with combat on a hex grid. The effective range of the player's currently selected ability is clearly shown in the tiles with a nice material effect

Scene from sunderfolk - a turn based rpg with combat on a hex grid. The effective range of the player's currently selected ability is clearly shown in the tiles with a nice material effect

You can see a bit of a idea of where it becomes useful in sunderfolk

29.07.2025 21:17 โ€” ๐Ÿ‘ 3    ๐Ÿ” 0    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0
Scene from a tactics videogame played on a hex grid. The player is planning a move and has a visualisation of movement distance

Scene from a tactics videogame played on a hex grid. The player is planning a move and has a visualisation of movement distance

Being able to access grid data at runtime in materials for visualisations. Like this movement distance range thingy which is currently done using the line batcher. Would probably use some mix of materials, meshes, splines to make this stuff look good. Next step is packing data for SDF generation

29.07.2025 21:09 โ€” ๐Ÿ‘ 1    ๐Ÿ” 0    ๐Ÿ’ฌ 1    ๐Ÿ“Œ 0

@rtm223.me is following 20 prominent accounts