HomeWildfire Games

Implement SmoothingPainter for random maps, fixes #5027.

Description

Implement SmoothingPainter for random maps, fixes #5027.

This allows only specific regions of the map to be smoothened, especially important on imported digital elevation models.
It uses the Inverse Distance Weighting / Shepard's method as mentioned by Imarok and formerly implemented in the Pyrenean Sierra map by wraitii in rP12248.

Supersedes the globalSmoothHeightmap function in FeXoRs heightmap library, refs #3764.
Drop the heightmap argument to be consistent with the other painters.
If painting on arbitrary heightmaps is wished, the createArea mechanism, all Placers, Painters, Constraints and Areas can and should support that.

Update the HeightmapPainter from rP21133 to not break if TILE_CENTERED_HEIGHT_MAP is enabled (i.e. numVertices = numTiles), refs #5018.
Use that mode on Mediterranean and Red Sea.
Drop the disabling of bicubic interpolation in the HeightmapPainter instead of extending it to this feature.

Inevitable smoothing performance improvement for Belgian Uplands (from 45 to 15 seconds per call), even if it implies a somewhat different outcome, refs #5011.

Details

Committed
elexisFeb 11 2018, 3:56 PM
Parents
rP21174: Merge the structree's loadUnit and loadStructure functions
Branches
Unknown
Tags
Unknown
Build Status
Buildable 4920
Build 8512: Post-Commit BuildJenkins

Event Timeline

From testing it seems that size and iterations yield almost undistinguishable results.
So we might consider dropping (at most) one of the two parameters.

Originally I only migrated the globalsmoothing function from heightmap.js which comes with size = 1 and less complexity:

SmoothingPainter.prototype.paint = function(area)
{
	//let neighboringCoordinates = this.radius = this.g_AdjacentCoordinates ? 

	for (let i = 0; i < this.iterations; ++i)
	{
		let heightmap = clone(g_Map.height);

		// Additional complexity to process all 4 vertices of each tile, i.e the last row too
		let seen = new Array(g_Map.height.length).fill(0).map(zero => new Uint8Array(g_Map.height.length).fill(0));

		for (let point of area.points)
			for (let tileVertex of g_TileVertices)
			{
				let vertex = Vector2D.add(point, tileVertex);
				if (!g_Map.validHeight(vertex) || seen[vertex.x][vertex.y])
					continue;

				seen[vertex.x][vertex.y] = 1;

				// Add weighted height of adjacent vertices
				for (let brushPoint of this.brushPoints)
				{
					let adjacent = Vector2D.add(vertex, brushPoint);
					if (g_Map.validHeight(adjacent))
						g_Map.height[vertex.x][vertex.y] += this.strength / g_TileVertices.length * (heightmap[adjacent.x][adjacent.y] - heightmap[vertex.x][vertex.y]);
				}
			}
	}
};