Determine field of view ✅
Set fogTile.material to a shader material ✅
Hide tile by setting atlas coord to fog tile ✅

# cc is cube coordinates from https://www.redblobgames.com/grids/hexagons/
# am is subclass of TileMapLayer.
func hide(cc: Cc):
	am.set_cell(cc.toOffset(), tileSourceId, fogAtlasCoords)

func reveal(cc: Cc):
	am.set_cell(cc.toOffset(), tileSourceId, am.getCell(cc).ogAtlasCoords)

Result: great but overlapping lines in fog from shader rendering twice

I've tried messing with Y Sort Origin and Rendering Quadrant Size

  • Got it. What a journey. Many complicated approaches. TileSet UV re-mapping, collision calcs for irregular hexagons, magic numbers, lots of overengineered nonsense.

    Then while reading shader docs I realized a much better way:

    // returns true if this pixel is within the hexagon
    bool isInBounds(sampler2D tex, vec2 uv) {
    	return texture(tex, uv).a > .0001;
    }
    void fragment() {
    	// ...
    	if (!isInBounds(TEXTURE, UV)) {
    		COLOR = vec4(0.,0.,0.,0.);
    	}
    }

    The tilesheet alpha channel already knows whether we want to draw there.

Fixed fog overlap revealed tiles with: fogTileData.z_index = -1
Fixed "light bars" by making shader COLOR output alpha = 1.

However, I would like the fog to be semi-transparent. So I can refactor a fog layer that semi-occludes the revealed tiles underneath. But I believe I will get the same "light bars".

Light bars with different shader at alpha = 0.8

Got it. What a journey. Many complicated approaches. TileSet UV re-mapping, collision calcs for irregular hexagons, magic numbers, lots of overengineered nonsense.

Then while reading shader docs I realized a much better way:

// returns true if this pixel is within the hexagon
bool isInBounds(sampler2D tex, vec2 uv) {
	return texture(tex, uv).a > .0001;
}
void fragment() {
	// ...
	if (!isInBounds(TEXTURE, UV)) {
		COLOR = vec4(0.,0.,0.,0.);
	}
}

The tilesheet alpha channel already knows whether we want to draw there.