unity 编辑mesh顶点位置
在某些特殊情况下,不得不对模型进行一些简单的修改,所以写了个简单的编辑脚本。
思路就是获取mesh上的所有顶点,然后在每个顶点位置创建一个控制点,控制点可以是任意你喜欢的物体,通过判断控制点的位置信息来修改mesh的顶点位置。
在unity中,mesh上的顶点与几个面相交,就会有几个坐标点,估计是把点为每一个三角形面复制了一份,所以这里在生成控制点时要注意剔除重复的点,不要重复生成。
这里我是把每个顶点的坐标转为字符串,使用该坐标的字符串作为key来把控制点与顶点数据联系起来。
下面给出完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class MeshEditorPoint : MonoBehaviour { //顶点id,(顶点初始位置转字符串) [HideInInspector] public string pointid; //记录坐标点上一次移动的位置,用于判断控制点是否移动 [HideInInspector] private Vector3 lastPosition; public delegate void MoveDelegate( string pid,Vector3 pos); //控制点移动时的回调 public MoveDelegate onMove = null ; // Use this for initialization void Start () { lastPosition = transform.position; } // Update is called once per frame void Update () { if (transform.position != lastPosition){ if (onMove != null ) onMove(pointid, transform.localPosition); lastPosition = transform.position; } } } |
然后是顶点编辑脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Text; using System; public class ModelMeshEditor : MonoBehaviour { //控制点的大小 public float pointScale = 1.0f; private float lastPointScale = 1.0f; Mesh mesh; //顶点列表 List<Vector3> positionList = new List<Vector3>(); //顶点控制物体列表 List<GameObject> positionObjList = new List<GameObject>(); /// <summary> /// key:顶点字符串 /// value:顶点在列表中的位置 /// </summary> Dictionary< string , List< int >> pointmap = new Dictionary< string , List< int >>(); // Use this for initialization void Start () { lastPointScale = pointScale; mesh = GetComponent<MeshFilter>().sharedMesh; CreateEditorPoint(); } //创建控制点 public void CreateEditorPoint(){ positionList = new List<Vector3>(mesh.vertices); for ( int i = 0; i < mesh.vertices.Length; i++) { string vstr = Vector2String(mesh.vertices[i]); if (!pointmap.ContainsKey(vstr)){ pointmap.Add(vstr, new List< int >()); } pointmap[vstr].Add(i); } foreach ( string key in pointmap.Keys) { GameObject editorpoint = (GameObject)Resources.Load( "Prefabs/MeshEditor/MeshEditorPoint" ); editorpoint = Instantiate(editorpoint); editorpoint.transform.parent = transform; editorpoint.transform.localPosition = String2Vector(key); editorpoint.transform.localScale = new Vector3(1f, 1f, 1f); MeshEditorPoint editorPoint = editorpoint.GetComponent<MeshEditorPoint>(); editorPoint.onMove = PointMove; editorPoint.pointid = key; positionObjList.Add(editorpoint); } } //顶点物体被移动时调用此方法 public void PointMove( string pointid,Vector3 position){ if (!pointmap.ContainsKey(pointid)){ return ; } List< int > _list = pointmap[pointid]; for ( int i = 0; i < _list.Count; i ++){ positionList[_list[i]] = position; } mesh.vertices = positionList.ToArray(); mesh.RecalculateNormals(); } // Update is called once per frame void Update () { //检测控制点尺寸是否改变 if (Math.Abs(lastPointScale - pointScale) > 0.1f){ lastPointScale = pointScale; for ( int i = 0; i < positionObjList.Count; i ++){ positionObjList[i].transform.localScale = new Vector3(pointScale, pointScale, pointScale); } } } string Vector2String(Vector3 v){ StringBuilder str = new StringBuilder(); str.Append(v.x).Append( "," ).Append(v.y).Append( "," ).Append(v.z); return str.ToString(); } Vector3 String2Vector( string vstr) { try { string [] strings = vstr.Split( ',' ); return new Vector3( float .Parse(strings[0]), float .Parse(strings[1]), float .Parse(strings[2])); } catch (Exception e){ Debug.LogError(e.ToString()); return Vector3.zero; } } } |
使用:
首先制作控制点的prefab,然后挂载上MeshEditorPoint脚本。
在想要编辑的mesh的GameObject上挂载ModelMeshEditor,不要忘记修改ModelMeshEditor中加载prefab的路径。
然后运行场景可就可以看到模型上的控制点了:
然后就可以拖动这些控制点来改变mesh的顶点数据了:
***注意:这里对mesh的修改是即时保存的,并且不能恢复,修改之前请务必做好备份!!!也可以修改上面的脚本,在开始时复制一个mesh来修改,修改后再决定是否需要保存。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!