Jump to content

  • Log In with Google      Sign In   
  • Create Account






Hooking into the tree to build a map

Posted by JTippetts, 26 January 2011 · 1,958 views

In the last entry, I showed how you can chain together various noise functions, combiner functions, masks and RGB operations to create a colorful over-map of a procedural island, showing mountains and forests and grasslands. The neat thing about the approach of building the chain from implicit fractal functions is that you can make the tree of modules serve multiple duties. The previous technique would serve well to create, for example, the detailed mini-map of an overworld location. And by installing additional "hooks" that attach to the various masks and fractals that generate the features of your map, you can obtain the data that you need to make a real-level representation of the map. For example, here is today's updated module chain:

islandtree=
{
	-- The main shape of the continent is founded on a fuzzy disk
	{name="ContinentSphere", type="sphere", cx=0.5, cy=0.5, radius=0.5*0.75},
	{name="ContinentXTurb", type="fractal", fractal_type="FBM", basis_type="GRADIENT", interp_type="QUINTIC",
		frequency=3, num_octaves=10},
	{name="ContinentYTurb", type="fractal", fractal_type="FBM", basis_type="GRADIENT", interp_type="QUINTIC",
		frequency=3, num_octaves=10},
	{name="ContinentTurb", type="turbulence", main_source="ContinentSphere", x_axis_source="ContinentXTurb", y_axis_source="ContinentYTurb",
		x_power=0.2, y_power=0.2},
	
	{name="ContinentDisk", type="greyscale_implicitadapter", source="ContinentTurb", seamlessmode=ESM_NONE},
	
	-- Create a selection mask to outline the shape of the continent and blend between ocean floor and continent landforms.
	{name="GConstant0", type="greyscale_constant", constant=0},
	{name="GConstant1", type="greyscale_constant", constant=1},
	{name="ContinentMask", type="greyscale_select", main_source="ContinentDisk", low_source="GConstant0", high_source="GConstant1",
		threshold=0.3, falloff=0.15},
		
	-- Create a selection mask to define the shoreline
	{name="ShorelineMask", type="greyscale_select", main_source="ContinentDisk", low_source="GConstant0", high_source="GConstant1",
		threshold=0.15, falloff=0.01},
	
		
	-- Create a fractal for the ocean floor
	{name="OceanFloorFractal", type="greyscale_fractal", fractal_type="HYBRIDMULTI", basis_type="GRADIENT", interp_type="QUINTIC",
		num_octaves=8, frequency=6, remaprange=true, low=0, high=0.3},
	
	
	-- Create a fractal for mountains
	{name="MountainFractal", type="greyscale_fractal", fractal_type="FBM", basis_type="GRADIENT", interp_type="QUINTIC",
		num_octaves=10, frequency=22, remaprange=true, low=0.45,high=1},
		
	-- Create a fractal for rolling hills
	{name="RollingHillsFractal", type="greyscale_fractal", fractal_type="FBM", basis_type="GRADIENT", interp_type="QUINTIC",
		num_octaves=8, frequency=6, remaprange=true, low=0.25, high=0.45},
		
	-- Create a fractal mask to separate areas of mountain from areas of non-mountain
	{name="MountainMaskFractal", type="greyscale_fractal", fractal_type="FBM", basis_type="GRADIENT", interp_type="QUINTIC",
		num_octaves=8, frequency=6, remaprange=true, low=0, high=1},
	{name="MountainMask", type="greyscale_select", main_source="MountainMaskFractal", low_source="GConstant0", high_source="GConstant1",
		threshold=0.7, falloff=0.19},
		
	-- Create a blender to combine mountains with lower terrain
	{name="MountainLowlandBlend", type="greyscale_blend", main_source="MountainMask", low_source="RollingHillsFractal", high_source="MountainFractal"},
	
	
	-- Continent blend
	{name="ContinentBlend", type="greyscale_blend", main_source="ContinentMask", low_source="OceanFloorFractal", high_source="MountainLowlandBlend"},
		
		
	{name="ContinentBump", type="greyscale_bumpmap", source="ContinentBlend", sharpness=4, light={1.5,3.5,-1.5}},
	
	
	
	-- RGBA Modules
	{name="RGBAConstantBlueDark", type="rgba_constant", red=0.2, green=0.5, blue=0.9},
	{name="RGBAConstantBlueLight", type="rgba_constant", red=0.5, green=0.6, blue=1},
	{name="RGBAConstantGrey", type="rgba_constant", red=0.5, green=0.5, blue=0.5},
	{name="RGBAConstantWhite", type="rgba_constant", red=1,green=1,blue=1},
	{name="RGBAConstantBrown", type="rgba_constant", red=195/255, green=130/255, blue=46/255},
	{name="RGBAConstantGreen", type="rgba_constant", red=0.2, green=0.7, blue=0.1},
	{name="RGBAConstantDarkGreen", type="rgba_constant", red=0.1, green=0.5, blue=0.2},
	
	-- Create a stretched ridged multi fractal to setup a wave pattern
	{name="WaveRippleFractal", type="greyscale_fractal", fractal_type="FBM", basis_type="GRADIENT", interp_type="QUINTIC",
		num_octaves=3, frequency=12, mapx1=0, mapy1=0, mapx2=1, mapy2=5, remaprange=true, low=0, high=1},
	{name="WaveRippleBump", type="greyscale_bumpmap", source="WaveRippleFractal", sharpness=0.1, light={1.5,3.5,-1.5}},
	{name="WaveLightColor", type="rgba_combinealpha", greyscale_source="WaveRippleFractal", rgba_source="RGBAConstantBlueLight"},
	{name="WaveColor", type="rgba_blend", source1="WaveLightColor", source2="RGBAConstantBlueDark", blendop1=0, blendop2=2},
	
	{name="RGBAWavePattern", type="rgba_multrgbagreyscale", greyscale_source="WaveRippleBump", rgba_source="WaveColor"},
	
	-- Multiply the mountain elevation map by the mountain mask and the shoreline mask in order to get a "real" elevation map for
	-- adding snow to higher elevation mountains,, then set up a selection buffer and do a blend between grey and white
	{name="MountainFractalMultiply", type="greyscale_combiner", combiner_type=ECT_MULT, source_0="MountainFractal", source_1="MountainMask",
		source_2="ContinentMask"},
		
	{name="MountainSnowLineSelect", type="greyscale_select", main_source="MountainFractalMultiply", low_source="GConstant0", high_source="GConstant1",
		threshold=0.45, falloff=0.075},
		
	{name="MountainSnowLayer", type="rgba_combinealpha", greyscale_source="MountainSnowLineSelect", rgba_source="RGBAConstantWhite"},
	{name="MountainSnowBlend", type="rgba_blend", source1="MountainSnowLayer", source2="RGBAConstantGrey", blendop1=0, blendop2=2},
	
	-- Setup a fractal to blend between green and brown for lowland colors
	{name="LowlandBlendMask", type="greyscale_fractal", fractal_type="FBM", basis_type="GRADIENT", interp_type="QUINTIC",
		num_octaves=6, frequency=4, remaprange=true, low=0, high=1},
	{name="LowlandColorLayer", type="rgba_combinealpha", greyscale_source="LowlandBlendMask", rgba_source="RGBAConstantGreen"},
	{name="LowlandColorBlend", type="rgba_blend", source1="LowlandColorLayer", source2="RGBAConstantBrown", blendop1=0, blendop2=2},
	
	-- Setup a tighter version of the mountain mask
	{name="MountainColorMask", type="greyscale_select", main_source="MountainMaskFractal", low_source="GConstant0", high_source="GConstant1",
		threshold=0.5, falloff=0.15},
		
	-- Invert the mountain color mask, set up a forest fractal mask and multiply it by the mountain mask, ie no forest cover in mountains
	--{name="MountainColorMaskInvert", type="greyscale_remaprange", source="MountainColorMask", low=1, high=0},
	{name="MountainColorMaskInvert", type="greyscale_scaleoffset", source="MountainColorMask", scale=-1, offset=1},
	{name="ForestBlendMask", type="greyscale_fractal", fractal_type="FBM", basis_type="GRADIENT", interp_type="QUINTIC",
		num_octaves=6, frequency=6, remaprange=true, low=0, high=1},
	{name="ForestBlendMaskSelect", type="greyscale_select", main_source="ForestBlendMask", low_source="GConstant0", high_source="GConstant1",
		threshold=0.5, falloff=0.05},
	{name="ForestMask", type="greyscale_combiner", combiner_type=ECT_MULT, source_0="ForestBlendMaskSelect", source_1="MountainColorMaskInvert"},
	
	-- Setup a color blend layer for forest/lowland
	-- First, set up a bump source to make bumpy forest color
	{name="ForestBumpFractal", type="greyscale_fractal", fractal_type="FBM", basis_type="GRADIENT", interp_type="QUINTIC",
		num_octaves=8, frequency=64, remaprange=true, low=0, high=1},
	{name="ForestBump", type="greyscale_bumpmap", source="ForestBumpFractal", sharpness=1, light={1.5,3.5,-1.5}},
	{name="ForestColorBump", type="rgba_multrgbagreyscale", greyscale_source="ForestBump", rgba_source="RGBAConstantDarkGreen"},
	
	-- Now, blend in forest color
	{name="ForestColorLayer", type="rgba_combinealpha", greyscale_source="ForestMask", rgba_source="ForestColorBump"},
	{name="VegetationColorBlend", type="rgba_blend", source1="ForestColorLayer", source2="LowlandColorBlend", blendop1=0, blendop2=2},
	
	{name="RGBAMountainLayer", type="rgba_combinealpha", greyscale_source="MountainColorMask", rgba_source="MountainSnowBlend"},
	{name="RGBAMountainBlend", type="rgba_blend", source1="RGBAMountainLayer", source2="VegetationColorBlend", blendop1=0, blendop2=2},
	
	
	-- Blend between land colors and ocean colors using the shoreline mask
	{name="RGBALandMap", type="rgba_combinealpha", greyscale_source="ShorelineMask", rgba_source="RGBAMountainBlend"},
	{name="RGBACombineLandOcean", type="rgba_blend", source1="RGBALandMap", source2="RGBAWavePattern", blendop1=0, blendop2=2},
	
	-- Multiple the whole thing by the elevation bump-map
	{name="RGBACombineBump", type="rgba_multrgbagreyscale", greyscale_source="ContinentBump", rgba_source="RGBACombineLandOcean"},
	
	{name="RGBAAdapter", type="rgba_greyscaleadapter", source="MountainFractalMultiply"},
	{name="Output", type="output", source="RGBACombineBump", mode=0, width=512, height=512},
	
	
	
	
	-- Connectors for building tile maps
	
	-- Ocean/Land
	{name="OceanLandMapper", type="greyscale_select", main_source="ShorelineMask", low_source="GConstant0", high_source="GConstant1",
		threshold=0.5, falloff=0},
	
	-- Grass
	{name="GrassLayer", type="greyscale_select", main_source="LowlandBlendMask", low_source="GConstant0", high_source="GConstant1",
		threshold=0.5, falloff=0},
	{name="GrassMapper", type="greyscale_combiner", combiner_type=ECT_MULT, source_0="GrassLayer", source_1="OceanLandMapper"},
		
	-- Mountain Mask
	{name="MountainLayer", type="greyscale_select", main_source="MountainMaskFractal", low_source="GConstant0", high_source="GConstant1",
		threshold=0.5, falloff=0},
	{name="MountainMapper", type="greyscale_combiner", combiner_type=ECT_MULT, source_0="MountainLayer", source_1="OceanLandMapper"},
	{name="InverseMountainMapper", type="greyscale_scaleoffset", source="MountainMapper", scale=-1, offset=1},
		
	-- Mountain Steepness
	{name="MountainSteep", type="greyscale_bumpmap", source="MountainFractal", sharpness=2, light={0,1,0}},
	{name="MountainSteepLayer", type="greyscale_select", main_source="MountainFractal", low_source="GConstant1", high_source="GConstant0",
		threshold=0.65, falloff=0},
	{name="MountainSteepMapper", type="greyscale_combiner", combiner_type=ECT_MULT, source_0="MountainSteepLayer", source_1="MountainMapper"},
		
	-- Snow
	{name="SnowLayer", type="greyscale_select", main_source="MountainFractalMultiply", low_source="GConstant0", high_source="GConstant1",
		threshold=0.55, falloff=0},
	{name="SnowMapper", type="greyscale_combiner", combiner_type=ECT_MULT, source_0="SnowLayer", source_1="MountainMapper"},
	
	-- Forest
	{name="ForestLayer", type="greyscale_select", main_source="ForestMask", low_source="GConstant0", high_source="GConstant1",
		threshold=0.5, falloff=0},
	{name="ForestMapper", type="greyscale_combiner", combiner_type=ECT_MULT, source_0="ForestLayer", source_1="OceanLandMapper",
		source_2="InverseMountainMapper"}
	}

There are some changes to the tree (including some that make it incompatible with the previously uploaded build package), but the chief additions come at the end of the table in the form of various modules designated by the name suffix of Mapper. These are hooks that you can call directly to obtain maps from which you could build, for example, a tile map of the world. By using these mappers to populate your tile map, you obtain a representation of the level map, and in a single procedure you can generate both the detailed mini-map and the level data itself. Here is a basic example using small tiles, showing the detail map and the corresponding tile map:

Attached Image

(Tile Map, click to expand)
Attached Image


Because the fractals can be sampled at any resolution, it is entirely possible to generate as detailed a level map as needed. The example here samples the detail map to a 512x512 buffer, while the level map is sampled to a 64x64 tilemap, using tiles sized 32x32. Also, it generates the entire map, but in reality we can sample whatever sized map area we want, at whatever detail level we want. By sampling only a sub-range of the tree, we can generate a level from a small piece of the overmap, one that allows more and smaller level details.




PARTNERS