Unity 自定义地形编辑器开发(一.快速创建基层模型地图)
废话不多说直接先看效果
下面是步骤
1.弹窗
效果:
代码:
public class InputImageToEditor : EditorWindow { public static InputImageToEditor instance; void OnEnable() { instance = this; } void OnDisable() { instance = null; } public Texture icon; string mapWidth="10", mapLength="0", mapPd="0"; string savePath; string mapName; bool IsDefault = true; void OnGUI() { byte[] bytes = File.ReadAllBytes("Assets/Texture/LOGO.png"); Texture2D texture = new Texture2D(200, 200); texture.LoadImage(bytes); icon = texture; EditorGUILayout.Space(); GUILayout.BeginVertical(); GUILayout.Space(10); GUILayout.Label(icon, GUILayout.Width(100), GUILayout.Height(100));//绘制图标 GUI.skin.label.fontSize = 14; GUI.skin.label.fontStyle = FontStyle.Bold; GUILayout.Label("输入相应参数"); GUI.skin.label.fontStyle = FontStyle.Normal; GUI.skin.label.fontSize = 12; GUILayout.Space(10); mapName = EditorGUILayout.TextField("设置地图名字", mapName); GUILayout.Space(10); mapWidth = EditorGUILayout.TextField("设置地图宽度", mapWidth); GUILayout.Space(10); EditorGUI.BeginDisabledGroup(true); //如果nextPath == null 为真,在Inspector面板上显示,承灰色(即不可操作) mapLength = EditorGUILayout.TextField("设置地图长度", mapWidth); EditorGUI.EndDisabledGroup(); GUILayout.Space(10); IsDefault = EditorGUILayout.Toggle("是否使用默认定点密度", IsDefault); if (!IsDefault) { GUILayout.Space(10); mapPd = EditorGUILayout.TextField("设置地图定点密度(建议为宽度X5)", mapPd); } else { mapPd = ""+int.Parse(mapWidth) * 5; } GUILayout.Space(10); if (GUILayout.Button("选择保存文件夹")) { savePath = EditorUtility.OpenFolderPanel("选择保存的文件夹", "Assets/", ""); } GUILayout.Space(10); GUILayout.EndVertical(); GUILayout.BeginHorizontal(); if (GUILayout.Button("确定")) { if (mapWidth.Length > 0) { XLZTerrainEditor.OpenImage(int.Parse(mapWidth), uint.Parse(mapPd), savePath,mapName); instance.Close(); EditorUtility.DisplayDialog("创建结果", "创建成功", "确定"); } else { Debug.LogError("请输入相应的值"); } } GUILayout.Space(120); if (GUILayout.Button("取消")) { instance.Close(); } GUILayout.EndHorizontal(); } }
2.调用弹窗选择图片并读取
效果
代码:
using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text.RegularExpressions; using System.Xml.Linq; using UnityEditor; using UnityEngine; using UnityEngine.UI; using System.Windows; public class XLZTerrainEditor { [MenuItem("Tools/创建基本地形", false, 21)] static void CreateBasicTerrain() { EditorWindow.GetWindow<InputImageToEditor>(false, "InputImageToEditor", true).Show(); } /// <summary> /// 发起Win会话读取选择的图片 /// </summary> public static void OpenImage(int mapWidth,uint mapPD,string savePath,string mapName) { string path= EditorUtility.OpenFilePanelWithFilters("选择文件", "C:\\Users\\Administrator\\Desktop", new string[] { "图片格式", "png,jpg,jpeg", "All files", "*" }); //创建文件读取流 FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read); fileStream.Seek(0, SeekOrigin.Begin); //创建文件长度缓冲区 byte[] bytes = new byte[fileStream.Length]; //读取文件 fileStream.Read(bytes, 0, (int)fileStream.Length); //释放文件读取流 fileStream.Close(); fileStream.Dispose(); fileStream = null; Texture2D texture = new Texture2D(1, 1); bool isload = texture.LoadImage(bytes); //Sprite tempSp = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0, 0)); //GameObject.Find("TestImage").GetComponent<Image>().sprite = tempSp; //GameObject tGO = new GameObject("testTerrain"); //DrawMesh(tGO, texture, mapWidth, mapPD); XLZMapMesh xLZMap = new XLZMapMesh(mapName, texture, savePath); xLZMap.CreatMesh(mapWidth, mapWidth, mapPD, mapPD, -10, 10); } }
3.创建网格地图模型
代码:
using UnityEngine; using System.Collections; using UnityEditor; using System.IO; public class XLZMapMesh { private GameObject mMesh; private Material mMaterial; private Texture2D mHeightImage; private Vector2 size;//长度和宽度 public float minHeight = -10;//最小高度 public float maxHeight = 10;//最大高度 private Vector2 segment;//长度的段数和宽度的段数 private float unitH;//最小高度和最大高度只差,值为正 private Vector3[] vertexes;//顶点数 private Vector2 uvs;//uvs坐标 private int[] triangles;//三角形索引 private string Name; private string SavePath=""; public XLZMapMesh(string name, Texture2D hMap,string savePath) { Name = name; mHeightImage = hMap; if (savePath!=null) { SavePath = savePath; } } public void CreatMesh(float width, float height, uint segmentX, uint segmentY, int min, int max) { size = new Vector2(width, height); maxHeight = max; minHeight = min; unitH = maxHeight - minHeight; segment = new Vector2(segmentX, segmentY); mMesh = new GameObject(); mMesh.name = Name; computeVertexes(); DrawMesh(); } private void computeVertexes() { int sum = Mathf.FloorToInt((segment.x + 1) * (segment.y + 1));//顶点总数 float w = size.x / segment.x;//每一段的长度 float h = size.y / segment.y; GetTriangles(); int index = 0; vertexes = new Vector3[sum]; for (int i = 0; i < segment.y + 1; i++) { for (int j = 0; j < segment.x + 1; j++) { vertexes[index] = new Vector3(j * w, GetHeight(mHeightImage,new Vector2(i/segment.x, j/ segment.y))* unitH, i * h); index++; } } } private void DrawMesh() { Mesh mesh = new Mesh(); mesh.name = Name; mMesh.AddComponent<MeshFilter>();//网格 mMesh.AddComponent<MeshRenderer>();//网格渲染器 mMaterial = new Material(Shader.Find("MTE/Legacy/4 Textures/Diffuse"));//材质 mMesh.GetComponent<Renderer>().material = mMaterial; /*设置mesh*/ mesh.Clear();//更新 mesh.vertices = vertexes; //mesh.uv mesh.triangles = triangles; mesh.RecalculateNormals(); mesh.RecalculateBounds(); mMesh.GetComponent<MeshFilter>().mesh= mesh; //SaveAll(mesh, mMaterial); } private void SaveAll(Mesh mesh, Material material) { string localPath = SavePath.Substring(SavePath.IndexOf("Assets")); localPath += "/" + Name; Directory.CreateDirectory(localPath); Object prefabObj = PrefabUtility.SaveAsPrefabAssetAndConnect(mMesh,localPath + "/" + Name + ".prefab",InteractionMode.AutomatedAction); AssetDatabase.CreateAsset(mMaterial, localPath + "/" + Name + ".mat"); AssetDatabase.CreateAsset(mesh, localPath + "/" + Name + ".asset"); } private int[] GetTriangles() { int sum = Mathf.FloorToInt(segment.x * segment.y * 6);//三角形顶点总数 triangles = new int[sum]; uint index = 0; for (int i = 0; i < segment.y; i++) { for (int j = 0; j < segment.x; j++) { int role = Mathf.FloorToInt(segment.x) + 1; int self = j + (i * role); int next = j + ((i + 1) * role); //顺时针 triangles[index] = self; triangles[index + 1] = next + 1; triangles[index + 2] = self + 1; triangles[index + 3] = self; triangles[index + 4] = next; triangles[index + 5] = next + 1; index += 6; } } return triangles; } private static float GetHeight(Texture2D texture, Vector2 uv) { if (texture != null) { Color c = GetColor(texture, uv); return c.r - 0.5f; } else { return 0.5f; } } private static Color GetColor(Texture2D texture, Vector2 uv) { Color color = texture.GetPixel(Mathf.FloorToInt(texture.width * uv.x), Mathf.FloorToInt(texture.height * uv.y)); return color; } }