Custom Terrain Texturing Script with Brushes

Hi Community!

I want to make an Editor Extension which is a terrain painter with advanced functions. I already know how to set alpha maps and modify them, but I want to know how can I get the alphamap area under the brush. In other words, can someone give me a good idea or working code (even better) to effectively carry out terrain painting in the same way that the Unity Terrain Engine does? Like if we choose a star brush, the texture will be painted in that shape and size?

EDIT:
I already can paint the texture on the terrain, but not in the correct shape.


The stars are from Unity’s Terrain Engine (which I want to simulate) and the squares are painted from my script:

Terrain terrain;
    TerrainData terrainData;
    TerrainPointData[] points;

    float[] strength;
    int size;

    float GetStrength(int x, int y)
    {
        x = Mathf.Clamp(x, 0, size - 1);
        y = Mathf.Clamp(y, 0, size - 1);

        return strength[y * size + x];
    }

    public void Initialize(Texture2D brushTexture, int size)
    {
        if (terrain == null)
            terrain = GetComponent<Terrain>();

        terrainData = terrain.terrainData;

        points = new TerrainPointData[terrainData.alphamapHeight * terrainData.alphamapWidth];

       

        for (int y = 0; y < terrainData.alphamapHeight; y++) {
            for (int x = 0; x < terrainData.alphamapWidth; x++) {
                //Normalize Coordinates
                float x01 = (float)x / terrainData.alphamapWidth;
                float y01 = (float)y / terrainData.alphamapHeight;

                //Get Height at point
                float height = terrainData.GetHeight(Mathf.RoundToInt(y01 * terrainData.heightmapHeight), Mathf.RoundToInt(x01 * terrainData.heightmapWidth));

                //Get Normal at point
                //Vector3 normal = terrainData.GetInterpolatedNormal(y01, x01);

                //Get Steepness at point
                float steepness = terrainData.GetSteepness(y01, x01);

                points[y * terrainData.alphamapHeight + x] = new TerrainPointData(x, y, height, steepness);//, normal);

               
            }
        }

        this.size = size;
        //size = brushTexture.height;

        strength = new float[size * size];

        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                strength[i * size + j] = brushTexture.GetPixelBilinear((float)j / size, (float)i / size).a;
            }
        }
    }

    public void Paint(Vector2 mousePosition, int textureIndex = 1, float opacity = 1)
    {
        int Size = 8 * size;
        int num = Mathf.FloorToInt(mousePosition.x * terrainData.alphamapWidth);
        int num2 = Mathf.FloorToInt(mousePosition.y * terrainData.alphamapHeight);
        int num3 = Mathf.RoundToInt((float)size) / 2;
        int num4 = Mathf.RoundToInt((float)size) % 2;
        int x = Mathf.Clamp(num - num3, 0, terrainData.alphamapWidth - 1);
        int y = Mathf.Clamp(num2 - num3, 0, terrainData.alphamapHeight - 1);
        int num7 = Mathf.Clamp((num + num3) + num4, 0, terrainData.alphamapWidth);
        int num8 = Mathf.Clamp((num2 + num3) + num4, 0, terrainData.alphamapHeight);
        int width = num7 - x;
        int height = num8 - y;

        float[, ,] splatmapData = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight);

        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int ix = (x + j) - ((num - num3) + num4);
                int iy = (y + i) - ((num2 - num3) + num4);
                splatmapData[y + i, x + j, textureIndex] = GetStrength(ix / size, iy / size) * opacity;
            }
        }

        terrainData.SetAlphamaps(0, 0, splatmapData);
    }

Please ignore the TerrainPointData array, that is for my experimentation.

@judah4 @FreebordMAD I saw your assets, could you just tell me how you implemented the different brushes for texturing your terrain? I spent 6 hours yesterday but couldn’t find a solution. Sorry for the direct reference.

Thanks!

I just modified a bit and it works! Only change was in this line:

                splatmapData[y + i, x + j, textureIndex] = GetStrength(ix, iy) * opacity;

And now it works brilliantly!