Home

Awesome

<h1 align="center"> TerraBrush <br> </h1> <h4 align="center">A minimal Terrain heightmap editor for <a href="https://godotengine.org/" target="_blank">Godot engine 4.3</a></h4> <p align="center"> <a href="https://godotengine.org/"> <img src="https://img.shields.io/badge/GODOT-%23000000.svg?style=for-the-badge&logo=godot-engine" alt="Godot"> </a> </p> <div align="center">

DisclaimerKey FeaturesHow To UseSupportLicense

</div> <div align="center">

screenshot

</div>

Disclaimer

This project has been made mainly for my own project. I'm pretty new to gamedev so if something is not done the way it should, feel free to contact me! <br> I'm happy to share it with the community but it's possible that some features that you would expect are not there. <br> I'm gonna be happy to accept PR for new features if it fits.

Godot 4.2 and lower (4.x)

The demo scene has been updated to Godot 4.3 which makes it break with older version of Godot.

Key Features

How To Use

Watch the tutorial video! https://youtu.be/n5WeAqeea1c

Note Make sure you have the .Net version of Godot Engine.

Clone this repository - If you only want to try out the demo scene, you can run this project in Godot directly. Else, copy the folder "addons/terrabrush" to your "addons" folder.

# Clone this repository
$ git clone https://github.com/spimort/TerraBrush

Add a C# Solution - To make sure that your project has C# enabled, go under "Project->Tools->C#->Create C# Solution".

Compile - It's really important to compile using this icon image so Godot can run the plugin.

Enable the plugin - When the game has been compiled once, you should be able to enable the plugin. To do that, go under "Project->ProjectSettings->Plugins" and enable the checkbox next to TerraBrush.

Add the node - To add a terrain node, in the "Add node" screen, search for "Node3D->TerraBrush" (image)

Update the terrain

Some properties of the node require the terrain to refresh (mainly for the shaders and stuff). If something does not refresh, hit that "UpdateTerrain" button! <br> For example, if you add a new texture, add foliage, add an object, add a water definition or add snow, you'll have to hit the "UpdateTerrain" button.

Node properties

PropertyDescription
Terrain Settings
Zones SizeThis is the size of the zones (in meters). By default, it will be 256m. There is no limit for this value but having a really high value will decrease the performance. Each zone will be created with this size.
Data PathIn order to work, TerraBrush needs to have somewhere to store some files. Make sure the option for "Data Path" is filled. If possible, the tool will fill in information by itself.
Collision OnlyThis option is useful for running for example a Game Server. This will only create the collisions of the terrain (the packed scenes will also be created since they could have a collision shape)
Visual Instance LayersThe godot layer on which the terrain will be displayed.
Custom ShaderAllow you to use a custom shader for the terrain.
Create TerrainCreate the terrain with the current settings (everything that has been done will be cleared).
Update TerrainUpdate the terrain with the current settings (it will keep everything that has been painted). This option is useful if you modify something that has a direct impact on the map (ex. Add a new texture, foliage, packed scenes, etc.).
Remove TerrainRemove the current terrain (everything that has been done will be cleared).
Lock all terrainLock all parts of the current Terrain.
Unlock all terrainUnlock all parts of the current Terrain.
LOD
LOD LevelsThe number of levels the clipmap will be made of. The default value is 5.
LOD Rows Per LevelThe number of rows per level. This is a base number, depending on the level, there might be more rows (ex. the first level is a little bit different so it has more cells). The default value is 101.
LOD Initial Cell WidthThe initial size of the cell. Each level will double the size of the previous level cell' size. the default value is 1.0 (1 meter)
Collisions
Create Collision In ThreadCreate the collision shape in a thread. This helps a lot when editing the terrain. This also means that the collision could appear late compared to the terrain. The default value is true.
Collision LayersThe terrain collision layers
Collision MaskThe terrain collision mask
Textures
Texture SetsLet you define the textures of the terrain. Be aware, that all the textures must be in the same format (ex. Mipmaps, compression mode, etc.). Make sure to hit the update terrain button when you modify this and the terrain has already been created. You should create a TextureSetsResource which holds several TextureSetResource. A set will accept an Albedo, Normal and Roughness texture. You can create a resource file with the TextureSetsResource so you can reuse your textures with other terrain.
TextureSetResource[x].NameThe name of the texture. This information is useful when you want to query the terrain to know the texture at a specific position.
TextureSetResource[x].AlbedoTextureThe albedo texure of the set.
TextureSetResource[x].NormalTextureThe normal map texture of the set.
TextureSetResource[x].RoughnessTextureThe roughness texture of the set.
TextureSetResource[x].TextureDetailThis will determine how often your texture will be repeated on the terrain. A higher value means more repetitions. The default value is -1 to take the global TextureDetail of the terrain.
Texture DetailThis will determine how often your textures will be repeated on the terrain. A higher value means more repetitions. The default value is 20.
Use Anti TileThis will determine if the textures will use an Anti Tile algorithm.
Height Blend FactorThe intensity (contrast) of the texture blending when using heightmaps/bumpmaps. 0 will use classic linear blending. The default value is 10. Negative or exaggerated values may produce interesting artistic effects.
Nearest Texture FilterUse nearest texture filter instead of linear filter.
Albedo Alpha Channel UsageAllow the use of the alpha channel of the albedo texture for either roughness or height. The default value is none.
Normal Alpha Channel UsageAllow the use of the alpha channel of the normal texture for either roughness or height. The default value is none.
Foliage
FoliagesAn array of FoliageResource. Make sure to hit the update terrain button when you modify this and the terrain has already been created.
FoliageResource[x].DefinitionThe definition of the foliage. Create a FoliageDefinitionResource to use it. You can create a resource of this definition to reuse it in other terrain.
FoliageResource[x].Definition.StrategyThe strategy used to generate the foliage (MultiMesh or GPUParticles). The default value is MultiMesh.
FoliageResource[x].Definition.MeshThe mesh that will be used for the foliage. The mesh should have as few vertices as possible for better performance.
FoliageResource[x].Definition.MeshScaleThe scale of the mesh.
FoliageResource[x].Definition.WindStrengthCreates some movement for the mesh. The default value is 0.1.
FoliageResource[x].Definition.NoiseTextureThis texture makes sure that the foliage placement is not too straight. If not specified, the default noise texture will be used.
FoliageResource[x].Definition.VisualInstanceLayersThe godot layer on which the foliage will be displayed.
FoliageResource[x].Definition.LODLevels(MultiMesh only) The number of levels the clipmap will be made of. The default value is 3.
FoliageResource[x].Definition.LODRowsPerLevel(MultiMesh only) The number of rows per level. This is a base number, depending on the level, there might be more rows (ex. the first level is a little bit different so it has more cells). The default value is 50.
FoliageResource[x].Definition.LODInitialCellWidth(MultiMesh only) The initial size of the cell. Each level will double the size of the previous level cell' size. the default value is 1.0 (1 meter)
FoliageResource[x].Definition.Albedo(MultiMesh only) The base color of the mesh. The default value is white
FoliageResource[x].Definition.AlbedoTextures(MultiMesh only) A set of textures that will be chosen randomly for each instance.
FoliageResource[x].Definition.UseGroundColor(MultiMesh only) If true, the color of the ground, depending on the position of the mesh, will be sent to the COLOR uniform and then to the color of the mesh. The default value is false.
FoliageResource[x].Definition.CastShadow(MultiMesh only) If true, the shadow will be enabled on the multimesh. The default value is false.
FoliageResource[x].Definition.UseBrushScale(MultiMesh only) If true, the more you paint at a specific location, the bigger the foliage will be (on a range of 0.0 to 1.0). The default value is true.
FoliageResource[x].Definition.ScaleNoiseTexture(MultiMesh only) A texture to help get various height on the foliage.
FoliageResource[x].Definition.RandomPlacementRange(MultiMesh only) A value that helps place randomly each mesh instance. The position will be between -RandomPlacementRange to RandomPlacementRange from the center of the original position in the clipmap. This helps blend each layers of the clipmap. The default value is 3.0.
FoliageResource[x].Definition.ApplyOnTextureIndexes(MultiMesh only) A list of texture indexes where foliage should be applied.
FoliageResource[x].Definition.CustomShader(MultiMesh only) A custom shader for the foliage.
FoliageResource[x].Definition.MeshMaterial(GPUParticles only) The material that will be used on the mesh.
FoliageResource[x].Definition.MaximumRenderDistance(GPUParticles only) This is the maximum distance the foliage will appear from the camera. A high value will decrease the performance.
FoliageResource[x].Definition.EditorMaximumRenderDistance(GPUParticles only) This is the maximum distance the foliage will appear from the camera, but only for the editor. A high value will decrease the performances. Useful if you want to see far.
Objects
Default Object FrequencyThis option is to define how often the objects will be placed on the terrain. This is the default for every objects. For example, a value of 10 will place an object every 10 meters. The default value is 10.
Object Loading StrategyDrives how the objects are being loaded (in a thread or not). The default value is ThreadedInEditorOnly.
ObjectsAn array of ObjectResource. Make sure to hit the update terrain button when you modify this and the terrain has already been created.
ObjectResource[x].DefinitionThe definition of the object. Create a ObjectDefinitionResource to use it. You can create a resource of this definition to reuse it in other terrain.
ObjectResource[x].Definition.StrategyThis option lets you choose between instancing packed scenes or using multimeshes for the objects.
ObjectResource[x].Definition.ObjectFrequencyThis option overrides the Default Object Frequency property if a value higher than -1 is set. This option is to define how often the objects will be placed on the terrain. For example, a value of 10 will place an object every 10 meters. The default value is 10.
ObjectResource[x].Definition.RandomRangeThe range from which the random placement will be added from the original grid position.
ObjectResource[x].Definition.NoiseTextureThis texture makes sure that the object placement is not too straight. If not specified, the default noise texture will be used.
ObjectResource[x].Definition.RandomYRotationThis allows the objects to be rotated randomly on the Y axis.
ObjectResource[x].Definition.ObjectScenesA list of packed scenes. A random one will be selected while painting.
ObjectResource[x].Definition.LODList(MultiMeshes only) The list of LOD for the objects.
ObjectResource[x].Definition.LODMeshes(MultiMeshes only) The list of meshes used with the LODList.
ObjectResource[x].Definition.UpdateDistanceThreshold(MultiMeshes only) This sets the movement threshold before we need to check if the objects are changing LOD.
ObjectResource[x].Definition.UpdateTimeFrequency(MultiMeshes only) This sets how often we check if the movement threshold has been reached.
ObjectResource[x].Definition.VisualInstanceLayers(MultiMeshes only) The visual layers used with the MultiMeshes.
ObjectResource[x].HideHide the whole layer of objects. This is useful when you want to see something on the terrain and the objects block the view.
Water
Water DefinitionThe definition of water. Create a WaterResource to use it. You can create a resource of this definition to reuse it in other terrain. Make sure to hit the update terrain button when you modify this and the terrain has already been created.
WaterResource.WaterFactorThis option lets you decide how deep the deepest water will be. A value of 1 will set the maximum deepness to 1m. The default value is 1.
WaterResource.WaterInnerOffsetThis is an offset of the water going into the ground. The goal is to prevent having square-looking water edges.
WaterResource.WaterColorThe color of the water.
WaterResource.WaterFresnelColorThe color of the fresnel reflection color.
WaterResource.WaterMetallicThe metallic value of the material.
WaterResource.WaterRoughnessThe roughness value of the material.
WaterResource.NormalMapThis is a normal map to create some waves in the water.
WaterResource.NormalMap2This is another normal map to create some waves in the water. Having two normal maps helps to create better movement. Make sure it is different from the first one.
WaterResource.WaterTimeScaleThis is how fast the water will move.
WaterResource.WaterStrengthThis is how fast the normal map will move.
WaterResource.WaterWaveThe Water Wave image is a noise texture that lets you drive how the waves will look like.
WaterResource.WaterNoiseScaleThe scale of the noise texture.
WaterResource.WaterHeightScaleThe height of the water waves created by the noise texture.
WaterResource.WaterColorDeepThe color of the deep water.
WaterResource.WaterColorShallowThe color of the Shallow water.
WaterResource.WaterBeersLawThis option sets the beer law for the water.
WaterResource.WaterDeepOffsetThis option sets how to calculate that the water is considered "Deep".
WaterResource.WaterEdgeScaleThis option sets the size of the "foam" on the edges of the water.
WaterResource.WaterNearThis option sets how to calculate whether the water is close or not for the "foam".
WaterResource.WaterFarThis option sets how to calculate whether the water is close or not for the "foam".
WaterResource.WaterEdgeColorThis is the color of the "foam".
WaterResource.VisualInstanceLayersThe godot layer on which the water will be displayed.
WaterResource.CustomShaderA custom shader for ther water.
Snow
Snow DefinitionThe definition of the snow. Create a SnowResource to use it. You can create a resource of this definition to reuse it in other terrain. Make sure to hit the update terrain button when you modify this and the terrain has already been created.
SnowResource.SnowFactorSets how thick the snow will be.
SnowResource.SnowInnerOffsetThis option is to decide the offset that the snow will get into the ground. This is to avoid having square edges of the snow.
SnowResource.SnowColorTextureThis sets the albedo texture that will be used for the snow.
SnowResource.SnowColorNormalThis sets the normal map texture that will be used for the snow.
SnowResource.SnowColorRoughnessThis sets the roughness texture that will be used for the snow.
SnowResource.SnowColorDetailThis is to define how often the texture will be repeated.
SnowResource.NoiseThe noise option allows the terrain to change shape a little bit to avoid having too straight a texture.
SnowResource.NoiseFactorThis option defines how much the noise will affect the snow.
SnowResource.MetallicThis is the metallic value of the material.
SnowResource.VisualInstanceLayersThe godot layer on which the snow will be displayed.
SnowResource.CustomShaderA custom shader for the snow.
Zones
Zones[x].ZonePositionThe position of the zone. This position is multiplied by the zone's size to position it in the world. The zones can be disconnected from each other. Make sure to hit the update terrain button when you modify this and the terrain has already been created
Zones[x].HeightMapTextureUnless you want to reuse an existing heightmap, leave this option to null. The tool will create it by itself.
Zones[x].SplatmapsTextureUnless you have existing splatmaps, leave this option empty, the tool will create them by itself.
Zones[x].FoliagesTexture[x]Unless you have existing foliage painting, leave this option empty, the tool will create it by itself.
Zones[x].ObjectsTexture[x]Unless you have existing object painting, leave this option empty, the tool will create it by itself.
Zones[x].WaterTextureUnless you have existing water painting, leave this option empty, the tool will create it by itself.
Zones[x].SnowTextureUnless you have an existing snow painting, leave this option empty, the tool will create it by itself.

Node Signals

Signal NameDescription
TerrainLoadedOccurs when the terrain is done loading all the different components.

Interact with the terrain

To interact with the terrain (for example, to make water ripple), you can call the function AddInteractionPoint on the TerraBrush node. This function requires an x and y position, corresponding to the x and y coordinates on the map, in meters. <br> To retrieve information from the map (for example, to get what texture the player is on), you can call the function GetPositionInformation on the TerraBrush node.

These two functions can be called from GDScript and C#.

C# Snippet

// Let's assume we have a variable called "TerraBrush" that is a TerraBrush Node.
// Let's validate that we are on the ground
if (IsOnFloor() && GetLastSlideCollision() != null) {
    // Get the current collision
    var collision = GetLastSlideCollision();

    // Let's make sure the collider is the collider of the Terrain
    if (collision?.GetCollider() == TerraBrush?.Terrain?.TerrainCollider) {
        // The variable playerX and playerZ are the variables for the global position of the player
        var result = TerraBrush.GetPositionInformation(playerX, playerZ);
        // If we don't get a result, it means we are out of the terrain
        if (result != null) {
            // The texture at position 0 is the most present one
            var mainTexture = result.Textures?.Length > 0 ? result.Textures?[0].Name : "";

            // Do something with the mainTexture information
            ...
        }
    }
}

GDScript Snippet

# Let's assume we have a variable called "%TerraBrush" that is a TerraBrush Node.
# Let's validate that we are on the ground
if is_on_floor() and get_last_slide_collision() != null:
    # Get the current collision
    var collision = get_last_slide_collision()

    # Let's make sure the collider is the collider of the Terrain
    if collision.get_collider() == %TerraBrush.Terrain.TerrainCollider:
        # The variable playerX and playerZ are the variables for the global position of the player
        var result = %TerraBrush.GetPositionInformation(playerX, playerZ)
        # If we don't get a result, it means we are out of the terrain
        if result != null:
            # The texture at position 0 is the most present one
            var mainTexture = result.Textures[0].Name if result.Textures.size() > 0 else ""
            # Do something with the mainTexture information
            ...

Navigation mesh

In order to use a navigation mesh, make sure to set the Parsed Geometry Type to Static Colliders in your navigation mesh.

Support

You want to support my work?

ko-fi

Demo credits

Trees: https://www.turbosquid.com/3d-models/3d-shapespark-low-poly-plants-kit-1826978 <br> Grass: https://opengameart.org/content/stylized-grass-and-bush-textures-0 <br> Textures: https://ambientcg.com/

License

MIT


Youtube @spimortdev  ·  Twitter @spimortdev