Terrain
Gorilla3D provides a simple terrain component for generation from height-map image. Besides the default usage, different procedural builders are available: diamond square, mandelbrot, perlin-noise (linear, cosine and cubic), plateau algorithms. The resolution / number of vertices is configurable.
For detailed information about the component and its methods, check out: Gorilla.Terrain
DesignTime
You can generate a terrain at design time by different ways.
From Heightmap
- Drop a TGorillaTerrain component onto your GorillaViewport
- Select the TGorillaTerrain instance
- Go to “Heightmap” property in object inspector
- Open the editor dialog and load a 2D image from file
- The heightmap will be stored inside the IDE formular file (*.fmx)
Autogenerate with Editor
When you select your TGorillaTerrain component in structure view of the IDE, you can right click onto and a popup will show.
Here you can select between the embedded procedural terrain generation algorithms.
Choose one of the “Random Terrain <ALGORITHM>” options.
After you have clicked, you need to click into the viewport in your form to refresh rendering.
Planting
The framework brings you a great feature called “Planting” to the terrain component.
After you have loaded a terrain from heightmap or by procedural generation, you can use this functionality.
It will need another TGorillaModel component as template and will perform an instancing onto the selected terrain.
This means all instances will automatically be adjusted to the shape of the terrain.
When clicking the “Planting” option a new dialog will open where you can configure some settings for the planting algorithm.
Configuration
The algorithm will create instances for all meshes inside the selected template / source model.
Basically the algorithm splits the terrain into cells for more realistic placement.
Setting | Description |
---|---|
Clear Instances | Clears all previously available instances in the source. |
Minimum Scale | If “Random Scaling” is activated, this is the lowest limit for scaling. |
Instance Scale | A basis scaling of each instance (will be multiplied with source scale if “Apply Source Transformation” is activated. |
Space | Adjustment between cell-center and source size. |
Padding | Increasing this value will compress cells for planting. Objects will be placed closer together. |
Random Y-Rotation | This is not suitable for all kind of source models. Depending on the internal transformation of submeshes. |
Random Scaling | This will randomly scale instances with limitations given by “Minimum Scale”. |
Apply Random Grid-Offset | Terrain is splitted into equal size grid cells. To produce a more realistic look, you can add some random offset to the cell-center. |
Apply Source Transformation | It will apply the transformation of the owner model. This is not suitable for all kind of models, depending on the internal transformation of submeshes. |
Count | The number of instances that should be created. This should be adjusted to the GPU you are using and the outcome you expect. |
Source Models
The planting algorithm is straight forward and treats all submeshes inside the source model equaly on creating instances.
Therefore it can produce unexpected results.
The source model should contain a flat hierarchy without or less transformation of sub-meshes.
NOTICE: The applied instance transformation is absolute and not relative to the source model!
Runtime
From Heightmap
- Form1.pas
uses Gorilla.Terrain, Gorilla.Material.Lambert; procedure TForm1.FormCreate(Sender: TObject); var LTexturePath : String; begin LTexturePath := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))); FTerrain := TGorillaTerrain.Create(fGorilla); FTerrain.Parent := FGorillaViewport; // set resolution of terrain to 256 x 256 sections // this generates 65.536 cells with 131.072 triangles and 393.216 vertices. FTerrain.ResolutionX := 256; FTerrain.ResolutionY := 256; // here we load the height map image FTerrain.HeightMap.LoadFromFile(LTexturePath + 'terrain-h.jpg'); // adjust terrain size and scaling FTerrain.HeightScale := 10; FTerrain.Scale.X := 100; FTerrain.Scale.Y := 10; FTerrain.Scale.Z := 100; // build terrain mesh from previously loaded heightmap // 1st param: static buffering for large number of vertices. // 2nd param: decimation disabled FTerrain.RebuildTerrain(true, false); // apply a material as texture to it FTerrainMaterial := TGorillaLambertMaterialSource.Create(FTerrain); FTerrainMaterial.Parent := FTerrain; FTerrainMaterial.Texture.LoadFromFile(LTexturePath + 'terrain-c.jpg'); FTerrain.MaterialSource := FTerrainMaterial; end;
Procedural Generation
- Form1.pas
uses Gorilla.Terrain, Gorilla.Material.Lambert; procedure TForm1.FormCreate(Sender: TObject); var LTexturePath : String; begin LTexturePath := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))); FTerrain := TGorillaTerrain.Create(fGorilla); FTerrain.Parent := FGorillaViewport; // set resolution of terrain to 256 x 256 sections // this generates 65.536 cells with 131.072 triangles and 393.216 vertices. FTerrain.ResolutionX := 256; FTerrain.ResolutionY := 256; // adjust terrain size and scaling FTerrain.HeightScale := 10; FTerrain.Scale.X := 100; FTerrain.Scale.Y := 10; FTerrain.Scale.Z := 100; // build a random terrain by a predefined procedural algorithm FTerrain.RandomTerrain(TRandomTerrainAlgorithmType.DiamondSquare); // apply a material as texture to it FTerrainMaterial := TGorillaLambertMaterialSource.Create(FTerrain); FTerrainMaterial.Parent := FTerrain; FTerrainMaterial.Texture.LoadFromFile(LTexturePath + 'terrain-c.jpg'); FTerrain.MaterialSource := FTerrainMaterial; end;
NOTICE: Once you build a random terrain, you are able to store the heightmap bitmap and reload later.
Terrain-Algorithms
Algorithm | Notice |
---|---|
Hill | A basic procedural hill algorithm. The algorithm will produce smooth hills by radius settings and a given count. |
DiamondSquare | A very popular algorithm to build random terrain. The algorithm creates randomly lows and highs for a realisic terrain. |
Mandelbrot | Creates the typical mandelbrot pattern: https://en.wikipedia.org/wiki/Mandelbrot_set This is a fixed result, but you could use this as basis for further computation. |
PerlinNoise | Perlin noise terrains are a good choice for random terrain. The component provides different mathmatical interpolation methods (linear, cosine, cubic). |
Plateau | A plateau terrain is described by a specific number of high and flat areas, while the rest is much lower. The algorithm extends the TDiamondSquareTerrain. |
Brownian | Brownian terrains or brownian surface is based on the diamond square based terrain algorithm: https://en.wikipedia.org/wiki/Brownian_surface The component computes peaks by a specific number of random particles. Afterwards the complete terrain will be smooth to create a realistic landscape. |
Creating an individual procedural terrain algorithm
You can also develop your own procedural algorithm by extending TRandomTerrainAlgorithm or any descendant. In the example below, we generate a random terrain:
- MyTerrainAlg.pas
type TMyTerrainAlgorithm = class(TRandomTerrainAlgorithm) protected procedure Generate(); public function GetHeightMap() : TBitmap; override; end; { TMyTerrainAlgorithm } procedure TMyTerrainAlgorithm.Generate(); var x, z: Integer; i : Integer; begin System.SetLength(FData, 256); for i := 0 to High(FData) do System.SetLength(FData[i], 256); for x := 0 to 255 do for z := 0 to 255 do begin FData[x, z] := Random(100) / 100; end; end; function TMyTerrainAlgorithm.GetHeightMap() : TBitmap; begin Generate(); result := inherited; end; LMyTerrainAlgorithm := TMyTerrainAlgorithm.Create(); try FTerrain.RandomTerrain(LMyTerrainAlgorithm); finally FreeAndNil(LMyTerrainAlgorithm); end;
Resolution
It is recommend to use 2 ^ X resolution sizes for your terrain. Set resolution by the published properties “ResolutionX” and “ResolutionY”.
The table below lists common terrain sizes and their resulting vertices.
Size | Vertex-Count | Index-Count | Triangles | Memory-Size |
---|---|---|---|---|
16 x 16 | 289 | 1536 | 512 | 26.952 Bytes |
32 x 32 | 1089 | 6144 | 2048 | 102.984 Bytes |
64 x 64 | 4225 | 24.576 | 8192 | 402.504 Bytes |
128 x 128 | 16.641 | 98.304 | 32.768 | 1.591.368 Bytes |
256 x 256 | 66.049 | 393.216 | 131.072 | 6.328.392 Bytes |
512 x 512 | 263.169 | 1.572.864 | 524.288 | 25.239.624 Bytes |
1024 x 1024 | 1.050.625 | 6.291.456 | 2.097.152 | 100.810.824 Bytes |
2048 x 2048 | 4.198.401 | 25.165.824 | 8.388.608 | 402.948.168 Bytes |
Notice: When using terrain on Android, remember the 16-Bit vertex and index limitation. You are allowed to use at max 65536 indices per mesh on Android systems.
Smoothing
In case you are using a height-map smaller than your terrain-resolution, the resulting terrain could show some unlovely steps. Therefore the component provides the published “Smoothing” property. Set a value between 1 and 20 to apply smoothing algorithm onto your heightmap. A value of zero means that smoothing is deactivated.
Decimation
Due to optimization reasons the component provides an experimental decimation algorithm.
// 1st parameter - static buffering of vertex data // 2nd parameter - decimation algorithm execution FTerrain.RebuildTerrain(true, >>>true<<<);
Generating a procedural terrain by algorithm, activate decimation like this:
// 1st parameter - type of terrain algorithm // 2nd parameter - static buffering of vertex data // 3rd parameter - decimation algorithm execution FTerrain.RandomTerrain(TRandomTerrainAlgorithmType.DiamondSquare, true, >>>true<<<);
Next step: Skybox