Skip to content

Commit

Permalink
Fixed #1 (black tile issue) and drafted building model gen code
Browse files Browse the repository at this point in the history
  • Loading branch information
mattyoung101 committed Sep 18, 2023
1 parent 88193d9 commit e499ec9
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
package com.decosegfault.atlas.map

import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.VertexAttributes
import com.badlogic.gdx.graphics.g3d.Material
import com.badlogic.gdx.graphics.g3d.Model
import com.badlogic.gdx.graphics.g3d.ModelCache
import com.badlogic.gdx.math.DelaunayTriangulator
import com.badlogic.gdx.graphics.g3d.ModelInstance
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder
import com.badlogic.gdx.graphics.g3d.utils.shapebuilders.BoxShapeBuilder
import com.badlogic.gdx.math.MathUtils
import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.math.Vector3
import com.decosegfault.atlas.util.Triangle
import io.github.sebasbaumh.postgis.PGgeometry
import net.mgsx.gltf.scene3d.attributes.PBRColorAttribute
import org.postgresql.PGConnection
import org.postgresql.geometric.PGpolygon
import org.tinylog.kotlin.Logger
Expand Down Expand Up @@ -35,6 +44,12 @@ object BuildingGenerator {
/** Approximate height in metres of one storey. Source: https://en.wikipedia.org/wiki/Storey#Overview */
private const val STOREY_HEIGHT = 4.3f

/**
* The tallest building in Brisbane is currently the Brisbane Skytower which is 90 storeys tall
* We clamp building storeys to this many in case of OSM data misinputs so they're not mega tall
*/
private const val MAX_STOREYS = 90f

/**
* Query to find polygons and tags for OSM buildings in a bounding box. Assumes coordinates in Web
* Mercator (EPSG coord ID 3857), which is true for this osm2pgsql generated PostGIS DB.
Expand All @@ -49,6 +64,12 @@ object BuildingGenerator {
|AND building IS NOT NULL;
""".trimMargin()

private val BUILDING_COLOUR = Color.LIGHT_GRAY

private val BUILDING_MATERIAL = Material().apply {
set(PBRColorAttribute.createBaseColorFactor(BUILDING_COLOUR))
}

private lateinit var conn: Connection

/** Prepared statement consisting of [BUILDING_QUERY] */
Expand Down Expand Up @@ -117,12 +138,42 @@ object BuildingGenerator {
return buildings
}

/**
* Extrudes the given triangulated base of a building into a 3D model
* @param height height in metres
*/
private fun extrudeToModel(tris: List<Triangle>, height: Float): Model {
val modelBuilder = ModelBuilder()
val mpb = modelBuilder.part(
"building", GL20.GL_TRIANGLES,
VertexAttributes.Usage.Position.toLong() or VertexAttributes.Usage.Normal.toLong(),
BUILDING_MATERIAL
)
BoxShapeBuilder.build(mpb, 5f, height, 5f)
return modelBuilder.end()
}

/**
* Generates a building chunk. Buildings are packaged together into a ModelCache.
*/
fun generateBuildingChunk(chunk: Vector3): ModelCache {
fun generateBuildingChunk(buildings: Set<Building>): ModelCache {
val cache = ModelCache()
cache.begin()

for (building in buildings) {
// calculate the triangulation of the floor plan
val triangles = building.triangulate()

// limit the height of buildings in case of errors, and if a height is missing give a default
// height of 1 floor
val height = MathUtils.clamp(building.floors.toFloat(), 1f, MAX_STOREYS) * STOREY_HEIGHT

// extrude the triangulation into a 3D model and insert into cache
val model = extrudeToModel(triangles, height) // FIXME: memory leak here (need to free model)
val instance = ModelInstance(model)
cache.add(instance)
}

cache.end()
return cache
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.decosegfault.atlas.map

import com.badlogic.gdx.graphics.g3d.ModelCache
import com.badlogic.gdx.math.MathUtils
import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.math.Vector3
import com.decosegfault.atlas.util.AbstractGarbageCollectedCache
Expand Down Expand Up @@ -48,6 +49,9 @@ object GCBuildingCache : AbstractGarbageCollectedCache<Vector3, ModelCache>(
// now we have the actual list of buildings to process on this thread, register them
buildingAssignments[key] = buildings.toList()

// process buildings
val chunk = BuildingGenerator.generateBuildingChunk(buildings)

throw NotImplementedError()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ class SimulationScreen(private val game: Game) : ScreenAdapter() {
isDebugDraw = !isDebugDraw
} else if (Gdx.input.isKeyJustPressed(Input.Keys.RIGHT_BRACKET)) {
// forces tile cache GC
GCTileCache.garbageCollect(true)
GCTileCache.gcNextFrame()
} else if (Gdx.input.isKeyJustPressed(Input.Keys.ENTER)) {
// toggle fullscreen
if (Gdx.graphics.isFullscreen) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ abstract class AbstractGarbageCollectedCache<K, V : Disposable>(
private var hits = 0
private var misses = 0
private var total = 0
private var shouldGcNextFrame = false

/** Implementers should override this function to instantiate a new item. Can block for as long as you want. */
abstract fun newItem(key: K): V
Expand All @@ -72,7 +73,6 @@ abstract class AbstractGarbageCollectedCache<K, V : Disposable>(
*/
fun retrieve(item: K, onRetrieved: (V) -> Unit) {
val begin = System.nanoTime()
garbageCollect()
val maybeItem = cache[item]
if (maybeItem != null) {
// tile was already in cache
Expand Down Expand Up @@ -129,11 +129,23 @@ abstract class AbstractGarbageCollectedCache<K, V : Disposable>(
}
}

/** Clears items in use for the next frame */
/** Performs garbage collection and clears items in use for next frame */
fun nextFrame() {
if (shouldGcNextFrame) {
Logger.debug("Forcing GC this frame")
garbageCollect(true)
shouldGcNextFrame = false
} else {
garbageCollect()
}
itemsInUse.clear()
}

/** Tells the garbage collector to GC on the next frame */
fun gcNextFrame() {
shouldGcNextFrame = true
}

/** Tells the cache that the item is in use and should not be GCd */
fun markUsed(item: K) {
itemsInUse.add(item)
Expand Down
18 changes: 18 additions & 0 deletions docs/atlas_buildings_design.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,21 @@ database is entirely in Web Mercator coords, which is great for us. Sources:
**Extrusion**

TODO

**Coordinates**

Centre of Brisbane in Atlas is: `-27.410786,153.01758`

Convert to EPSG 3857 Web Mercator (from WGS84 to Web Mercator):
https://epsg.io/transform#s_srs=4326&t_srs=3857&x=153.0175800&y=-27.4107860

Yields: `x=17033839.088019006, y=-3174888.4441493554`

Subtract these from the PostGIS database to centre the buildings

---

random building web mercator: `17042011.25221322 -3178371.2622345123`

actual in game: `27370.577 11667.356`

0 comments on commit e499ec9

Please sign in to comment.