OSM2World2Lua

OpenStreetMap buildings, in plain Lua

A port of OSM2World's building rules to Lua. Give it a building's outline and its OpenStreetMap tags, and it gives back textured triangles: walls, windows and the right roof. No engine code, so it works in LÖVE, Garry's Mod, Roblox or anything else that runs Lua.

A rendered street of buildings with gabled, hipped, pyramidal and dome roofs and a church with a tower
Made by OSM2World2Lua from tags alone: gabled, hipped, pyramidal, skillion and dome roofs, colours and materials from building:colour, building:material and roof:colour, and a church whose tower is a building:part.

What it does

OpenStreetMap describes buildings with an outline and tags: height, building:levels, roof:shape, roof:height, colours and materials, and separate building:part areas for towers and wings. OSM2World turns that into 3D models with years of rules for every tag. OSM2World2Lua follows those rules one for one, so the same tags give the same buildings, just in Lua.

It is meant for games that build their world from map data while the player moves, so it only does the geometry: you hand it outlines in metres and get triangle lists grouped by material, ready to turn into your engine's meshes.

What is ported so far

The library is new and grows piece by piece. Each piece is a direct port of the OSM2World class named next to it.

PieceOSM2World sourceState
Roofs: flat, gabled, saltbox, hipped, side-hipped, half-hipped, side-half-hipped, gambrel, mansard, round
Checked against the real OSM2World: 56 of 56 test roofs give the same triangles, order and texture coordinates.
FlatRoof, GabledRoof, … RoofWithRidgePorted
Roofs: pyramidal, cone, skillion, sawtooth, dome, onion, chimney
Smooth roofs (dome, onion, cone, round) are lit per triangle.
PyramidalRoof, ConeRoof, SkillionRoof, SawtoothRoof, DomeRoof, OnionRoof, ChimneyRoofPorted
Roof height from roof:height, roof:angle, roof:levels, defaultsRoof, RoofWithRidge, LevelAndHeightDataPorted
Complex roofs from mapped ridge and edge ways
Needs the mapped roof:ridge / roof:edge ways; falls back to flat.
ComplexRoofNot yet
Building types, levels, heights, min_height, building:min_level
Indoor level tags (indoor=level) are not used.
BuildingDefaults, LevelAndHeightDataPorted
Materials and colours from building:material, building:colour, roof:material, roof:colour
Including OSM2World's own colour names (red roofs, white walls, …).
BuildingPart.buildMaterialPorted
Building parts and when the outline itself is drawn
The “parts cover too little” rule uses areas, not exact polygon subtraction.
BuildingMostly
Walls split at corners, tops following the roof (gable ends)ExteriorBuildingWallPorted
Windows as textures, one row per level
FLAT_TEXTURES: the window texture drawn just in front of the wall.
ExteriorBuildingWall, TexturedWindowPorted
Windows and doors as 3D geometry, mapped windows and doorsGeometryWindow, Door, WallSurfaceNot yet
Building passages, indoor roomsBuildingPart, indoor/*Not yet
Roads, trees, water, barriers and the other modules
Buildings come first.
RoadModule, TreeModule, …Not yet

Use it

Copy the o2w folder (and textures) into your project. Plain Lua finds it with require; engines without require set O2W_REQUIRE to their own loader first.

local o2w = require("o2w")
local out = o2w.collector({ max_verts = 65535 })

o2w.building({
  outer = { 0, 0, 10, 0, 10, 8, 0, 8 },           -- metres, x east, y north
  tags = { building = "house", ["building:levels"] = "2",
           ["roof:shape"] = "gabled", ["roof:colour"] = "red" },
  base = 3.5,                                     -- ground elevation
}, out)

for _, g in ipairs(out:groups()) do
  local tex = o2w.materials[g.material].tex       -- e.g. "roof_default.png"
  -- g.d = { x, y, z, u, v, r, g, b, ... }, three vertices per triangle
end

Buildings with parts

Pass building:part areas in parts. As in OSM2World, the building outline itself is only drawn when it has no parts, or when the parts cover too little of it.

Light

Vertex colours are the material colour times a simple sun and sky light. Pass opts.light(nx, ny, nz) to use your own.

Textures

The textures come from OSM2World's default style, scaled down for games by tools/import_style.py. Most are from ambientCG (CC0); others come from the OSM Wiki Texture Library (public domain). The style's own textures and settings are CC0. The full list is in textures/SOURCES.md.