Files
Introduction
Mojang Minecraft was the first true gaming format added to FME. Unlike most other formats and standards made for serious uses by professionals, Minecraft appeals to a much wider, and often younger audience. Minecraft is more often used in professional settings in recent years because of the great spatial aspect. See the additional resources for use-case examples!
Windswept Forest Biome from Minecraft Wiki
Bringing real data into Minecraft allows turning a block-building game into a simple yet spectacular modeling tool where everyone can try all kinds of natural or urban scenarios. What if the sea level rises or falls by 100 meters? How quickly can a forest fire spread, and what are the consequences? What would happen if a sleeping volcano suddenly erupted? How might a Moai statue fit into the cityscape of our hometown? These questions can easily be answered with Minecraft.
FME is an excellent tool for bringing real data of any kind into Minecraft. Vector layers, rasters, point clouds, and 3D models can be transformed, adjusted, and aligned to the required size and position in the Minecraft world.
For FME, a Minecraft world is a regularly spaced point cloud, so the transformation task is essentially a combination of all the necessary sources into such a cloud. Below, we go in-depth into one example of making a Minecraft world.
Files
Additional files are available on the right-hand side of this article.
- data.zip (33.1 MB)
Important to Know
World Size
An important consideration at the beginning of world-making is its desired size. We may want to scale down the source map in order to make the world not too big. Otherwise, walking through such a world could take as long as it would in reality. With regard to elevation, we are limited by Minecraft's 1.7 range, which goes from altitude 1 to 256. Given that sea level in Minecraft is at 63, we usually scale everything, even the highest mountains, to fit within the range 63-256. For bathymetric maps and underground structures, we can go below 63, but not below 1.
Minecraft Blocks
Minecraft worlds are built from blocks. There are hundreds of block types in the game representing all kinds of stones and ores, water, trees and leaves, flowers, carpets, lava, glass, and so on. Internally, these blocks are identified by two components: blockID and blockData.
Below is a table showing Minecraft blocks. The numbers above the blocks represent blockID components, and the smaller indices beside them are blockData components. So, for example, "Grass" has blockID = 2, and no blockData component. "Birch Wood Planks" has blockID = 5 and blockData = 2.
Minecraft Wiki has a separate article about each block. The latest version of the blockID table can be found here
Each block has its own properties. When choosing a block, we need to determine whether there are any additional requirements imposed by the block's nature.
For example, vegetation blocks such as flowers or saplings will survive only on certain blocks underneath them, such as "Grass" or "Dirt". In FME, we can simply copy all the points of the vegetation blocks, elevate them by 1 block, and set the blockID of those remaining in their places to "Grass".
Rail blocks need to know where their neighbor rails are located; otherwise, they "will not know" how to orient themselves. This can be set via the blockData component and requires additional analysis in FME.
For some purposes, the real nature of the blocks may be unimportant, and their main role is their color or appearance. For example, we may want to create a physical 3D map of the world using traditional colors - dark to light blue for oceans, green through yellow and brown to white for continents:
In FME, there are several ways of setting blockID and blockData. If we already have a point cloud, the PointCloudComponentAdder or PointCloudExpressionEvaluator transformers can set these components directly (see the Easter Island example). We can create blockID and blockData attributes on vector features with the AttributeCreator transformer. Then, when the vectors are turned into a point cloud using the PointCloudCombiner, we should specify these attributes to be preserved as components in the lower section of the transformer's parameters:
For raster features, we have to select the necessary bands with the RasterSelector, set blockID and blockData as band names with the RasterBandNameSetter, and deselect all the bands with the RasterSelector. Then, when we combine a raster to a point cloud, these bands will become point cloud components.
Minecraft Chunks
The Minecraft writer writes the worlds for version 1.7 using whole chunks that are 16 blocks wide, 16 blocks long, and 256 blocks high. This means that if on the edge of our world we don't have a whole chunk, we end up with a hole going all the way down to the bottom of the world. A possible technique to avoid this is to add a few blocks to complete the chunks.
The coordinates of the chunks along X are as follows:
.........................
-32 to -17
-16 to -1
0 to 15
16 to 31
.........................
The coordinates of the chunks along Y are as follows:
.........................
-31 to -16
-15 to 0
1 to 16
17 to 32
.........................
We can buffer the whole world, extract coordinates, round them to multiples of 16, and make a bounding box around the world as follows:
When we do so, we should turn off the "Center Point Cloud at 0,0" option in the writer in the Navigation pane.
Then we would set the box to the desired Minecraft blockID and handle all other features that we are going to write to the world.
Step-By-Step Instructions
Here is our simple example. A raster DEM for Easter Island, and an OBJ file with two Moai statues.
Part 1: Process the DEM
The size of Easter Island is about 25 by 15 kilometers, and the highest elevation is above 500 meters. This means we need to make the island smaller to bring it to a reasonable size. For this purpose, we removed the original coordinate system from the DEM raster, where each pixel was over 27 meters, and used its pixel coordinates as its own coordinate system. The easiest way to do so is to use the RasterPropertyExtractor to find the number of rows in the raster, and then use that number in the RasterGeoreferencer.
We also reduced the elevation range by 10x using the RasterExpressionEvaluator, so the highest hill is only 50 meters. The downloadable example includes the modified raster, so these steps aren't required, but it is useful to know them.
1. Open FME Workbench
Open FME Workbench and click New to create a new workspace.
2. Add the DEM to the Canvas
The DEM is stored in a GeoTIFF file. Add a GeoTIFF reader to the canvas and browse to the Moai300.tif file, which can be downloaded from the Files section of this article.
3. Extract the Coastline
Once the DEM is read by FME, we extract the vector coastline from it with the RasterExtentsCoercer and generalize it - we will need this feature for statue orientation. Add a RasterExtentsCoercer, and connect it to the TIFF reader feature type. In the parameters, set the Extents Type to Data Extents. Next, add a Generalizer, and connect it to the RasterExtentsCoercer. In the parameters, set the Algorithm to Wang, 5 for Generalization Tolerance, and leave the rest at their defaults.
4. Raise to Sea Level
Now we will need to raise the sea level by 63, which is the Minecraft sea level. Add a RasterExpressionEvaluator to the canvas and connect it to the TIFF reader feature type. In the parameters, set the Mode to One Raster and the Interpretation to Preserve. The expression is A[0] + 63.
5. Make Surface Point Cloud
Add a PointCloudCombiner to make the surface point cloud, and connect it to the Result output port on the RasterExpressionEvaluator. Make sure to set the Point Interval to 1.0, set Extract Nodata to Yes, and leave the rest of the parameters as defaults.
6. Add a PointCloudFilter
Before going on to the next part, we want to make sure that the ground surface is filtered for the island and the ocean. This is important because Part 6 assigns information to these points.
Add a PointCloudFilter to the canvas and connect it to the PointCloudCombiner (from Part 1). Set the Expression to @Component(z)>63 and the Output Port to Island.
Part 2: Read Moai Statues
The 3D model contains only two statues, but we would like to place them several times around the island. For that, we created a CSV file with XY coordinates of the locations where we would like to see our statues.
1. Add the Moai Data
Add the Moai OBJ file to the canvas.
2. Read CSV and Create Points
Add a FeatureReader to the canvas and connect it to the Moai file. In the parameters, set the format to CSV, the file path to statues.csv, and the feature type to read as CSV. Expand Attribute and Geometry Handling, set the Accumulation Mode to Merge Initiator and Result, Conflict Resolution to Use Result, Ignore Nulls to No, and Geometry to Use Result. Add the VertexCreator to the canvas and connect it to the FeatureReader's CSV output port. Set the Mode to Replace with Point and the X and Y Values to col0 and col1, respectively.
Part 3: Make Draped Points
1. Drape Points to Surface
Once the statue locations are brought into FME, we’ll drape them onto the surface using the DEM. This adds the third coordinate (Z) to the locations. Add the SurfaceDraper to the canvas and connect the DrapeFeatures input port to the VertexCreator output, and the Points/Lines input port to the PointCloudCombiner output port (from Part 1). The parameters will be as follows:
- Surface Tolerance: 1
- Drape Method: Vertex
- Interpolation Method: Auto
- Existing Elevation: Replace Z
2. Calculate Direction by the Coastline
Then we use the NeighborFinder to find the closest segment of the coastline to each location point. Add a NeighborFinder to the canvas and connect the Base input port to the DrapedFeatures output port on the SurfaceDraper, then connect the Candidate input port to the Generalizer. In the parameters, set Replace Measures/Z with Candidate to No. The other parameters will be left at their default values.
3. Expose the Elevation (Z) Value
Add an AttributeManager to the canvas and connect it to the MatchedBase output port of the NeighborFinder. Create a new attribute called “z” and set the value to @ZValue().
Part 4: Joining Points to Statues
1. Create Attributes to Join
Add a Counter and a Cloner to the canvas. Connect the Counter to the AttributeManger in Part 4, and leave all the parameters at their default values. Connect the Cloner to the Moai OBJ file from Part 2. Set the Number of Copies to 17.
2. Join the Features
Add a FeatureJoiner to the canvas and connect the Left input port to the Counter and the Right input port to the Cloner. Set the Left attribute to _count and the Right attribute to _copynum; leave the Comparison Mode set to Automatic. Leave the remaining parameters at their defaults.
Part 5: Make Oriented Models from Points
1. Set the Statues to the Coordinates
Add an Offsetter to the canvas and connect it to the FeatureJoiner's Joined output port. Have the Mode set to Cartesian Coordinate, with the X Offset as col0, the Y Offset as col1, and the Z Offset as z. Click OK.
2. Rotate the Statues
Add a Rotator to the canvas and connect it to both the <Rejected> port and the Output ports of the Offsetter. Set the rotation angle to @Value(_angle)+90, and the x and y origin to _closest_base_x and _closest_base_y, respectively.
3. Make Model Point Cloud
Add a PointCloudCombiner to the canvas and connect it to the Rotator. Leave all the parameters as default.
Part 6: Set blockID and blockData
Now that we have the DEM raster ready and the statues placed around the island, we can turn them into point clouds with a PointCloudCombiner in the next step, after we have added the necessary block components.
1. Add Four PointCloudComponentAdders
Add four PointCloudComponentAdders to the canvas. Connect two of them to the Island output port of the PointCloudFilter; these will be the grass and podzol blocks. Connect one PointCloudComponentAdder to the <unfiltered> port of the PointCloudFilter for the ocean blocks. Connect the fourth PointCloudComponentAdder to the PointCloudCombiner output port for the moss stone of the statues. Labeling the PointCloudComponentAdders with annotations will help you in the next step.
2. Set the parameters for the PointCloudComponentAdders
For each point cloud, we will set the blockID and, in some cases, blockData components. See the table below to know which of the blockID and blockData you need for each PointCloudComponentAdder. Keep in mind that these codes are for Minecraft version 1.7, since that is the version the writer writes for.
| Component | Data Type | Value | |
|---|---|---|---|
| Grass | blockID | UInt8 | 31 |
| blockData | UInt8 | 1 | |
| Podzol | blockID | UInt8 | 3 |
| blockData | UInt8 | 2 | |
| Ocean | blockID | UInt8 | 8 |
| Moss Stone | blockID | UInt8 | 48 |
3. Raise Grass Over Ground (Podzol)
Add an Offsetter to the canvas and connect it to the grass PointCloudComponentAdder. Set the Z Offset to 1 and leave the other parameters at their defaults.
Part 7: Output
The last step before saving the world is combining all the point clouds into a single point cloud.
1. Make a Single Point Cloud
Add the PointCloudCombiner to the canvas. Connect all of the outputs from the last part to the input of the PointCloudCombiner; this includes the three PointCloudComponentAdders and the Offsetter. Leave all parameters at their defaults.
2. Save to Minecraft
Add a Mojang Minecraft writer to the canvas by typing freely on the canvas “minecraft” and selecting the writer. Choose a name and file path for your file.
The result saved as a Minecraft world can look as follows:
Please note that opening a world for the first time can take a while, so please be patient. Minecraft should go through all blocks and add some extra information to them.
Extras
Block Replacement
FME allows not only writing Minecraft worlds, but also reading them. Once read, the world becomes a simple point cloud with the usual XYZ coordinates and two components: blockID and blockData. Within FME, we can manipulate the world in many different ways.
For example, we can merge two or more worlds together, or add a new feature to the world - say, place a SketchUp model of your favorite cartoon hero in the center of your town. We can replace existing blocks with some other blocks, turn iron into gold, and a block of TNT into a pumpkin.
In our Kartverket example, we filled the space under the surface with glass blocks. It means that if we go under the surface, we will see through the inside of the hill. We can, for example, create a perfect tunnel using the glass's transparency, then replace it with stone.
Change Detection
The regularity of blocks in Minecraft worlds makes change detection easy. Using the freshly generated Kartverket world and the same world one day older, we can see what was added in 24 Minecraft hours. The PointCloudMerger transformer, which can take two point clouds (Requestor and Supplier), can be matched by any number of coordinates and/or other components. This outputs matches through a Merged port, no matches through a NotMerged port, and, for the supplier, Referenced and Unreferenced ports. The image below shows the FME Data Inspector visualization of the difference between two points in time:
Additional Resources
- MinecraftStyler Custom Transformer
- Building Norway in Minecraft with FME
- Minecraft Reader/Writer
- Example Minecraft Worlds Created with FME
Data Attribution
Data used in this tutorial originates from Safe Software, NASA SRTM data, and 3DWarehouse.