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;
    }
}

  

posted @ 2020-03-01 01:57  修齐治平丶  阅读(2009)  评论(0编辑  收藏  举报