zoukankan      html  css  js  c++  java
  • Unity 自定义地形编辑器开发(二.模型顶点编辑)

    老样子先看效果

    实现步骤

      1.弹窗

        效果

        代码

        

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Text;
    using UnityEditor;
    using UnityEngine;
    
    public class EditVector : EditorWindow
    {
         string SavePath = "";
        bool FreeMove = true;
    
     private void OnGUI()
        {
            GUILayout.BeginVertical();
            //标签
            GUILayout.BeginHorizontal();
            GUILayout.Box("正在编辑顶点...", TitleBoxStyle(), GUILayout.Height(60), GUILayout.ExpandWidth(true));
            GUILayout.EndHorizontal();
            GUILayout.Space(10);
            if (GUILayout.Button("选择源文件夹", GUILayout.Height(30), GUILayout.Width(180)))
            {
                SavePath = EditorUtility.OpenFolderPanel("选择源文件夹", "Assets/", "");
            }
            GUILayout.Space(10);
            FreeMove=GUILayout.Toggle(FreeMove,"自由拖拽");
    
            GUILayout.BeginHorizontal();
            if (GUILayout.Button("保存", GUILayout.Height(30)))
            {
                if (SaveEdit())
                {
                    instance.Close();
                }
                
            }
            GUILayout.Space(10);
            if (GUILayout.Button("取消", GUILayout.Height(30)))
            {
                Reset();
                instance.Close();
            }
            GUILayout.Space(10);
            GUILayout.EndHorizontal();
    
            GUILayout.EndVertical();
           
        }
        public GUIStyle TitleBoxStyle()
        {
            GUIStyle boxStyle = new GUIStyle();
    
            boxStyle.margin = new RectOffset(2, 2, 2, 2);
            boxStyle.border = new RectOffset(2, 2, 2, 2);
            boxStyle.fontSize = 25;
            boxStyle.fontStyle = FontStyle.Bold;
            boxStyle.alignment = TextAnchor.MiddleCenter;
            return boxStyle;
        }
    }
    

        2.调用弹窗

        代码

    public class EditVectorManager
    {
        //网格
        [MenuItem("GameObject//编辑顶点", false, -1)]
        static void EditTerrainVector()
        {
            EditorWindow ew=EditorWindow.GetWindow<EditVector>(false, "编辑顶点", true);
            ew.Show();
        }
      
    }
    

        3.鼠标选择Scene场景UI

          效果:

          代码:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Text;
    using UnityEditor;
    using UnityEngine;
    
    public class EditVector : EditorWindow
    {
        string SavePath = "";
        bool FreeMove = true;
        public static EditVector instance;
      
        void OnEnable()
        {
            instance = this;
            SceneView.duringSceneGui -= this.OnSceneGUI;
            SceneView.duringSceneGui += this.OnSceneGUI;
         
    
    
        }
    
    
    
        void OnDisable()
        {
            instance = null;
            SceneView.duringSceneGui -= this.OnSceneGUI;
        }
    
    
        void OnSceneGUI(SceneView sceneView)
        {
            //绘制选择框
            Handles.BeginGUI();
            if (starSelectPos != Vector2.zero)
            {
    
                Vector2 difference = mousePos - starSelectPos;
                difference = new Vector2(Mathf.Abs(difference.x), Mathf.Abs(difference.y));
                GUILayout.BeginArea(new Rect(starSelectPos, difference));
                GUILayout.Box("", SelectMouesDraw(), GUILayout.Height(difference.y), GUILayout.Width(difference.x));
                GUILayout.EndArea();
    
    
            }
            Handles.EndGUI();
      
            HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));//替换Uinity自带的默认控制
            SelectVectorGUI();
            sceneView.Repaint();
        }
    
        
        Vector2 mousePos;
        Vector2 starSelectPos;
        /// <summary>
        /// 检测输入
        /// </summary>
        void SelectVectorGUI()
        {
           
            Event e = Event.current;
            mousePos = e.mousePosition;
           
           
            if (e.type==EventType.MouseDrag&&e.control&&e.button==0)
            {
               
                if (starSelectPos == Vector2.zero)
                {
                    starSelectPos = new Vector2(mousePos.x, mousePos.y);
                }
                isShowSelectVector = false;
               /// Debug.LogError("开始选择");
                
            }
            if (e.type == EventType.MouseUp && e.control && e.button == 0)
            {
                starSelectPos=Vector2 .zero;
            }
            
           
        }
       
        private void OnGUI()
        {
            GUILayout.BeginVertical();
            //标签
            GUILayout.BeginHorizontal();
            GUILayout.Box("正在编辑顶点...", TitleBoxStyle(), GUILayout.Height(60), GUILayout.ExpandWidth(true));
            GUILayout.EndHorizontal();
            GUILayout.Space(10);
            if (GUILayout.Button("选择源文件夹", GUILayout.Height(30), GUILayout.Width(180)))
            {
                SavePath = EditorUtility.OpenFolderPanel("选择源文件夹", "Assets/", "");
            }
            GUILayout.Space(10);
            FreeMove=GUILayout.Toggle(FreeMove,"自由拖拽");
    
            GUILayout.BeginHorizontal();
            if (GUILayout.Button("保存", GUILayout.Height(30)))
            {
                if (SaveEdit())
                {
                    instance.Close();
                }
                
            }
            GUILayout.Space(10);
            if (GUILayout.Button("取消", GUILayout.Height(30)))
            {
                Reset();
                instance.Close();
            }
            GUILayout.Space(10);
            GUILayout.EndHorizontal();
    
            GUILayout.EndVertical();
           
        }
        public GUIStyle TitleBoxStyle()
        {
            GUIStyle boxStyle = new GUIStyle();
    
            boxStyle.margin = new RectOffset(2, 2, 2, 2);
            boxStyle.border = new RectOffset(2, 2, 2, 2);
            boxStyle.fontSize = 25;
            boxStyle.fontStyle = FontStyle.Bold;
            boxStyle.alignment = TextAnchor.MiddleCenter;
            return boxStyle;
        }
        public GUIStyle SelectMouesDraw()
        {
            GUIStyle boxStyle = new GUIStyle();
            boxStyle.margin = new RectOffset(0, 0, 0, 0);
            boxStyle.border = new RectOffset(2, 2, 2, 2);
            boxStyle.padding = new RectOffset(0, 0, 0, 0);
            boxStyle.alignment = TextAnchor.MiddleCenter;
            Texture2D img = new Texture2D(1,1);
            Color[] colorlist = img.GetPixels();
            colorlist[0] = new Color(0,1,0,0.3f);
            img.SetPixels(colorlist);
            boxStyle.normal.background = img;
    
            return boxStyle;
        }
    }
    

        4.选择顶点并编辑

        效果:不放了给最上面一致

        代码(即:完整代码)

          

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Text;
    using UnityEditor;
    using UnityEngine;
    
    public class EditVector : EditorWindow
    {
        string SavePath = "";
        bool FreeMove = true;
        public static EditVector instance;
        public RaycastHit curHit;
        public Mesh selectMesh;//网格
        MeshCollider selectMeshCollider;
        GameObject selectObj;
        Vector3[] selectObjVectors;//用于还原
        List<Vector3> selectMeshVectorWPs; 
        List<Vector3> selectedVertex;//选择的顶点
        List<int> selectedVertexIndex;//选择的顶点的下标
        void OnEnable()
        {
            instance = this;
            SceneView.duringSceneGui -= this.OnSceneGUI;
            SceneView.duringSceneGui += this.OnSceneGUI;
            selectObj = Selection.activeGameObject;
            selectMesh =Selection.activeGameObject.GetComponent<MeshFilter>().mesh;
            selectMeshCollider = Selection.activeGameObject.GetComponent<MeshCollider>();
            selectObjVectors = selectMesh.vertices;
    
    
            //获取游戏物体上的顶点在世界空间的坐标
            selectMeshVectorWPs = LocalToWorld(selectMesh.vertices, selectObj.transform);
    
    
        }
    
        #region 工具函数
        List<Vector3> LocalToWorld(Vector3[] s,Transform objTF)
        {
            List<Vector3> vector3s = new List<Vector3>();
            foreach (Vector3 i in s)
            {
                vector3s.Add(objTF.TransformPoint(i));
            }
            return vector3s;
        }
        Vector3[] WorldToLocal(List<Vector3> s, Transform objTF)
        {
            Vector3[] vector3s =new Vector3[s.Count];
            for (int i=0;i< s.Count;i++)
            {
                vector3s[i] = objTF.InverseTransformPoint(s[i]);
            }
            return vector3s;
        }
        #endregion
    
    
        void OnDisable()
        {
            instance = null;
            SceneView.duringSceneGui -= this.OnSceneGUI;
        }
    
        bool isShowSelectVector = false;
        void OnSceneGUI(SceneView sceneView)
        {
            //绘制选择框
            Handles.BeginGUI();
            if (starSelectPos != Vector2.zero)
            {
    
                Vector2 difference = mousePos - starSelectPos;
                difference = new Vector2(Mathf.Abs(difference.x), Mathf.Abs(difference.y));
                GUILayout.BeginArea(new Rect(starSelectPos, difference));
                GUILayout.Box("", SelectMouesDraw(), GUILayout.Height(difference.y), GUILayout.Width(difference.x));
                GUILayout.EndArea();
    
    
            }
            Handles.EndGUI();
    
            Handles.color = Color.green;
     
            //处理选择好的顶点
            if (isShowSelectVector)
            {
                SelectVertex(sceneView.camera);
                starSelectPos = Vector2.zero;
                isShowSelectVector = false;
            }
            //绘制选择的顶点并编辑
            if (selectedVertex != null)
            {
    
                Vector3 vtr3=Vector3.zero;
                Vector3 delta = Vector3.zero;
                foreach (Vector3 item in selectedVertex)
                {
                    Vector3 lastVtr = new Vector3(item.x, item.y, item.z);
                    
                    //给选中的点挂载拖动的方法
                    if (FreeMove)
                    {
                        vtr3=Handles.FreeMoveHandle(lastVtr, Quaternion.identity, 0.005f * sceneView.size, Vector3.zero, Handles.DotCap);
                    }
                    else
                    {
                        vtr3=Handles.PositionHandle(lastVtr, Quaternion.identity);
                    }
    
                    if(lastVtr!= vtr3)//有点被移动
                    {
                        delta = vtr3 - lastVtr;
                        break;
                    }
                    
                }
                //更新网格
                for (int k=0;k< selectedVertexIndex.Count;k++)
                {
                    selectMeshVectorWPs[selectedVertexIndex[k]] += delta;
                    selectedVertex[k] = selectMeshVectorWPs[selectedVertexIndex[k]];
                }
                selectMesh.vertices= WorldToLocal(selectMeshVectorWPs, selectObj.transform);
            }
    
            HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));//替换Uinity自带的默认控制
            SelectVectorGUI();
            sceneView.Repaint();
        }
    
        /// <summary>
        /// 选择顶点
        /// </summary>
        /// <param name="camera"></param>
        void SelectVertex(Camera camera)
        {
            //获取模型点在屏幕上的位置
            List<Vector3> vector3s = new List<Vector3>();
            foreach (Vector3 i in selectMeshVectorWPs)
            {
                vector3s.Add(camera.WorldToScreenPoint(i));
            }
            
            //获取在选取内的模型顶点
            float minX = Math.Min(mousePos.x, starSelectPos.x);
            float maxX = Math.Max(mousePos.x, starSelectPos.x);
            float minY = Math.Min(mousePos.y, starSelectPos.y);
            float maxY = Math.Max(mousePos.y, starSelectPos.y);
            selectedVertex = new List<Vector3>();
            selectedVertexIndex = new List<int>();
            for (int i=0;i< vector3s.Count;i++)
            {
                if (vector3s[i].x>= minX&& vector3s[i].x <= maxX && camera.scaledPixelHeight-vector3s[i].y <= maxY && camera.scaledPixelHeight-vector3s[i].y >= minY )//这里坐标有坑 选区是左上角为原点 实际上是左下角
                {
                    selectedVertex.Add(selectMeshVectorWPs[i]);
                    selectedVertexIndex.Add(i);
                }
            }
        }
        Vector2 mousePos;
        Vector2 starSelectPos;
        /// <summary>
        /// 检测输入
        /// </summary>
        void SelectVectorGUI()
        {
           
            Event e = Event.current;
            mousePos = e.mousePosition;
           
           
            if (e.type==EventType.MouseDrag&&e.control&&e.button==0)
            {
               
                if (starSelectPos == Vector2.zero)
                {
                    starSelectPos = new Vector2(mousePos.x, mousePos.y);
                }
                isShowSelectVector = false;
               /// Debug.LogError("开始选择");
                
            }
            if (e.type == EventType.MouseUp && e.control && e.button == 0)
            {
                isShowSelectVector = true;
            }
            
           
        }
        #region 保存和取消
        void Reset()
        {
            if (selectObjVectors != null)
            {
                selectMesh.vertices = selectObjVectors;
            }
        }
        bool SaveEdit()
        {
            if (SavePath.Equals(""))
            {
                Debug.LogError("没有选择保存路径");
                return false;
            }
            selectMeshCollider.sharedMesh= selectMesh;
            MeshUtility.Optimize(selectMesh);//优化网格
            string savePath = SavePath.Substring(SavePath.IndexOf("Assets"));
            AssetDatabase.CreateAsset(selectMesh, savePath + "/"+ selectObj.name+ ".asset");
            return true;
        }
        #endregion
        private void OnGUI()
        {
            GUILayout.BeginVertical();
            //标签
            GUILayout.BeginHorizontal();
            GUILayout.Box("正在编辑顶点...", TitleBoxStyle(), GUILayout.Height(60), GUILayout.ExpandWidth(true));
            GUILayout.EndHorizontal();
            GUILayout.Space(10);
            if (GUILayout.Button("选择源文件夹", GUILayout.Height(30), GUILayout.Width(180)))
            {
                SavePath = EditorUtility.OpenFolderPanel("选择源文件夹", "Assets/", "");
            }
            GUILayout.Space(10);
            FreeMove=GUILayout.Toggle(FreeMove,"自由拖拽");
    
            GUILayout.BeginHorizontal();
            if (GUILayout.Button("保存", GUILayout.Height(30)))
            {
                if (SaveEdit())
                {
                    instance.Close();
                }
                
            }
            GUILayout.Space(10);
            if (GUILayout.Button("取消", GUILayout.Height(30)))
            {
                Reset();
                instance.Close();
            }
            GUILayout.Space(10);
            GUILayout.EndHorizontal();
    
            GUILayout.EndVertical();
           
        }
        public GUIStyle TitleBoxStyle()
        {
            GUIStyle boxStyle = new GUIStyle();
    
            boxStyle.margin = new RectOffset(2, 2, 2, 2);
            boxStyle.border = new RectOffset(2, 2, 2, 2);
            boxStyle.fontSize = 25;
            boxStyle.fontStyle = FontStyle.Bold;
            boxStyle.alignment = TextAnchor.MiddleCenter;
            return boxStyle;
        }
        public GUIStyle SelectMouesDraw()
        {
            GUIStyle boxStyle = new GUIStyle();
            boxStyle.margin = new RectOffset(0, 0, 0, 0);
            boxStyle.border = new RectOffset(2, 2, 2, 2);
            boxStyle.padding = new RectOffset(0, 0, 0, 0);
            boxStyle.alignment = TextAnchor.MiddleCenter;
            Texture2D img = new Texture2D(1,1);
            Color[] colorlist = img.GetPixels();
            colorlist[0] = new Color(0,1,0,0.3f);
            img.SetPixels(colorlist);
            boxStyle.normal.background = img;
    
            return boxStyle;
        }
    }
    public class EditVectorManager
    {
        //网格
        [MenuItem("GameObject//编辑顶点", false, -1)]
        static void EditTerrainVector()
        {
            EditorWindow ew=EditorWindow.GetWindow<EditVector>(false, "编辑顶点", true);
            ew.Show();
        }
      
    }
    

      

    总结:

      基本上核心功能就是这些东西,时间有限很多东西都没来得及解释(有时间的话再添加详细解释),有不明白的地方可以留言,不对的地方希望大家指正。希望能和大家一起进步!

        

  • 相关阅读:
    451. Sort Characters By Frequency
    424. Longest Repeating Character Replacement
    68. Text Justification
    44. Wildcard Matching
    160. Intersection of Two Linked Lists
    24. Swap Nodes in Pairs
    93. 递归实现组合型枚举
    98. 分形之城
    97. 约数之和
    96. 奇怪的汉诺塔
  • 原文地址:https://www.cnblogs.com/littlebao/p/12387762.html
Copyright © 2011-2022 走看看