/// <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); } }
/// <summary> /// 获取当前位置在地图上的对应位置 /// </summary> /// <returns></returns> public bool GetPositionOnTerrain(Vector3 pos, out Vector3 posOnTerrain) { Terrain terrain = GetTerrain(pos); return(TerrainUtility.GetPositionOnTerrain(terrain, pos, out posOnTerrain)); }
/// <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); }
public void Undo(RuntimeTerrainEditor t) { TerrainUtility.SetAlphaMap(cmd.terrain, cmd.alphaMap, cmd.startMapIndex.x, cmd.startMapIndex.y); }
public void Undo(RuntimeTerrainEditor t) { TerrainUtility.SetDetailLayer(cmd.terrain, cmd.detailMap, cmd.startMapIndex.x, cmd.startMapIndex.y, cmd.layer); }