The paintcontext already handles this for you if you paint the terrain with it. https://docs.unity3d.com/ScriptReference/Experimental.TerrainAPI.PaintContext.html
The way i solved this for my own custom terrain system was:
- Created a Terrain_Grid class which has a hashmap that stores a reference to each terrain’s data where the key is the position of a tile in terrain space rounded to int. The step from world space to terrain space is easy to calculate. Just divide 1 by the size of the terrain for each axis.
Etc.: if the general terrain tile size = (1000, 1000, 1000), then the step from world to terrain space will be (1/1000, 1/1000, 1/1000).
The key is in terrain space to avoid floating point errors for when it’s time to retrieve a terrain tile by other classes.
Etc.: if the general terrain tile size = (1000, 1000, 1000) and a terrain tile has a position of (1000, 0, 1000) it’s hashmap key will be (1, 0, 1), if the tiles position is (-3000, 2000, 0), the key will be (-3, 2, 0).
- Created a custom class Terraformation which handles manipulating a terrain area in world space. The class then transforms that area into terrain space. Afterwards, it expands it to fully fit into a (1,1) grid.
Etc.: if general terrain tile size = (1000, 1000, 1000), world space xz manipulation area = (pos (500, 500), size (500,500)). The area will be transformed from world to terrain space into (pos(0.5, 0.5), size(0.5, 0.5)), which will then be expanded to (pos(0, 0), size(1, 1)).
The expanded area will then be used to retrieve all of the terrains the Terraformation is overlapping. For each terrain, a heightmap area overlap function is called. To calculate a terrain’s heightmap space area and the Terraformation’s heightmap space area, a world to heightmap step is calculated.
Etc.: if the general terrain tile size = (1000, 1000, 1000) and general terrain tile heightmap resolution = 257, then the step from world to heightmap space for xz axes will be (257 / 1000, 257 / 1000). For some calculations the step needs to be calculated by subtracting 1 from the heightmap resolution ((257 - 1) / 1000, (257 - 1) / 1000).
Once the area is transformed to heightmap space it once again is expanded into a (1, 1) grid. This is because an integer area is needed to properly deal with heightmap areas.
Etc.: if general terrain tile size = (1000, 1000, 1000), world space xz manipulation area = (pos (500, 500), size (500,500)). The area will be transformed from world to heightmap space into (pos(128.5, 128.5), size(128.5, 128.5)), which will then be expanded to (pos(128, 128), size(129, 129)). Though the lessened step might have been applied here before the expansion, i don’t quite remember.
Once the terrain’s heightmap area and the terraformation’s heightmap area are calculated, an overlap between the 2 areas is made where the overlapping area is retrieved. The overlap heightmap area is then localized to the terrain. Now having the heightmap area which needs manipulating, effects are applied for heightmap distortion.