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

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM