Unity地形设计之地形平滑处理Smooth(十一)

平滑算法处理本身是基于模糊图像处理,在高度图中模糊高度也是完全相同的过程,模糊处理最简单的算法是对数字求平均值。

例如下面是一个高度图像以及像素,如果是在(x,y)处模糊,这个像素周围有8个相邻像素,我们将9个值相加并除以9,然后进行相应计算:

我们将上述平滑算法应用于平滑地形:

using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
public class CustomTerrain : MonoBehaviour { 
    public int smoothAmount = 2; 
    public Terrain terrain; //获取地形(物体)对象   
    public TerrainData terrainData;//TerrainData里有地形所有的数据 
    private void OnEnable()
    {       
        terrain = gameObject.GetComponent<Terrain>(); //初始化地形数据 先获取地形再获取本身的地形数据
        terrainData = Terrain.activeTerrain.terrainData;
    }
    //传入地形的任何一个点位置,获取这些点的邻居
    //对于顶部边缘的任何像素,有的方位都没有邻居,处理好地图边缘的值
    List<Vector2> GenerateNeighbours(Vector2 pos, int width, int height)
    {
        List<Vector2> neighbours = new List<Vector2>();
        for (int y = -1; y < 2; y++)
        {
            for (int x = -1; x < 2; x++)
            {
                if (!(x == 0 && y == 0))
                {
                    Vector2 nPos = new Vector2(Mathf.Clamp(pos.x + x, 0, width - 1),
                                                Mathf.Clamp(pos.y + y, 0, height - 1));
                    if (!neighbours.Contains(nPos))
                        neighbours.Add(nPos);//把点的邻居放在列表里
                }
            }
        }
        return neighbours;
    }

    public void Smooth()
    {
        //平滑处理不需要重置地形
        float[,] heightMap = terrainData.GetHeights(0, 0, terrainData.heightmapWidth, terrainData.heightmapHeight);
        float smoothProgress = 0;//使用系统进度条告诉用户程序正在运行中而不是崩溃状态
        EditorUtility.DisplayProgressBar("Smoothing Terrain",
                                 "Progress",
                                 smoothProgress);
        #region  多次Smooth循环,多次循环应用会执行很长时间,让人感觉系统是崩溃状态,其实不然
        for (int s = 0; s < smoothAmount; s++)
        {
            #region 这是一次Smooth循环: 获取地形高度图的每一个的高度值,求出自身与周围邻居相加的平均值
            for (int y = 0; y < terrainData.heightmapHeight; y++)
            {
                for (int x = 0; x < terrainData.heightmapWidth; x++)
                {
                    float avgHeight = heightMap[x, y];
                    List<Vector2> neighbours = GenerateNeighbours(new Vector2(x, y),
                                                                  terrainData.heightmapWidth,
                                                                  terrainData.heightmapHeight);
                    foreach (Vector2 n in neighbours)
                    {
                        //自身与周围邻居相加
                        avgHeight += heightMap[(int)n.x, (int)n.y];
                    }
                    //求出自身与周围邻居相加的平均值
                    heightMap[x, y] = avgHeight / ((float)neighbours.Count + 1);
                }
            }
            #endregion
            smoothProgress++;
            #endregion
            //更新系统进度条
            EditorUtility.DisplayProgressBar("Smoothing Terrain",
                                             "Progress",
                                             smoothProgress / smoothAmount);

        }
        terrainData.SetHeights(0, 0, heightMap);
        EditorUtility.ClearProgressBar();//平滑处理完之后系统进度条消失
    }

   
}

解释 下上面脚本方法里的嵌套for循环:


using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(CustomTerrain))]
public class CustomTerrainEditor : Editor {
    bool showSmooth = false;
    SerializedProperty smoothAmount;
    private void OnEnable()
    {         
        smoothAmount = serializedObject.FindProperty("smoothAmount");

    }
    //绘制编辑面板
    public override void OnInspectorGUI()
    {
        //更新所有序列化的值
        serializedObject.Update();
        //获取自定义的地形属性脚本组件
        CustomTerrain terrain = (CustomTerrain)target;
        #region  
        //创建平滑按钮
        showSmooth = EditorGUILayout.Foldout(showSmooth, "Smooth Terrain");
        if (showSmooth)
        {
          EditorGUILayout.IntSlider(smoothAmount, 1, 10, new GUIContent("smoothAmount"));
            if (GUILayout.Button("Smooth"))
            {
                terrain.Smooth();
            }

        }      
        #endregion
        //应用发生的所有更改
        serializedObject.ApplyModifiedProperties();

    }
   
}

结果:

发布了122 篇原创文章 · 获赞 13 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_40229737/article/details/103524221