u3d change terrain textrue&height
using UnityEngine; using System.Collections; public class terrainTest : MonoBehaviour { public int terrainDeformationTextureNum = 1; private Terrain terr; // terrain to modify protected int hmWidth; // heightmap width protected int hmHeight; // heightmap height protected int alphaMapWidth; protected int alphaMapHeight; protected int numOfAlphaLayers; protected const float DEPTH_METER_CONVERT = 0.05f; protected const float TEXTURE_SIZE_MULTIPLIER = 1.25f; private float[,] heightMapBackup; private float[, ,] alphaMapBackup; void Start() { terr = this.GetComponent<Terrain>(); hmWidth = terr.terrainData.heightmapWidth; hmHeight = terr.terrainData.heightmapHeight; alphaMapWidth = terr.terrainData.alphamapWidth; alphaMapHeight = terr.terrainData.alphamapHeight; numOfAlphaLayers = terr.terrainData.alphamapLayers; if (Debug.isDebugBuild) { heightMapBackup = terr.terrainData.GetHeights(0, 0, hmWidth, hmHeight); alphaMapBackup = terr.terrainData.GetAlphamaps(0, 0, alphaMapWidth, alphaMapHeight); } } //this has to be done because terrains for some reason or another terrains don't reset after you run the app void OnApplicationQuit() { if (Debug.isDebugBuild) { terr.terrainData.SetHeights(0, 0, heightMapBackup); terr.terrainData.SetAlphamaps(0, 0, alphaMapBackup); } } public void DestroyTerrain(Vector3 pos, float craterSizeInMeters) { DeformTerrain(pos, craterSizeInMeters); TextureDeformation(pos, craterSizeInMeters * 1.5f); } public void DeformTerrain(Vector3 pos, float craterSizeInMeters) { //get the heights only once keep it and reuse, precalculate as much as possible Vector3 terrainPos = GetRelativeTerrainPositionFromPos(pos, terr, hmWidth, hmHeight);//terr.terrainData.heightmapResolution/terr.terrainData.heightmapWidth int heightMapCraterWidth = (int)(craterSizeInMeters * (hmWidth / terr.terrainData.size.x)); int heightMapCraterLength = (int)(craterSizeInMeters * (hmHeight / terr.terrainData.size.z)); int heightMapStartPosX = (int)(terrainPos.x - (heightMapCraterWidth / 2)); int heightMapStartPosZ = (int)(terrainPos.z - (heightMapCraterLength / 2)); float[,] heights = terr.terrainData.GetHeights(heightMapStartPosX, heightMapStartPosZ, heightMapCraterWidth, heightMapCraterLength); float circlePosX; float circlePosY; float distanceFromCenter; float depthMultiplier; float deformationDepth = (craterSizeInMeters / 3.0f) / terr.terrainData.size.y; // we set each sample of the terrain in the size to the desired height for (int i = 0; i < heightMapCraterLength; i++) //width { for (int j = 0; j < heightMapCraterWidth; j++) //height { circlePosX = (j - (heightMapCraterWidth / 2)) / (hmWidth / terr.terrainData.size.x); circlePosY = (i - (heightMapCraterLength / 2)) / (hmHeight / terr.terrainData.size.z); distanceFromCenter = Mathf.Abs(Mathf.Sqrt(circlePosX * circlePosX + circlePosY * circlePosY)); //convert back to values without skew if (distanceFromCenter < (craterSizeInMeters / 2.0f)) { depthMultiplier = ((craterSizeInMeters / 2.0f - distanceFromCenter) / (craterSizeInMeters / 2.0f)); depthMultiplier += 0.1f; depthMultiplier += Random.value * .1f; depthMultiplier = Mathf.Clamp(depthMultiplier, 0, 1); if(heights[i,j] <0.1) heights[i, j] = Mathf.Clamp(heights[i, j] +deformationDepth * depthMultiplier, 0, 1); } } } // set the new height terr.terrainData.SetHeights(heightMapStartPosX, heightMapStartPosZ, heights); } public void TextureDeformation(Vector3 pos, float craterSizeInMeters) { Vector3 alphaMapTerrainPos = GetRelativeTerrainPositionFromPos(pos, terr, alphaMapWidth, alphaMapHeight); int alphaMapCraterWidth = (int)(craterSizeInMeters * (alphaMapWidth / terr.terrainData.size.x)); int alphaMapCraterLength = (int)(craterSizeInMeters * (alphaMapHeight / terr.terrainData.size.z)); int alphaMapStartPosX = (int)(alphaMapTerrainPos.x - (alphaMapCraterWidth / 2)); int alphaMapStartPosZ = (int)(alphaMapTerrainPos.z - (alphaMapCraterLength / 2)); float[, ,] alphas = terr.terrainData.GetAlphamaps(alphaMapStartPosX, alphaMapStartPosZ, alphaMapCraterWidth, alphaMapCraterLength); float circlePosX; float circlePosY; float distanceFromCenter; for (int i = 0; i < alphaMapCraterLength; i++) //width { for (int j = 0; j < alphaMapCraterWidth; j++) //height { circlePosX = (j - (alphaMapCraterWidth / 2)) / (alphaMapWidth / terr.terrainData.size.x); circlePosY = (i - (alphaMapCraterLength / 2)) / (alphaMapHeight / terr.terrainData.size.z); //convert back to values without skew distanceFromCenter = Mathf.Abs(Mathf.Sqrt(circlePosX * circlePosX + circlePosY * circlePosY)); if (distanceFromCenter < (craterSizeInMeters / 2.0f)) { for (int layerCount = 0; layerCount < numOfAlphaLayers; layerCount++) { //could add blending here in the future if (layerCount == terrainDeformationTextureNum) { alphas[i, j, layerCount] = 1; } else { alphas[i, j, layerCount] = 0; } } } } } terr.terrainData.SetAlphamaps(alphaMapStartPosX, alphaMapStartPosZ, alphas); } protected Vector3 GetNormalizedPositionRelativeToTerrain(Vector3 pos, Terrain terrain) { //code based on: http://answers.unity3d.com/questions/3633/modifying-terrain-height-under-a-gameobject-at-runtime // get the normalized position of this game object relative to the terrain Vector3 tempCoord = (pos - terrain.gameObject.transform.position); Vector3 coord; coord.x = tempCoord.x / terr.terrainData.size.x; coord.y = tempCoord.y / terr.terrainData.size.y; coord.z = tempCoord.z / terr.terrainData.size.z; return coord; } protected Vector3 GetRelativeTerrainPositionFromPos(Vector3 pos, Terrain terrain, int mapWidth, int mapHeight) { Vector3 coord = GetNormalizedPositionRelativeToTerrain(pos, terrain); // get the position of the terrain heightmap where this game object is return new Vector3((coord.x * mapWidth), 0, (coord.z * mapHeight)); } }