Editing mesh vertices in Unity

Is there a way to move mesh vertices directly in the Unity3D editor? I thought I saw something about this in the documentation one time, but I can't find it...

Here’s a pretty simple script I created that you can use and tweak however you wish. It isn’t the best but will give u an idea of what you need to do. This fits my needs, but like I said change it however you wish :smiley:

using UnityEngine;
using System.Collections;

[ExecuteInEditMode]

public class VertHandler : MonoBehaviour 
{
	Mesh mesh;
	Vector3[] verts;
	Vector3 vertPos;
	GameObject[] handles;
	
	void OnEnable()
	{
		mesh = GetComponent<MeshFilter>().mesh;
		verts = mesh.vertices;
		foreach(Vector3 vert in verts)
		{
			vertPos = transform.TransformPoint(vert);
			GameObject handle = new GameObject("handle");
			handle.transform.position = vertPos;
			handle.transform.parent = transform;
			handle.tag = "handle";
			//handle.AddComponent<Gizmo_Sphere>();
			print(vertPos);
		}
	}
	
	void OnDisable()
	{
		GameObject[] handles = GameObject.FindGameObjectsWithTag("handle");
		foreach(GameObject handle in handles)
		{
			DestroyImmediate(handle);	
		}
	}
	
	void Update()
	{
		handles = GameObject.FindGameObjectsWithTag ("handle");
		for(int i = 0; i < verts.Length; i++)
		{
			verts _= handles*.transform.localPosition;	*_

* }*
* mesh.vertices = verts;*
* mesh.RecalculateBounds();*
* mesh.RecalculateNormals();*
* }*
}

Ok so it might be a few years late, but I needed something for this recently and found this code… I tweaked it a little to add nice little gizmo handles to each vert to make it easier to move things around. That a component menu entry under mesh to add the component and a bool property on each handle to remove them all…

Drop the script in and you’re good to go.

#if UNITY_EDITOR
using UnityEngine;
using System.Collections;

[AddComponentMenu("Mesh/Vert Handler")]
[ExecuteInEditMode]
public class VertHandler : MonoBehaviour 
{
	
	public bool _destroy;
	
    private Mesh mesh;
    private Vector3[] verts;
    private Vector3 vertPos;
    private GameObject[] handles;
 
	private const string TAG_HANDLE = "VertHandle";
	
    void OnEnable()
    {
       mesh = GetComponent<MeshFilter>().mesh;
       verts = mesh.vertices;
       foreach(Vector3 vert in verts)
       {
         vertPos = transform.TransformPoint(vert);
         GameObject handle = new GameObject(TAG_HANDLE);
//		 handle.hideFlags = HideFlags.DontSave;
         handle.transform.position = vertPos;
         handle.transform.parent = transform;
         handle.tag = TAG_HANDLE;
         handle.AddComponent<VertHandleGizmo>()._parent = this;

       }
    }
 
    void OnDisable()
    {
       GameObject[] handles = GameObject.FindGameObjectsWithTag(TAG_HANDLE);
       foreach(GameObject handle in handles)
       {
         DestroyImmediate(handle);    
       }
    }
 
    void Update() {
		if(_destroy) {
			_destroy = false;
			DestroyImmediate(this);
			return;
		}
		
		handles = GameObject.FindGameObjectsWithTag (TAG_HANDLE);
		
		for(int i = 0; i < verts.Length; i++) {
			verts _= handles*.transform.localPosition;*_ 

* }*

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

}

}

[ExecuteInEditMode]
public class VertHandleGizmo : MonoBehaviour
{

* private static float CURRENT_SIZE = 0.1f;*

* public float _size = CURRENT_SIZE;
public VertHandler _parent;
public bool _destroy;*

* private float _lastKnownSize = CURRENT_SIZE;*

* void Update() {*
* // Change the size if the user requests it*
* if(_lastKnownSize != _size) {
_lastKnownSize = _size;
CURRENT_SIZE = size;
_
}*

* // Ensure the rest of the gizmos know the size has changed…*
* if(CURRENT_SIZE != _lastKnownSize) {
_lastKnownSize = CURRENT_SIZE;
_size = lastKnownSize;
_
}*

* if(_destroy)
DestroyImmediate(parent);
_
}*

* void OnDrawGizmos() {*
* Gizmos.color = Color.red;*
Gizmos.DrawCube(transform.position, Vector3.one * CURRENT_SIZE);
* }*

}
#endif

Take a look at the procedural example: http://unity3d.com/support/resources/example-projects/procedural-examples

There are no built-in mesh editing tools in Unity. As spree wrote, you could write some yourself inside Unity using editor scripting, but unless you have some very specific needs, you will probably be much better of using any of the commonly available 3d modeling tools Unity supports - why reinvent the wheel, when there are plenty of well-developed tools to address this?

http://forum.unity3d.com/threads/226406-Dynamic-Mesh-Vertex-Selection-for-ingame-or-editor-modification
Here is a more pro solution it makes it very easy and also makes u control the indices alone instead of the vertices which u can find more than 3 in the same position but I can still move them

Here it is in JS

#pragma strict
// Using this in edit mode seems to change the UV info which is undesirable.
//Also, you have to use .sharedMesh if using edit mode.
//@script ExecuteInEditMode()

var mesh : Mesh;
var verts : Vector3[];
var vertPos : Vector3;
var n : int =0;
var handles : GameObject[];




function OnEnable()
{

//mesh = this.transform.GetComponent(MeshFilter).sharedMesh as Mesh;
mesh = this.transform.GetComponent(MeshFilter).mesh as Mesh;
verts = mesh.vertices;
for(var vert : Vector3 in verts)
{
vertPos = transform.TransformPoint(vert);
var handle : GameObject = new GameObject("handle" + n);
n ++;
handle.transform.position = vertPos;
handle.transform.parent = transform;
handle.tag = ("handle");

}
}

function OnDisable()
{
n = 0;
handles = GameObject.FindGameObjectsWithTag("handle");
for(var handle : GameObject in handles)
{
gameObject.DestroyImmediate(handle);
}

}

function Update () {
handles = GameObject.FindGameObjectsWithTag("handle");
for(var i : int =0; i < verts.Length; i++)
{
    verts _= handles*.transform.localPosition;*_

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

}

Here’s another version of the above scripts. Has unique verticies like midomido mentioned, and also has a grouping capability. You can group verticies and color them by group. I also improved the gizmo class to allow each vertex to display what groups it belongs to. Hope you like it!

Like the others, just create a script called “VertHandler.cs” then copy this code in and attach to an object.
-Kurt

#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;


    [AddComponentMenu("Mesh/Vert Handler")]
    [ExecuteInEditMode]
    public class VertHandler : MonoBehaviour
    {


        public VertGroup selectedHandles;
        public bool groupSelected; //group the selected set of verticies, add them to the groups list
        public bool removeFromGroup; // removes the selected objects from a given group
        public bool removeFromAll; // removes the selected objects from all groups
        public List<VertGroup> groups; //list of vertex groups
        public bool destroy;

        private Mesh mesh;
        private Vector3[] verts;
        private Vector3 vertPos;
        private VertHandleGizmo[] handles;

        void OnEnable()
        {
            mesh = GetComponent<MeshFilter>().sharedMesh;
            verts = GetUniqueVerticies(mesh.vertices);
            if (handles == null)
            {
                foreach (Vector3 vert in verts)
                {
                    vertPos = transform.TransformPoint(vert);
                    GameObject handle = new GameObject("VertHandle");
                    handle.transform.position = vertPos;
                    handle.transform.parent = transform;
                    VertHandleGizmo gizmo = handle.AddComponent<VertHandleGizmo>();
                    gizmo.parent = this;
                }
            }
        }

        void OnDrawGizmos()
        {
            //display a list of the currently selected vertex handles
            handles = this.gameObject.GetComponentsInChildren<VertHandleGizmo>();
            if (selectedHandles == null)
                return;
            if (selectedHandles.vertHandles == null)
                return;
            selectedHandles.vertHandles.Clear();
            foreach (VertHandleGizmo handle in handles)
            {
                if (handle.selected)
                {
                    selectedHandles.vertHandles.Add(handle.gameObject);
                }
            }
        }

        void Update()
        {
            if (destroy)
            {
                destroy = false;
                DestroyImmediate(this);
                return;
            }



            if (groupSelected)
            {
                groupSelected = false;
                bool newGroup = true;
                //for all existing groups
                foreach (VertGroup group in groups)
                {
                    //if this group has the same name as what's in the selected group
                    if (group.name == selectedHandles.name)
                    {
                        //this group already exists
                        newGroup = false;
                        //add any new edges to the group
                        foreach (GameObject vertHandle in selectedHandles.vertHandles)
                        {
                            if (!group.vertHandles.Contains(vertHandle))
                            {
                                group.vertHandles.Add(vertHandle);
                            }
                            //make the edge know about the group it now belongs to
                            VertHandleGizmo gizmo = vertHandle.GetComponent<VertHandleGizmo>();
                            if (!gizmo.HasGroup(group))
                            {
                                gizmo.groups.Add(group);
                            }
                        }
                        //set the group color
                        group.color = selectedHandles.color;
                    }

                }
                if (newGroup)
                {
                    VertGroup g = new VertGroup(selectedHandles);// selectedHandles.name, selectedHandles.edges, selectedHandles.color);
                    groups.Add(g);
                }
            }

            if (removeFromGroup)
            {
                removeFromGroup = false;
                foreach (VertGroup group in groups)
                {
                    if (group.name == selectedHandles.name)
                    {
                        foreach (GameObject vertHandle in selectedHandles.vertHandles)
                        {
                            if (group.vertHandles.Contains(vertHandle))
                            {
                                group.vertHandles.Remove(vertHandle);
                                VertHandleGizmo gizmo = vertHandle.GetComponent<VertHandleGizmo>();
                                if (gizmo.groups.Contains(group))
                                {
                                    gizmo.groups.Remove(group);
                                }
                            }
                        }
                    }
                }
                CleanGroups();
            }

            if (removeFromAll)
            {
                removeFromAll = false;
                foreach (VertGroup group in groups)
                {
                    foreach (GameObject vertHandle in selectedHandles.vertHandles)
                    {
                        if (group.vertHandles.Contains(vertHandle))
                        {
                            group.vertHandles.Remove(vertHandle);
                            VertHandleGizmo gizmo = vertHandle.GetComponent<VertHandleGizmo>();
                            if (gizmo.groups.Contains(group))
                            {
                                gizmo.groups.Remove(group);
                            }
                        }
                    }
                }
                CleanGroups();
            }
        }


        //clean out groups that have no edges in them
        void CleanGroups()
        {
            List<VertGroup> toRemove = new List<VertGroup>();
            foreach (VertGroup group in groups)
            {
                if (group.vertHandles.Count == 0)
                {
                    toRemove.Add(group);
                }
            }
            foreach (VertGroup group in toRemove)
            {
                groups.Remove(group);
            }
        }

        Vector3[] GetUniqueVerticies(Vector3[] verticies)
        {
            List<Vector3> uniqueVerts = new List<Vector3>();

            foreach(Vector3 vert in verticies)
            {
                if(!uniqueVerts.Contains(vert))
                {
                    uniqueVerts.Add(vert);
                }
            }


            return uniqueVerts.ToArray();
        }
    }

    [System.Serializable]
    public class VertGroup
    {

        public string name;
        public Color color = Color.white;
        public List<GameObject> vertHandles;


        public VertGroup(VertGroup selectedGroup)
        {
            name = selectedGroup.name;
            vertHandles = new List<GameObject>();
            color = selectedGroup.color;
            foreach (GameObject vertHandle in selectedGroup.vertHandles)
            {
                vertHandles.Add(vertHandle);
                VertHandleGizmo gizmo = vertHandle.GetComponent<VertHandleGizmo>();
                gizmo.groups.Add(this);
            }
        }


    }

    [ExecuteInEditMode]
    public class VertHandleGizmo : MonoBehaviour
    {

        private static float CURRENT_SIZE = 0.1f;

        public float _size = CURRENT_SIZE;
        public VertHandler parent;
        public bool selected = false;
        public bool destroy;
        private Color color = Color.white;
        public List<VertGroup> groups = new List<VertGroup>(); // the groups this gizmo belongs to
        private float lastKnownSize = CURRENT_SIZE;

        void Update()
        {
            // Change the size if the user requests it
            if (lastKnownSize != _size)
            {
                lastKnownSize = _size;
                CURRENT_SIZE = _size;
            }

            // Ensure the rest of the gizmos know the size has changed...
            if (CURRENT_SIZE != lastKnownSize)
            {
                lastKnownSize = CURRENT_SIZE;
                _size = lastKnownSize;
            }

            if (destroy)
                DestroyImmediate(parent);
        }

        void OnDrawGizmos()
        {
            Vector3 toCenter = (parent.transform.position - transform.position).normalized;
            Vector3 up = Vector3.Cross(Vector3.right, toCenter).normalized;
            Vector3 right = Vector3.Cross(toCenter,up).normalized;
            float radius = CURRENT_SIZE;

            //draw an icon for each group this vertex belongs to
            float angleStep = 360f / groups.Count;
            for (int i = 0; i < groups.Count; i++)
            {
                VertGroup group = groups*;*

Gizmos.color = group.color;
float angle = angleStep * i;
float rad = Mathf.Deg2Rad * angle;
float x = Mathf.Cos(rad) * radius;
float y = Mathf.Sin(rad) * radius;
Vector3 position = transform.position + right * x + up * y;
Gizmos.DrawCube(position, Vector3.one * CURRENT_SIZE*.5f);
}

//draw the selectable cube
Gizmos.color = color;
selected = Selection.Contains(this.gameObject);//IsSelected();
if (selected)
{
Gizmos.color = Color.black;
}
Gizmos.DrawCube(transform.position, Vector3.one * CURRENT_SIZE);
}

public bool HasGroup(VertGroup g)
{
foreach(VertGroup group in groups)
{
if(group.name == g.name)
{
return true;
}
}
return false;
}
}

#endif

Hello, this is an improved version of the script which is able to group vertices auto according to distance threshold and put groups inside the edited object, so it makes more easy changing of the model geometry by dragging the whole group. Also it does not lose handles during switch Play mode on/off in the Editor.

Please set up public values BEFORE put the component on the target object if a case you want to change them.

using UnityEngine;
using System.Collections.Generic;

/// <summary>
/// Put this script in Editor mode to some object
/// </summary>
[ExecuteInEditMode]
public class VertHandler : MonoBehaviour
{
    /// <summary>
    /// Consider such close vertices as one welded point of geometry.
    /// </summary>
    public float DistThreshold = 0.1f;
    
    /// <summary>
    /// Highlight welded points
    /// </summary>
    public bool ShowPoints = true;
    
    /// <summary>
    /// Prefix for handles' names
    /// </summary>    
    public string HandlePrefix = "Handle_";

    /// <summary>
    /// When work is done remove this script and handles from the hierarchy of the current object 
    /// </summary>
    public bool DestroyMe = true;

    /// <summary>
    /// Array of handles' transforms
    /// </summary>
    List<Transform> HandlesTr;

    // internal values
    Mesh m_mesh;
    Vector3[] m_verts;
    Vector3 m_vertPos;    
    List<GameObject> m_groups;
    MeshFilter m_meshFilter;
    MeshCollider m_meshCollider;

    void Awake()
    {        
        Debug.Log("Awake " + Application.isPlaying);
        if (Application.isPlaying)
        {
            Debug.Log("DO NOT USE ME IN PLAY MODE!");
            enabled = false;
            ShowPoints = false;
        }

        DestroyMe = false; // usually, we do not want to be destroyed from the beginning ;)
    }
    
    void OnEnable()
    {
        // after switch from the Play mode we should clear old handles, try not to use this script in the play mode
        Transform tt;
        for (int i = transform.childCount - 1; i >= 0; i--)
        {
            tt = transform.GetChild(i);        
            if (tt.name.IndexOf(HandlePrefix) == 0)
                DestroyImmediate(tt.gameObject);
        }

        // init arrays
        m_groups = new List<GameObject>();
        HandlesTr = new List<Transform>();

        // make some steps in order to avoid error: "Instantiating mesh due to calling MeshFilter.mesh during edit mode. This will leak meshes. Please use MeshFilter.sharedMesh instead."
        m_meshFilter = GetComponent<MeshFilter>();
        m_mesh = Instantiate(m_meshFilter.sharedMesh); 
        m_meshFilter.mesh = m_mesh;

        m_verts = m_mesh.vertices;

        // Make groups vertices these closer than DistTreshold to each other
        GameObject handle;
        foreach (Vector3 vert in m_verts)
        {
            m_vertPos = transform.TransformPoint(vert);
            handle = new GameObject();
            handle.transform.position = m_vertPos;
            handle.transform.parent = transform;            
            
            int index = m_groups.FindIndex(var => Vector3.Distance(var.transform.position, m_vertPos) < DistThreshold);
            if (index > -1)
            {
                handle.transform.parent = m_groups[index].transform;
                handle.name = HandlePrefix + index;
            }
            else
            {
                m_groups.Add(handle); // some new vertex that to far from each previous, make the group for it
                handle.name = HandlePrefix + (m_groups.Count-1);
            }

            HandlesTr.Add(handle.transform); // memo this handle
        }        
    }

    /// <summary>
    /// Draw draggable points
    /// </summary>
    void OnDrawGizmos()
    {
        if (ShowPoints)
        {
            Gizmos.color = Color.red;
            for (int i = 0; i < m_groups.Count; i++)
            {                
                Gizmos.DrawSphere(m_groups*.transform.position, 0.03f);*

}
}
}

void Update()
{
if (DestroyMe)
{
// cleanup and destroy
for (int i = 0; i < m_groups.Count; i++)
{
DestroyImmediate(m_groups*);
_
}_
DestroyImmediate(this);
return;
_
}*_

// Trace handlers position
for (int i = 0; i < HandlesTr.Count; i++)
{
m_verts = transform.InverseTransformPoint(HandlesTr*.position);*
}

// update the mesh according to last changes
m_mesh.vertices = m_verts;
m_mesh.RecalculateBounds();
m_mesh.RecalculateNormals();
}
}

So, here it is Jan 5, 2019, and I just found your script, Luke Kellett , and it “IS” awesome… More that I needed, but EXACTLY what I needed.
I have a ray that I shoot out at a plane, and was trying to figure out how to identify each vertices on the plane, and, not only does this identify each one, but adds handles for each vertex that allows me to edit each one, in the editor.
Thanks for your SHARING…