Painting custom terrain with a raycast

How can I accomplish this? I have no idea where to start and need help.

Painting texture or grass/foliage?
Custom terrain is made from mesh?
Paint in editor scene window or runtime?

If mesh:
raycast will return texture coordinate, so you can draw into that texture

If in editor script, see:
this for getting ray from mouse,

put code inside OnSceneGUI loop

get events (like mouse buttons, keypresses) with

draw brush preview circle with this (use raycast hit point and normal to get position)

1.grass not foligae
2. custom terrain is made from mesh, just a flat plane in blender, that I have used to be able to edit vertices with my script.
3. it is being painted in the editor.

how do I draw onto the texture?

every single link you posted I already know about and am using in my code currently. it is 400 lines and I don’t think you will need to see it but here it is anyway just for reference I guess.

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;

public class TerrainEditor : EditorWindow
{
    //Declare variables for the terrain editor window to use.
    public static List<GameObject> cellsToSave = new List<GameObject>();

    public static bool editVertices = true;
    public static bool editTextures = false;

    public static bool dimmensionalView = false;

    public static float gridLock = 0.25f;
    public static float newHeight;

    public static bool showBrush = true;
    public static string brushRadius = "5";

    public static bool raiseTerrain = true;
    public static bool lowerTerrain = false;

    public static bool flattenTerrain = false;
    public static string flattenHeight = "1";

    public static bool leftMouseButton = false;

    //Call each frame to determine if the mouse is over the scene window.
    void OnInspectorUpdate()
    {
        if (mouseOverWindow) mouseOverWindow.Focus();
        Repaint();
    }

    [MenuItem("Heightmap/Terrain Editor %#e")]
    public static void Init()
    {
        //Controls the creation of the window itself.
        TerrainEditor editorWindow = (TerrainEditor)GetWindow(typeof(TerrainEditor), true, "Terrain Editor");
        SceneView.onSceneGUIDelegate += OnScene;
        editorWindow.Show();
    }

    //Switches between terrain painting mode and terrain editing mode.
    private bool terrainChanger(string label, bool currentValue)
    {
        var result = EditorGUILayout.Toggle(label, currentValue);
        return result && !currentValue;
    }

    //when in terrain editing mode switches between which tool to use.
    private bool ToggleChangedToTrue(string label, bool currentValue)
    {
        var result = EditorGUILayout.Toggle(label, currentValue);
        return result && !currentValue;
    }

    void OnGUI()
    {
        //Creates the window.
        EditorGUILayout.BeginHorizontal();
        GUILayout.Label("Map Editor");
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        GUILayout.Label("");
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        dimmensionalView = GUILayout.Toggle(dimmensionalView, "3d Mode");
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        bool meshChangedToTrue = terrainChanger("Edit Terrain", editVertices);
        bool texturesChangedToTrue = terrainChanger("Terrain Painting", editTextures);
        EditorGUILayout.EndHorizontal();

        if (editVertices)
        {
            EditorGUILayout.BeginHorizontal();
            brushRadius = GUILayout.TextField(brushRadius, 2);
            showBrush = GUILayout.Toggle(showBrush, "Show Brush");
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            GUILayout.Label("");
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            GUILayout.Label("Editor Tools");
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            bool bool1ChangedToTrue = ToggleChangedToTrue("Raise Terrain", raiseTerrain);
            bool bool2ChangedToTrue = ToggleChangedToTrue("Lower Terrain", lowerTerrain);
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            bool bool3ChangedToTrue = ToggleChangedToTrue("Flatten Terrain", flattenTerrain);
            GUILayout.Label("Height");
            flattenHeight = GUILayout.TextField(flattenHeight, 9);
            EditorGUILayout.EndHorizontal();

            //controls the switching of the tools to ensure only one tool is active at a time.
            if (bool1ChangedToTrue || bool2ChangedToTrue || bool3ChangedToTrue)
            {
                raiseTerrain = bool1ChangedToTrue;
                lowerTerrain = bool2ChangedToTrue;
                flattenTerrain = bool3ChangedToTrue;
            }
        }
        if (editTextures)
        {
            Material[] terrainPaints = Resources.LoadAll("Textures/Terrain Paints") as Material[];

            if (terrainPaints.Length > 0)
            {
                foreach (Material terrainPaint in terrainPaints)
                {
                    EditorGUILayout.BeginHorizontal();
                    GUILayout.Box(terrainPaint.mainTexture);
                    EditorGUILayout.EndHorizontal();
                }
            }
        }

        //Controls which terrain mode is active and ensures only one is active at a time.
        if (meshChangedToTrue || texturesChangedToTrue)
        {
            editVertices = meshChangedToTrue;
            editTextures = texturesChangedToTrue;
        }
    }

    public static void OnScene(SceneView sceneview)
    {
        //Creates the current event that is happening in the sceneview.
        Event input = Event.current;

        //Disables the ability to select objects in the scene.
        HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));

        //If the scene camera is not blank it will lock it to a birds eye view of the scene.
        SceneView view = SceneView.currentDrawingSceneView;

        if (view != null)
        {
            if (!dimmensionalView)
            {
                view.rotation = Quaternion.Euler(90, 0, 0);
                view.orthographic = true;
                view.in2DMode = true;
            }
            else
            {
                view.orthographic = false;
                view.in2DMode = false;
            }
        }

        //Locates every cell in the scene.
        GameObject cellCheck = GameObject.FindGameObjectWithTag(TerrainSystem.cellTag);

        //determines if there are any cells on scene and displays an error if there are not any.
        if (cellCheck != null)
        {

            //Handles the ray casting from the scenes camera to the mouses position.
            Ray worldRay = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
            RaycastHit hitInfo;

            //If the brush is enabled this uses the mouse position to draw the brush.
            if (showBrush)
            {
                if (Physics.Raycast(worldRay, out hitInfo))
                {
                    //Only functions if it hits a cell by determining what tag the hit object has.
                    if (hitInfo.transform.tag == TerrainSystem.cellTag)
                    {
                        //Use the point at which the ray hit the cell to determine where the mouse is at.
                        Vector3 mousePosition = hitInfo.point;

                        float radius = (float.Parse(brushRadius));

                        Handles.color = Color.blue;
                        Handles.DrawWireDisc(mousePosition, Vector3.up, radius);
                    }
                }
            }

            //The system of if statements that determines when and if the mouse button is clicked and when to edit terrain.
            if (input.type == EventType.MouseDown || input.type == EventType.MouseDrag)
            {
                if (input.button == 0) if (leftMouseButton == false) leftMouseButton = true;
                    else if (input.button != 0 && leftMouseButton) leftMouseButton = false;
            }
            else if (input.type != EventType.MouseDown && leftMouseButton || input.type != EventType.MouseMove && leftMouseButton) leftMouseButton = false;

            //Use the terrain handler function to raise or lower terrain.
            if (leftMouseButton)
            {
                TerrainHandler();
            }
        }
        //Display the error code for if there are no cells on scene.
        else ErrorCodeT.x003b();
    }

    public void OnDestroy()
    {
        //Destroy the temp data and scene functions when the window is closed.
        SceneView.onSceneGUIDelegate -= OnScene;
    }

    //Function used to handle the editing of cells.
    public static void TerrainHandler()
    {
        //The part that handles the editing of terrain.
        if (editVertices)
        {
            //Handles the ray casting from the scenes camera to the mouses position.
            Ray worldRay = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
            RaycastHit hitInfo;

            if (Physics.Raycast(worldRay, out hitInfo))
            {
                if (hitInfo.transform.tag == TerrainSystem.cellTag)
                {
                    //Use the point at which the ray hit the cell to determine where the mouse is at.
                    Vector3 mousePosition = hitInfo.point;

                    //ebug.Log("The mouses position is: " + mousePosition);
                    //Debug.Log("Main ray information: " + worldRay);

                    //Used to construct the bounds inside of which vertices will be edited.
                    float radius = (float.Parse(brushRadius));

                    GameObject cell = hitInfo.transform.gameObject;

                    Mesh mesh = cell.gameObject.GetComponent<MeshFilter>().mesh;
                    Vector3[] vertices = mesh.vertices;

                    if (flattenTerrain)
                        newHeight = float.Parse(flattenHeight) / (1 / gridLock);

                    for (int i = 0; i < vertices.Length; i++)
                    {
                        Vector3 worldPoint = cell.transform.TransformPoint(vertices[i]);

                        if (Vector3.Distance(mousePosition, worldPoint) <= radius)
                        {
                            Vector3 newPosition = new Vector3();

                            if (raiseTerrain)
                                newPosition = new Vector3(worldPoint.x, worldPoint.y + gridLock, worldPoint.z);
                            if (lowerTerrain)
                                    newPosition = new Vector3(worldPoint.x, worldPoint.y - gridLock, worldPoint.z);
                            if (flattenTerrain)
                                newPosition = new Vector3(worldPoint.x, newHeight, worldPoint.z);

                            vertices[i] = cell.transform.InverseTransformPoint(newPosition);
                        }
                    }

                    Ray[] extraRay = new Ray[8];
                    RaycastHit extraHitInfo;

                    Vector3 mainRayPosition = new Vector3(mousePosition.x, mousePosition.y + 15, mousePosition.z);
                    float mainRayDistance = mainRayPosition.y + 5;

                    Vector3[] extraRayOrigin = new Vector3[8];
                    Vector3 extraRayDirection = Vector3.down;

                    float offSet = radius;

                    extraRayOrigin[0] = new Vector3(mainRayPosition.x + offSet, mainRayPosition.y, mainRayPosition.z);
                    extraRayOrigin[1] = new Vector3(mainRayPosition.x - offSet, mainRayPosition.y, mainRayPosition.z);
                    extraRayOrigin[2] = new Vector3(mainRayPosition.x, mainRayPosition.y, mainRayPosition.z + offSet);
                    extraRayOrigin[3] = new Vector3(mainRayPosition.x, mainRayPosition.y, mainRayPosition.z - offSet);
                    extraRayOrigin[4] = new Vector3(mainRayPosition.x + offSet, mainRayPosition.y, mainRayPosition.z + offSet);
                    extraRayOrigin[5] = new Vector3(mainRayPosition.x - offSet, mainRayPosition.y, mainRayPosition.z - offSet);
                    extraRayOrigin[6] = new Vector3(mainRayPosition.x - offSet, mainRayPosition.y, mainRayPosition.z + offSet);
                    extraRayOrigin[7] = new Vector3(mainRayPosition.x + offSet, mainRayPosition.y, mainRayPosition.z - offSet);

                    extraRay[0] = new Ray(extraRayOrigin[0], extraRayDirection);
                    extraRay[1] = new Ray(extraRayOrigin[1], extraRayDirection);
                    extraRay[2] = new Ray(extraRayOrigin[2], extraRayDirection);
                    extraRay[3] = new Ray(extraRayOrigin[3], extraRayDirection);
                    extraRay[4] = new Ray(extraRayOrigin[4], extraRayDirection);
                    extraRay[5] = new Ray(extraRayOrigin[5], extraRayDirection);
                    extraRay[6] = new Ray(extraRayOrigin[6], extraRayDirection);
                    extraRay[7] = new Ray(extraRayOrigin[7], extraRayDirection);

                    for (int ray = 0; ray < extraRay.Length; ray++)
                    {
                        if (Physics.Raycast(extraRay[ray], out extraHitInfo))
                        {
                            //int rayNumber = ray + 1;
                            //Debug.Log("Ray " + rayNumber + " information: " + extraRay[ray]);

                            if (extraHitInfo.transform.gameObject != hitInfo.transform.gameObject)
                            {
                                GameObject extraCell = extraHitInfo.transform.gameObject;

                                Mesh extraMesh = extraCell.gameObject.GetComponent<MeshFilter>().mesh;
                                Vector3[] extraVertices = extraMesh.vertices;

                                for (int i = 0; i < extraVertices.Length; i++)
                                {
                                    Vector3 worldPoint = extraCell.transform.TransformPoint(extraVertices[i]);

                                    if (Vector3.Distance(mousePosition, worldPoint) <= radius)
                                    {
                                        Vector3 newPosition = new Vector3();

                                        if (raiseTerrain)
                                            newPosition = new Vector3(worldPoint.x, worldPoint.y + gridLock, worldPoint.z);
                                        if (lowerTerrain)
                                            newPosition = new Vector3(worldPoint.x, worldPoint.y - gridLock, worldPoint.z);
                                        if (flattenTerrain)
                                            newPosition = new Vector3(worldPoint.x, newHeight, worldPoint.z);

                                        extraVertices[i] = extraCell.transform.InverseTransformPoint(newPosition);
                                    }
                                }
                                extraMesh.vertices = extraVertices;
                                extraMesh.RecalculateBounds();
                                extraMesh.RecalculateNormals();

                                extraCell.GetComponent<MeshFilter>().mesh = extraMesh;
                            }
                        }
                    }

                    if (!cellsToSave.Contains(hitInfo.transform.gameObject))
                        cellsToSave.Add(hitInfo.transform.gameObject);

                    mesh.vertices = vertices;
                    mesh.RecalculateBounds();
                    mesh.RecalculateNormals();

                    cell.GetComponent<MeshFilter>().mesh = mesh;
                }
            }
        }

        foreach (GameObject cell in cellsToSave)
        {
            cell.GetComponent<MeshCollider>().sharedMesh = null;
            cell.GetComponent<MeshCollider>().sharedMesh = cell.GetComponent<MeshFilter>().sharedMesh;
        }
    }
}

there is working example in

Test that in playmode first, then convert into editor script…

can you take a look at lines 115 - 128 and help me make a sort of selection system for all the materials in my terrain paints folder? I am working on the terrain painting system itself;f now but I need a good selection system in place also.