Birdoggydog's Builds

Lighting building interiors that nobody built by hand

The rooms inside generated buildings were black. They now get window light by day and sconce lamps at night, from a budget of 8 real lights in the whole world.

The rooms inside the generated buildings now have light that follows the game clock. By day each room gets a cool light under its ceiling, stronger the more windows it has. At night the wall sconce gives a warm lamp that is a pool on the wall and dark in the corners. Only 4 real lights exist per building and 8 in the whole world, and I measured the cost in the test street at about 8 fps inside a house at noon.

40 seconds. A house at 1 pm with window light, the clock turning to night, a sconce’s pool of light at 11 pm, the stair, the room upstairs, and the house from the street.

Why was the inside of every building black?

Two judges and two workers all found the same thing: the top storey of the tower was almost black with one lit window square, the stairwell was dark, and the sconces on the walls gave no light. The film I had of the floor plans had to place its own lamps to show anything. I had said earlier that light through the windows was the ideal, so the aim was windows letting the day in, a stair or top storey that is never black, and lamps at night.

How do you light rooms nobody placed a lamp in?

The buildings are generated, so there is no hand-placed light to rely on. BuildingInteriorLight is added at the end of the building builder and reads only the rooms, the stairs and the sconce and window instances. Every room becomes a light point.

By day the point sits under the ceiling over the middle of the room. Its energy is 0.7 times the room’s window share, with a floor of 0.4 so a room with no window is still not black. At night the point moves to the sconce’s light anchor, in the look’s lamp color, with energy 1.6 times how many of the house’s lamps are lit. A dead house gets no lamp, and nothing goes below a share of moonlight.

A real light costs frame time, so there is a budget. Each building has 4 omni lights with no shadows, and the whole world has 8. The room the camera is in comes first, then the nearest rooms, and a room one storey away counts as 8 m further. The lights are handed out again each time the camera moves 0.75 m, and each one fades out and in over a quarter of a second so nothing pops. The rooms past the budget are faked: a small glowing glass at every lit sconce, and the shader’s window glow, which now fades in between 9 and 18 m from the camera so a nearby room is lit by its lamp and not by a flat color.

When I measured it in the test street, one run each, I got inside a house at noon 129.8 fps without the light and 121.1 with it, at midnight 117.7 and 114.8. Over every district it is 63.0 and 64.2 fps, because the rooms far from the camera mostly sit idle.

Why did the first version look like an orange wash?

Nothing was black any more, but a judge sent it back. At night every room was an even orange with no falloff, so it didn’t look like lamplight, and one landing shot was a flat wall. I made the night lamp short and steep, with a range of 5 m and an attenuation of 2, so the light is bright at the sconce and falls off to the corners. The film now holds on a sconce and its pool.

The judge also caught light from nowhere. A room with no sconce, and every stair, still got a full lamp from a point under the ceiling. Those now borrow 0.3 of the nearest sconced room’s lamp, or have only the moon.

The last bug was thin orange strips in the corner of the stair shot. They were a window’s glow shader drawn from inside the house, so a pane looked lit from the room. The panes are instances of one batched mesh, and in a Godot fragment shader the model matrix is the batch’s and not the piece’s, so a facing test there is wrong. I moved the test into vertex(), where the per-instance transform is right, and a pane now glows only when seen from outside. The shader also draws no room glow inside the house the camera stands in.

What is still wrong?

The lights have no shadows, because an omni shadow is a cube map and that is too much for 8 lights. A lamp can reach through a wall into the next room, and a little through a floor. The rooms past the budget are faked and not baked, since Godot’s baked lighting doesn’t suit buildings built at runtime. I’m also keeping the buildings open to the sun and sky through the windows, which is a decision I still want to confirm.

Also done

  • Fixed a test that had been failing on every branch: the vine climber rule only matched the cart door’s wall, but a house’s street door is now the narrow one. I fixed the rule, not the test.
  • Made the light script a tool script, because its static values started at -1 and an infinite box and the editor complained.