Lighting techniques with good payoff:effort ratios

Since I'm going to be getting deep into lighting with my gamedev project, I'm wondering, what are some of the simpler lighting techniques that have the highest payoff in terms of inexpensive graphical fidelity. I already have experience with basic ambient/diffuse/specular lighting, and also with incorporating textures (normal maps and... "shinyness maps"?) into these calculations, so I'll want something more advanced than that. What's the lighting equivalent of of a random skip list or a Brain Fuck Scheduler?
Maybe you could fake some static global illumination?

If your world is constructed of cube voxels you could do fairly easy lookups of light reflected by neighbouring voxels (could do this by sampling a few rays perturbed from the surface normal of the voxel at each of the voxels vertices). Modulate the resulting reflected colour by the distance to the intersection with the reflected voxel.

This would give you a colour to blend with your existing voxel colour at each vertice.

Just an idea!
Yeah I'm definitely planning to have "baked" lighting which recomputes (for some subset of blocks) whenever a block is changed. That's what Minecraft has. I have a basic implementation of that done. But I want to look better than Minecraft!
What Minecraft has looks like faked ambient-occlusion baking, but what I mean is faked global illumination baking. The difference is due to sampling the color and light reflected by neighbours (not just how much darkening/shadow) You'd get some color-bleed on neighbouring voxels approximating reflected light. I.e. If a white block is next to a red block, you'd likely see some of the red colour bounce onto the white block surface (especially at close distance). I don't think Minecraft has that? Would look pretty good imho - cheap to fake also I think. Could potentially combine with the fake ambient occlusion baking step. If that's not awesome enough, maybe a screen space water shader with normal mapped waves/ripples which refract and reflect? That'd look cool! :)
xcodedave
What Minecraft has looks like faked ambient-occlusion baking, but what I mean is faked global illumination baking. The difference is due to sampling the color and light reflected by neighbours (not just how much darkening/shadow) You'd get some color-bleed on neighbouring voxels approximating reflected light. I.e. If a white block is next to a red block, you'd likely see some of the red colour bounce onto the white block surface (especially at close distance). I don't think Minecraft has that? Would look pretty good imho - cheap to fake also I think. Could potentially combine with the fake ambient occlusion baking step. If that's not awesome enough, maybe a screen space water shader with normal mapped waves/ripples which refract and reflect? That'd look cool! :)


👍

Edited by Oswald Hurlem on
FWIW, as far as I can tell from looking (I haven't delved into it too closely), Minecraft has roughly the following things baked:

  • some kind of local AO
  • some kind of soft-shadowed skylight -- the starting approximation is any surface which doesn't have another block straight above it is skylit; but there's some kind of fuzzing as you go down that softens the effect. this maybe also produces a bit of a "global illumination" effect on things adjacent to sky-lit surfaces
  • local light sources (torches etc) don't penetrate solid walls; it looks like it just uses a depth-first-search lighting algorithm, which allows the light to go around corners and produces a local "global illumination" effect, which is cheaper to compute then casting rays from all the nearby surfaces, and probably looks better too

These all seem like they're all pretty good payoff:computation; I'm not sure if you meant "human effort" or "computational effort".

Probably the biggest payoff (which you may already be planning) would be using shadowmapping for the sun, so you get one good solid light source (unlike Minecraft). I've just hesitated to do that on OBBG because I don't really want to spend half my geometry budget on shadows, just because. It also gives you something for your normal maps to respond to; responding to local lights is gonna be hard without light-going-through-walls.


Edited by Sean Barrett on
Light in minecraft is baked per block.

Each block has 2 4-bit light level values, sunlight and artificial light. Blocks that can see the sky will have sunlight as 15 and the light emitting blocks will set their light value to whatever its light level is (14 for torches, 15 for glowstone,...)

Then a floodfill will spread the light accounting for a per block drop-off (air and glass has drop-off 1, water has something higher, ...)

The final light level (used for rendering and game logic) is the max of the artificial light and the (sun light - night darkness).

The reason for the 2 separate light levels is to avoid lag fests when night falls or morning comes.

The AO is I think an artifact in how the light values per vertex are calculated. The renderer averages out the light values of the neighbouring blocks to smooth out the light. That same operation will reduce the light level in inside corners.
@nothings @ratchetfreak

Yep, the simple skylight, breadth-first light propogation, and the AO is what I have coded up right now. It was quite low effort, by which I do mean "human effort", although it's not too computationally expensive either. There's some artifacts in the lighting, I know why and it's a TODO.


Indoor lighting is a big emphasis and I want to do something interesting with it. What I think I'm going to do for the light baking is have the first bounce be physical (possibly just one ray per vertex), then spread some of the light with the breadth-first technique.

I'd also like moving objects to respond to lights. For that, I have two ideas. The first is, I'll store a 64 bit mask in each empty grid cell, saying which lights (in its chunk or a neighboring chunk) can light an object in that cell. That will limit a player to >64 light sources per "chunk," but maybe that won't be a problem?

The second idea is to store a mask where if a bit is set to 1, it means that light is coming from some fixed direction. With 26 bits I can store Up, Down, North, South, East, West, and every diagonal in between. Then if an object is in a cell with that direction's bit set, I make it lit from that direction. This is contingent upon there being only one type of light, and it might look totally janky.

I guess I'll find out!

Edited by Oswald Hurlem on
Sorry, breadth-first not depth-first, yes.

The big problem is always shadows. The problem I forsee w/ something like the mask-reachability is making it match the baked lighting. At least MC-style, the light is allowed to reach around corners, and darkens w/ distance based on the distance *travelled* in the breadth-first. So you'd need to store that distance in the 'empty mask', or else you're just going to use actual distance from the light and it won't match the background. Additionally, in MC lights don't reach very far; you don't want to BFS 100^3 when creating a light (unless you're not supporting placing them dynamically).

Modern "lots of light" rendering is done with deferred rendering (or similarly tiled forward), which seems pretty simple to do (if you're willing to sacrifice MSAA), but still doesn't have a good answer to *shadowing* lots of lights. (But AAA can still shadow more lights than we can because they're less likely to be geometry-limited so they can render the scene 8 times for 8 lights or whatever; but past that I assume it's mostly the level designers being careful to hide/prevent bleed-through.)