/// <summary>
        /// 利用笔刷设置贴图
        /// </summary>
        public async void SetTextureWithBrush(Terrain terrain, Vector3 point, int index, float radius, float[,] brush)
        {
            Vector3 down = new Vector3(point.x - radius, 0, point.z - radius);

            if (terrain != null)
            {
                Vector2Int mapIndex  = TerrainUtility.GetAlphaMapIndex(terrain, down);
                int        mapRadius = (int)(radius / terrain.terrainData.size.x * terrain.terrainData.alphamapResolution);
                float[,,] map      = terrain.terrainData.GetAlphamaps(mapIndex.x, mapIndex.y, 2 * mapRadius, 2 * mapRadius);
                float[,] realBrush = await Math2d.ZoomBilinearInterpAsync(brush, 2 *mapRadius, 2 *mapRadius);

                // 这么计算所附加的贴图实际上是有问题的,但是我懒得继续算了
                for (int i = 0; i < map.GetLength(0); i++)
                {
                    for (int j = 0; j < map.GetLength(1); j++)
                    {
                        float temp = (1 - realBrush[i, j]) / (terrain.terrainData.alphamapLayers - 1);
                        for (int k = 0; k < terrain.terrainData.alphamapLayers; k++)
                        {
                            map[i, j, k] = temp;
                        }
                        map[i, j, index] = 1 - temp;
                    }
                }
                terrain.terrainData.SetAlphamaps(mapIndex.x, mapIndex.y, map);
            }
        }
        /// <summary>
        /// 设置贴图
        /// </summary>
        /// <param name="center">中心点</param>
        /// <param name="radius">半径</param>
        /// <param name="index">layer索引</param>
        /// <param name="strength">力度</param>
        /// <param name="isMix">是否混合, 如果为false 则strength无效</param>
        private void InternalSetTexture(Vector3 center, float radius, int index, float strength, bool isMix, bool regesterUndo)
        {
            Vector3 leftDown = new Vector3(center.x - radius, 0, center.z - radius);
            Terrain terrain  = Utility.SendRayDown(leftDown, LayerMask.GetMask("Terrain")).collider?.GetComponent <Terrain>();

            if (terrain != null)
            {
                // 获取数据
                TerrainData terrainData = terrain.terrainData;
                int         mapRadius   = (int)(radius / terrainData.size.x * terrainData.alphamapResolution);
                Vector2Int  mapIndex    = TerrainUtility.GetAlphaMapIndex(terrain, leftDown);
                float[,,] alphaMap = TerrainUtility.GetAlphaMap(terrain, mapIndex.x, mapIndex.y, 2 * mapRadius, 2 * mapRadius);

                if (regesterUndo)
                {
                    TextureCmdData textureCmdData = new TextureCmdData(terrain, mapIndex, alphaMap);
                    RegisterUndo(new TextureCmd(textureCmdData));
                }

                // 修改数据
                if (isMix)
                {
                    ChangeAlphaMap(alphaMap, index, strength);
                }
                else
                {
                    ChangeAlphaMapNoMix(alphaMap, index);
                }

                // 设置数据
                TerrainUtility.SetAlphaMap(terrain, alphaMap, mapIndex.x, mapIndex.y);
            }
        }
        /// <summary>
        /// 可跨多块地形的细节修改
        /// </summary>
        /// <param name="terrain"></param>
        /// <param name="center"></param>
        /// <param name="radius"></param>
        /// <param name="layer"></param>
        /// <param name="count"></param>
        private void InternalSetDetail(Vector3 center, float radius, int layer, int count, bool regesterUndo)
        {
            Vector3 leftDown = new Vector3(center.x - radius, 0, center.z - radius);
            Terrain terrain  = Utility.SendRayDown(leftDown, LayerMask.GetMask("Terrain")).collider?.GetComponent <Terrain>();

            if (terrain != null)
            {
                // 获取数据
                TerrainData terrainData = terrain.terrainData;
                int         mapRadius   = (int)(radius / terrainData.size.x * terrainData.detailResolution);
                Vector2Int  mapIndex    = TerrainUtility.GetDetialMapIndex(terrain, leftDown);
                int[,] detailMap = TerrainUtility.GetDetailLayer(terrain, mapIndex.x, mapIndex.y, 2 * mapRadius, 2 * mapRadius, layer);

                if (regesterUndo)
                {
                    DetialCmdData detialCmdData = new DetialCmdData(terrain, mapIndex, layer, detailMap);
                    RegisterUndo(new DetialCmd(detialCmdData));
                }

                // 修改数据
                ChangeDetailMap(detailMap, count);

                // 设置数据
                TerrainUtility.SetDetailLayer(terrain, detailMap, mapIndex.x, mapIndex.y, layer);
            }
        }
        /// <summary>
        /// 创建树木
        /// </summary>
        private void InternalCreatTree(Terrain terrain, Vector3 pos, int count, int radius, int index = 0)
        {
            TerrainData terrainData = terrain.terrainData;
            Vector3     relativePosition;
            Vector3     position;

            for (int i = 0; i < count; i++)
            {
                // 获取世界坐标系的位置和相对位置
                position         = pos + new Vector3(UnityEngine.Random.Range(-radius, radius), 0, UnityEngine.Random.Range(-radius, radius));
                relativePosition = position - terrain.GetPosition();

                if (Mathf.Pow(pos.x - position.x, 2) + Mathf.Pow(pos.z - position.z, 2) > radius * radius)
                {
                    i--; // 没有创建的数不计入
                    continue;
                }

                TreeInstance instance = TerrainUtility.GetTreeInstance(index);

                // 对跨地形做处理
                Vector3 p = new Vector3(relativePosition.x / terrainData.size.x, 0, relativePosition.z / terrainData.size.z);
                if (p.x > 1 || p.z > 1)
                {
                    if (p.x > 1)
                    {
                        p.x -= 1;
                    }
                    if (p.z > 1)
                    {
                        p.z -= 1;
                    }
                    instance.position = p;
                    GetTerrain(position)?.AddTreeInstance(instance);
                }
                else if (p.x < 0 || p.z < 0)
                {
                    if (p.x < 0)
                    {
                        p.x += 1;
                    }
                    if (p.z < 0)
                    {
                        p.z += 1;
                    }
                    instance.position = p;
                    GetTerrain(position)?.AddTreeInstance(instance);
                }
                else
                {
                    instance.position = p;
                    terrain.AddTreeInstance(instance);
                }
            }
        }
        /// <summary>
        /// 设置贴图
        /// </summary>
        /// <param name="point"></param>
        /// <param name="index"></param>
        public void InternalSetTexture(Vector3 center, float radius, int index, float strength)
        {
            Vector3 leftDown = new Vector3(center.x - radius, 0, center.z - radius);
            Terrain terrain  = Utility.SendRayDown(leftDown, LayerMask.GetMask("Terrain")).collider?.GetComponent <Terrain>();

            if (terrain != null)
            {
                // 获取数据
                TerrainData terrainData = terrain.terrainData;
                int         mapRadius   = (int)(radius / terrainData.size.x * terrainData.alphamapResolution);
                Vector2Int  mapIndex    = TerrainUtility.GetAlphaMapIndex(terrain, leftDown);
                float[,,] alphaMap = TerrainUtility.GetAlphaMap(terrain, mapIndex.x, mapIndex.y, 2 * mapRadius, 2 * mapRadius);

                // 修改数据
                ChangeAlphaMap(alphaMap, index, strength);

                // 设置数据
                TerrainUtility.SetAlphaMap(terrain, alphaMap, mapIndex.x, mapIndex.y);
            }
        }
Beispiel #6
0
        /// <summary>
        /// 获取当前位置在地图上的对应位置
        /// </summary>
        /// <returns></returns>
        public bool GetPositionOnTerrain(Vector3 pos, out Vector3 posOnTerrain)
        {
            Terrain terrain = GetTerrain(pos);

            return(TerrainUtility.GetPositionOnTerrain(terrain, pos, out posOnTerrain));
        }
Beispiel #7
0
        /// <summary>
        /// 获取地形上某一位置的坡度值
        /// </summary>
        /// <param name="pos"></param>
        public float GetSeepness(Vector3 pos)
        {
            Terrain terrain = GetTerrain(pos);

            return(TerrainUtility.GetSeepness(terrain, pos));
        }
        /// <summary>
        /// 初始化地形高度图编辑所需要的参数
        /// 后四个参数需要在调用前定义
        /// 编辑高度时所需要用到的参数后期打算用一个结构体封装
        /// </summary>
        /// <param name="center">目标中心</param>
        /// <param name="radius">半径</param>
        /// <param name="mapIndex">起始修改点在高度图上的索引</param>
        /// <param name="heightMap">要修改的高度二维数组</param>
        /// <param name="mapRadius">修改半径对应的索引半径</param>
        /// <param name="limit">限制高度</param>
        /// <returns></returns>
        private Terrain InitHMArg(Vector3 center, float radius, out HMArg arg)
        {
            Vector3 leftDown = new Vector3(center.x - radius, 0, center.z - radius);
            // 左下方Terrain
            Terrain centerTerrain   = Utility.SendRayDown(center, LayerMask.GetMask("Terrain")).collider?.GetComponent <Terrain>();
            Terrain leftDownTerrain = Utility.SendRayDown(leftDown, LayerMask.GetMask("Terrain")).collider?.GetComponent <Terrain>();

            arg = default(HMArg);
            if (leftDownTerrain != null)
            {
                // 获取相关参数
                arg.mapRadiusX     = (int)(heightMapRes / terrainSize.x * radius);
                arg.mapRadiusZ     = (int)(heightMapRes / terrainSize.z * radius);
                arg.mapRadiusX     = arg.mapRadiusX < 1 ? 1 : arg.mapRadiusX;
                arg.mapRadiusZ     = arg.mapRadiusZ < 1 ? 1 : arg.mapRadiusZ;
                arg.startMapIndex  = TerrainUtility.GetHeightmapIndex(leftDownTerrain, leftDown);
                arg.centerMapIndex = new Vector2Int(arg.startMapIndex.x + arg.mapRadiusX, arg.startMapIndex.y + arg.mapRadiusZ);
                arg.heightMap      = GetHeightMap(leftDownTerrain, arg.startMapIndex.x, arg.startMapIndex.y, 2 * arg.mapRadiusX, 2 * arg.mapRadiusZ);
                arg.limit          = 0 /*heightMap[mapRadius, mapRadius]*/;
                return(leftDownTerrain);
            }
            // 左下至少有一个方向没有Terrain,大多数情况下不会进入,如果删掉地图的左边界和下边界无法编辑,影响不大,其实我很想删掉,所以注释什么的就去TM的吧
            else if (centerTerrain != null)
            {
                // 获取相关参数
                arg.mapRadiusX = (int)(heightMapRes / terrainSize.x * radius);
                arg.mapRadiusZ = (int)(heightMapRes / terrainSize.z * radius);
                arg.mapRadiusX = arg.mapRadiusX < 1 ? 1 : arg.mapRadiusX;
                arg.mapRadiusZ = arg.mapRadiusZ < 1 ? 1 : arg.mapRadiusZ;

                arg.centerMapIndex = TerrainUtility.GetHeightmapIndex(centerTerrain, center);
                arg.startMapIndex  = new Vector2Int(arg.centerMapIndex.x - arg.mapRadiusX, arg.centerMapIndex.y - arg.mapRadiusZ);

                int width = 2 * arg.mapRadiusX, height = 2 * arg.mapRadiusZ;

                if (arg.startMapIndex.x < 0 && arg.startMapIndex.y < 0)
                {
                    if (centerTerrain.Left() != null)
                    {
                        height += arg.startMapIndex.y;
                        arg.startMapIndex.y  = 0;
                        arg.startMapIndex.x += heightMapRes;

                        centerTerrain = centerTerrain.Left();
                    }
                    else if (centerTerrain.Bottom() != null)
                    {
                        width += arg.startMapIndex.x;
                        arg.startMapIndex.x  = 0;
                        arg.startMapIndex.y += heightMapRes;

                        centerTerrain = centerTerrain.Bottom();
                    }
                    else
                    {
                        width += arg.startMapIndex.x;
                        arg.startMapIndex.x = 0;
                        height += arg.startMapIndex.y;
                        arg.startMapIndex.y = 0;
                    }
                }
                else if (arg.startMapIndex.x < 0)
                {
                    width += arg.startMapIndex.x;
                    arg.startMapIndex.x = 0;
                }
                else if (arg.startMapIndex.y < 0)
                {
                    height += arg.startMapIndex.y;
                    arg.startMapIndex.y = 0;
                }

                arg.heightMap = GetHeightMap(centerTerrain, arg.startMapIndex.x, arg.startMapIndex.y, width, height);
                arg.limit     = 0 /*heightMap[mapRadius, mapRadius]*/;
            }
            return(centerTerrain);
        }
Beispiel #9
0
 public void Undo(RuntimeTerrainEditor t)
 {
     TerrainUtility.SetAlphaMap(cmd.terrain, cmd.alphaMap, cmd.startMapIndex.x, cmd.startMapIndex.y);
 }
Beispiel #10
0
 public void Undo(RuntimeTerrainEditor t)
 {
     TerrainUtility.SetDetailLayer(cmd.terrain, cmd.detailMap, cmd.startMapIndex.x, cmd.startMapIndex.y, cmd.layer);
 }