FME Version
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 could 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 combining of all the necessary sources into such a cloud. Below we go in depth into one example of making a Minecraft world.
Important to Know
World Size
An important thing to consider 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 much time as it would take in reality. With regard to elevation, we are limited by the range allowed by Minecraft in version 1.7, which goes from altitude 1 to altitude 256. Taking into account that sea level in Minecraft is at altitude 63, we usually want to scale everything, even the highest mountains, to fit into the range between 63 and 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 have to find out whether there are any extra requirements imposed by the block 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 on 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 through the blockData component and requires some extra analysis with FME.
For some purposes, the real nature of the blocks can be unimportant, and the main role plays their color or look. 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 RasterBandSelector. 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 the 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 divisibles of 16, and make a bounding box around the world as follows:
When we do so, we should turn off the option "Center Point Cloud at 0,0" on 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 find the number of rows in the raster with the RasterPropertyExtractor, and then use this number in the RasterGeoreferencer.
We also made the elevation range 10 times smaller with the RasterExpressionEvaluator, so the highest hill goes up to 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 as the Generalization Tolerance, and leave the rest of the parameters as the default.
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 onto 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 have the format set to CSV, set the file path to the statues.csv, and the feature type to read is 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 CSV output port of the FeatureReader. Have the Mode set to Replace with Point and the X and Y Values set 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 as default.
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 of Part 4, leave all the parameters as default. 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 to Automatic. Leave the rest of the parameters as default.
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 Joined output port of the FeatureJoiner. 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 all around the island, we can turn them into point clouds with a PointCloudCombiner in the next step after we have added the various block components necessary.
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 because that is the version that the writer writes to.
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 PointCloudComponenentAdder. Set the Z Offset to 1 and leave the rest of the parameters as 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 PointCloudComponenentAdders and the Offsetter. Leave all of the parameters as 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 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, make a perfect tunnel using the transparency of the glass, and then replace it with the stone.
Change Detection
The regularity of the blocks in Minecraft worlds allows an easy change detection. 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, a Requestor and Supplier, can be matched by any number of coordinates and/or other components. This outputs the matches through a Merged port, no matches through a NotMerged port, and for the supplier we have 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 data made at Safe Software, the SRTM data from NASA, and the 3DWarehouse.
Comments
0 comments
Please sign in to leave a comment.