Second Chance GazetteDevlogToken Use

A lamp material named GlassClear renders opaque in Unreal Engine 5.8

unreal-engineblendermaterialslightinglandscapewaterstatic-meshface-windinglodsilent-failure

He was on the treadmill when the riverbed got fixed

It was a Saturday, so for once he could start something that would not fit in an evening. James went out for a thirty-minute run. The agent – Claude Code Opus 5, which does most of the driving here – carried on at the machine at home, and he checked on it from his phone.

What it was carrying on with, he had reported himself the day before, off the screen: the grass goes under the river.

Landscape grass in Unreal is scattered from the landscape layer, and the landscape layer knows nothing about where a water body sits on top of it. So the Oakhaven – the river that runs through the town – had a proper lawn growing on its bed, blades standing bolt upright through 2.3 metres of water and perfectly visible through the surface. That was checked first, from underneath, before anything was touched. It was exactly as daft as it sounds.

An underwater view along a riverbed. The bottom is covered edge to edge in green grass with individual blades standing upright out of it, fading to blue-green in the distance, with the underside of the water surface dark across the top of the frame.
The riverbed at the hero reach, seen from under the water. That is landscape grass, growing on the bottom of a river.

The obvious fix was the banned one. Thinning the grass weights on the landscape is the same move as the mown mask on the golf course, and James had already ruled that out after having to go round deleting floating patches by hand. It also re-dirties something like 271 landscape packages, which is a lot of disk for a thing nobody can see from the bank.

What went in instead was a single greyscale image of the river corridor, world-aligned, baked offline in about twenty seconds. Both grass materials sample it: inside the wetted channel the blades collapse to their roots and the ground colour lerps to silt. Nothing was deleted, no grass weight moved, and not one landscape package was written. The blade-collapse path was already in the material – it ships for rain puddles.

The clever version of that field encodes the water surface height per texel, so the material can compare it against world height. It would have needed 16 bits, because the river falls 95 metres end to end and 8 bits quantises that to 37 centimetre steps, which would terrace the waterline into stairs. That is 64 MB of texture against roughly 0.8 GB of headroom on an 8 GB card. It was also unnecessary: a blade inside the wetted channel is on the bed, and the bed is under the water by construction. Sixteen megabytes, 8-bit, done.

Then the one nobody had reported. The river had been dropped 20 centimetres the day before and the survey file everything else is baked from never got rewritten. Forty-seven of forty-seven waterfowl sites and 1,076 of 1,076 fish rows carried the old height. Every duck, goose and swan on the Oakhaven had been floating 20 centimetres clear of the water, and the mist sat about half a metre up instead of a quarter. It was found by comparing modification dates, not by anybody looking at a duck.

He got back, looked at the water, and said he was happy with it.

Fourteen men, ten streets

There is a lodge in Second Chance – a black temple on a plot at the edge of town, a car park beside it, an inscription over the bronze doors. Fourteen men drive there in the evening. Saturday afternoon was spent deciding who they are.

The game's whole argument is that the player picks a direction and is never walked down it. You come out on a release programme; there is the straight road, and there is the other one, and nothing in the game chooses for you. GTA 6 will be a story you are taken through, and it will be magnificent at it. This is a town you can walk past things in. The lodge is meant to be one of those things – a bit of mystery for as long as you ignore it, and the plan is for it to be worth something to a player who does not. ⚠ None of that second half exists. What the fourteen men will eventually be good for is an intention on the roadmap, and today there are fourteen cars, a timetable, and no men at all.

So: fourteen of them, aged 43 to 100, spread across ten streets with no more than two on any one street, and their houses chosen by how far each has to drive – from under 50 metres to just under 500 – so that a staggered departure is worth watching.

That choice has to be deterministic, and the word is a trap for anyone meeting it cold. It sounds like it means fixed, or not random. It means very nearly the opposite: the answer should look scattered and arbitrary, and it should come out identical every time the level is rebuilt. Pick the houses with a plain random number and the fourteen get new addresses on every run, and every other file that named a house is now wrong.

The first cut used Python's own hash() for the tie-break, which is the trap inside the trap. hash() on a string is salted per process. Same script, same data, a different answer every time the interpreter starts – and it fails quietly, because each individual run looks perfectly sensible. It was swapped for FNV-1a, which is about twelve lines, needs no library, and gives the same answer on every machine on every day.

The cars come out of that same roster, which is the other phrase worth defining: a single source of truth. One file owns who lives where, who leaves at what time, who parks in which bay and what he drives, and the fourteen black saloons are placed out of it. There is no second list to forget. That is the only reason it is safe to move a man to a different street.

A dark stone building with rows of tall narrow windows, seen from above through the branches of a tree. A tarmac car park beside it holds fourteen black saloon cars parked in two rows of bays, with ornate black lamp posts spaced along the edge and green lawn all around.
Fourteen black saloons in the lodge car park, one bay each. Three donor models, dealt round-robin off the roster so they scatter without clumping.

The number plates came out of a pipeline the project already had, and it is a small thing worth getting right. Oakhaven registrations run AA111 AAA – eight characters, which no real British series has ever been – and the second letter of the area code is always Z, which the DVLA has never issued. Precise enough to read as real; deliberately impossible to match to anybody's actual car.

The cars themselves cost the afternoon's one real mistake. One of the three donor models is over two million triangles and another is not far behind, which is affordable once and not fourteen times, so each got its own reduction chain. Asking for the four levels as fractions produced a second level ten times smaller than intended – because that percentage is a fraction of the source mesh for the first level, and a fraction of the already reduced result for every level after it. Nothing warns about this. It would have surfaced as cars visibly popping as you walked across the car park, and it would have been blamed on anything but the arithmetic.

Rockstar have a department for this. He had a Saturday.

Eight lamps that would never have come on

The car park needed lighting, and the obvious answer was the project's existing big street column. It would have been eight dead lamps.

That was caught by reading the Blueprint rather than by looking at it. The big column's light components ship with visibility off, and nothing anywhere in that Blueprint ever turns them on – its construction script sets intensity and stops. The smaller column, by contrast, has a working day–night rig: it finds the sun, reads the time of day off the game instance on a timer, and drives intensity, visibility and the lamp panel material together.

The big one also carries three movable lights apiece at a 32 metre radius. Across eight posts that is twenty-four lights in a private yard, against eight from the smaller column at twelve metres. The entire VRAM question was settled by reading a construction script for four minutes.

The light was locked inside a solid cover

James had photographs of the lamp he actually wanted: a Victorian cast-iron gas standard – stepped octagonal plinth, swelling foot, banded waist, scroll brackets, four tapered panes under an ogee cap with an acorn on the top. Not the council sodium column that lights the rest of the town. This is a private yard and it should read as one. The agent built it parametrically in Blender, he looked at it in the viewport and said it looked great, and eight went round the car park.

Then he looked at a night render and asked whether the cover was transparent glass, because it looked like the light was locked inside a solid one.

A tall black cast-iron lamp post at night on a tiled floor. The lantern at the top reads as a solid dark box with a thin bright line of orange light escaping down one corner seam and along its base, while a wide pool of warm light falls on the floor in the foreground.
The lamp lit at night. Light escaping only at the seams, the panes reading as a solid dark box, and a pool of it on the ground below.

It was. The panes had been given a material called MI_LDG_GlassClear, chosen on the strength of its name. Clear in that name means untinted. The material is opaque, single-sided, and parented to the architectural house master – it is a building window meant to be seen from outside. On a preview sphere a dark opaque grey and a dark translucent grey are the same picture, which is how it got through.

It was the second one of those in an evening. An hour earlier the same reasoning had nearly put a material called M_LampIron on the columns, on the strength of the name and the fact that nothing else in the project used it. Rendered, it is a flat mid-grey that reads as unpainted metal rather than cast iron, and "used by nothing" turned out to mean unfinished rather than available. The correct material was already there, and the Lodge's own ironwork was already using it.

There are seven translucent glass materials in this project and two convincing impostors, and the names do not tell you which is which.

The eye over the door

The last thing that went up was an eye – James asked for one over the bronze doors, a green glowing orb behind a glass lens, that follows you.

The agent raised the problem with that before building it, which was the one time all day it got in front of something. A uniform glowing orb looks identical at every rotation, so an eye that tracked you perfectly would be indistinguishable from an eye that did not, and the whole job would have been invisible. It needed a pupil. Not a separate cap sitting proud of the ball – that is a curved surface three millimetres off another curved surface of the same radius, which is exactly the near-coincidence that makes two faces flicker against each other – but the ball's own faces within twenty degrees of the pole, given a second material slot.

Then the winding checker earned its keep three times running. All three pieces came out of the mesh builder facing the wrong way. The eyeball was blunt about it: 960 faces out of 960 inverted. The lens came back with a negative volume. The socket was the dangerous one, because it returned a plausible positive number – 0.016 cubic metres where 0.041 was expected – on account of its two pole fans disagreeing with the rest of it. A number that is merely wrong reads as a modelling mistake, not as a bug.

A Blender viewport cannot see any of this. It draws both sides of every face, so a model that is entirely inside out looks perfect right up until it reaches the engine.

A green glowing eye set in a winged stone emblem above a doorway on a dark brick wall at night. Beneath it a carved band reads OCULUS NON DORMIT between small roundels, and stone columns stand to either side.
The Unsleeping Eye over the bronze doors, with the motto band beneath it. The dark pupil is the only reason you can tell which way it is looking.

The pupil aims at the player on a 0.06 second timer, clamped to fifty degrees of yaw and thirty-eight of pitch, with an ease on it so it moves like something mechanical rather than something alive. The graph compiles clean, the node counts confirm all three writes landed, and the readback shows the aim chain wired correctly.

Nobody has seen it work. PIE was never started, so at the end of Saturday the eye is built and unproven, which is a different thing and the entry says so.

He had a roast on and his parents on a video call from Rotterdam. The eye could wait until somebody was there to watch it.

The fault

A material named GlassClear renders opaque in Unreal Engine 5.8

A lantern's glass panes were given MI_LDG_GlassClear, picked because of the word Clear. The lamp lit the ground beneath it and the lantern itself read as a solid dark box with light escaping only at the seams.

Clear in that name means untinted, not transparent. The asset is a material instance parented to an opaque architectural master, intended for a building window seen from the street.

Two things hid it:

  • on a preview sphere, a dark opaque grey and a dark translucent grey are the same picture
  • nothing errors, nothing warns, and the material is genuinely applied and genuinely bound

The same reasoning had nearly put M_LampIron on the columns an hour earlier, on the strength of its name and the fact that nothing used it. Rendered, it is a flat mid-grey that reads as unpainted metal.

The fix

Read the blend mode off the master material, not off the thumbnail

Walk up the parent chain to the master and read blend_mode and two_sided directly. The replacement here was a genuinely BLEND_TRANSLUCENT, two-sided pane material that already existed in the project.

The guard: a material's name is not a look, and "used by nothing" is as likely to mean unfinished as available. Preview it, and read the blend mode off the master before committing. This project has seven translucent glass materials and two opaque impostors whose names suggest otherwise.

The second guard: the fix was patched into both the importer and the placement script, so a re-run cannot quietly revert it.

The fault

Landscape grass grows on the riverbed and is visible through the water

Landscape grass is scattered from the landscape layer, which has no knowledge of where a water body sits. The riverbed carried a full lawn of upright blades under 2.3 metres of water, clearly visible through the surface from the bank.

Confirmed from underneath before anything was changed — a downward look from the bank would not have shown how bad it was.

The fix

Mask the grass from a world-aligned corridor field, not from grass weights

One 4096² 8-bit greyscale image of the river corridor, baked offline in about 20 seconds and sampled world-aligned by both grass materials: blades collapse to their roots inside the channel, ground colour lerps to silt, roughness rises.

  • zero landscape packages written — this is render-time only
  • reuses the blade-collapse path already shipping for rain puddles
  • 16 MB, against 64 MB for the 16-bit water-height version

Why not encode water height per texel: it needs 16 bits (the river falls 95 m; 8 bits quantises to 37 cm steps and terraces the waterline), and it is unnecessary — a blade inside the wetted channel is on the bed, and the bed is below the water by construction.

The guard: bake from the surface width, never the design channel width. The real wetted width is wider than the designed one wherever the bank is embanked, and grass would be left standing in the flooded margin.

The kit

ToolWhy this one
Blender, driven by a parametric scriptthe lamp and the eye are re-runnable from source, not hand-modelled
A signed-volume winding check that prints its own controlscaught all three eye pieces inverted, including one that returned a plausible positive
FNV-1aa hash that answers the same on every machine; the built-in one is salted per process
Reference photographs of a real cast-iron standardsettled the proportions no asset library was going to get right

Plain English

TermWhat it means
deterministicWritten so that the same question always gets the same answer, however many times it is asked. Picking which houses a group of people live in looks like it wants randomness, but plain randomness would give them a different address every time the level was rebuilt. Instead the choice is derived from something fixed — a name, a number, the house's own position — so it comes out scattered and unpredictable-looking, and comes out identical on the next run. The point is not the shuffle; it is that the world remembers.
single source of truthOne file that owns a fact, with everything else reading from it instead of keeping its own copy. The fourteen Lodge members' cars are placed out of the same roster that decides who lives where and who leaves at what time, so moving a member to a different house moves his car with him. The value of it is not tidiness — it is that there is no second list to forget to update, and therefore no way for two parts of the game to disagree about the same man.
material instanceA copy of a material with some settings changed. Cheap to make and cheap to render, so most surfaces are instances rather than originals.
landscapeUnreal's ground system — the sculpted, painted terrain the town sits on.
LODSimpler versions of a model, swapped in as it gets further away. The trick that lets a street hold hundreds of objects.
face windingThe order the corners of a triangle are listed in. That order is what decides which way the face points, so a model built with its corners listed the wrong way round comes out inside out.
PIE"Play In Editor" — pressing play inside the editor to test the game without building it first. Fast, and it behaves subtly differently from the real build.
VRAMMemory on the graphics card. This project has 8 GB of it, and that ceiling shapes most of the decisions in the devlog.

Things we still need to fix tomorrow:

  • The eye is built and has never run. Nobody has seen the pupil follow anything.
  • Zero of the fourteen men exist. They have houses, cars, departure times and no bodies.
  • The riverbed reads a bit flat, and it has never been seen wet.
  • The lamps have never been seen lit in the game — the editor sun is daylight, so the time of

day has to be moved before anyone can judge them.

  • The ray-tracing pool was already warning in red at the river before 369 trees went onto the

bank. Nobody has measured it since, and measuring it honestly means closing the editor.

  • The engine loop on the fourteen cars is a placeholder borrowed from a clapped-out hatchback

and has never been heard in game.

  • There is still no video of any of it.

← All devlog entries

Watch it get built. All of this goes up on YouTube as it happens — broken animations, buildings hovering a foot off the ground, the lot.

Subscribe on YouTube