public void textureTerrain(TextureProgressDelegate textureProgressDelegate) { Terrain ter = (Terrain) GetComponent(typeof(Terrain)); if (ter == null) { return; } TerrainData terData = ter.terrainData; splatPrototypes = terData.splatPrototypes; int nTextures = splatPrototypes.Length; if (nTextures < 2) { Debug.LogError("Error: You must assign at least 2 textures."); return; } textureProgressDelegate("Procedural Terrain Texture", "Generating height and slope maps. Please wait.", 0.1f); int Tw = terData.heightmapWidth - 1; int Th = terData.heightmapHeight - 1; float[,] heightMapData = new float[Tw, Th]; float[,] slopeMapData = new float[Tw, Th]; float[,,] splatMapData; terData.alphamapResolution = Tw; splatMapData = terData.GetAlphamaps(0, 0, Tw, Tw); // Angles to difference... Vector3 terSize = terData.size; float slopeBlendMinimum = ((terSize.x / Tw) * Mathf.Tan(slopeBlendMinAngle * Mathf.Deg2Rad)) / terSize.y; float slopeBlendMaximum = ((terSize.x / Tw) * Mathf.Tan(slopeBlendMaxAngle * Mathf.Deg2Rad)) / terSize.y; try { float greatestHeight = 0.0f; int xNeighbours; int yNeighbours; int xShift; int yShift; int xIndex; int yIndex; float[,] heightMap = terData.GetHeights(0, 0, Tw, Th); for (int Ty = 0; Ty < Th; Ty++) { // y... if (Ty == 0) { yNeighbours = 2; yShift = 0; yIndex = 0; } else if (Ty == Th - 1) { yNeighbours = 2; yShift = -1; yIndex = 1; } else { yNeighbours = 3; yShift = -1; yIndex = 1; } for (int Tx = 0; Tx < Tw; Tx++) { // x... if (Tx == 0) { xNeighbours = 2; xShift = 0; xIndex = 0; } else if (Tx == Tw - 1) { xNeighbours = 2; xShift = -1; xIndex = 1; } else { xNeighbours = 3; xShift = -1; xIndex = 1; } // Get height... float h = heightMap[Tx + xIndex + xShift, Ty + yIndex + yShift]; if (h > greatestHeight) { greatestHeight = h; } // ...and apply to height map... heightMapData[Tx, Ty] = h; // Calculate slope... float tCumulative = 0.0f; float nNeighbours = xNeighbours * yNeighbours - 1; int Ny; int Nx; float t; for (Ny = 0; Ny < yNeighbours; Ny++) { for (Nx = 0; Nx < xNeighbours; Nx++) { // Ignore the index... if (Nx != xIndex || Ny != yIndex) { t = Mathf.Abs(h - heightMap[Tx + Nx + xShift, Ty + Ny + yShift]); tCumulative += t; } } } float tAverage = tCumulative / nNeighbours; // ...and apply to the slope map... slopeMapData[Tx, Ty] = tAverage; } // Show progress... // float completePoints = Ty * Th; // float totalPoints = Tw * Th; // float percentComplete = (completePoints / totalPoints) * 0.6f; // textureProgressDelegate("Procedural Terrain Texture", "Generating height and slope maps. Please wait.", percentComplete); } // Blend slope... float sBlended; int Px; int Py; for (Py = 0; Py < Th; Py++) { for (Px = 0; Px < Tw; Px++) { sBlended = slopeMapData[Px, Py]; if (sBlended < slopeBlendMinimum) { sBlended = 0; } else if (sBlended < slopeBlendMaximum) { sBlended = (sBlended - slopeBlendMinimum) / (slopeBlendMaximum - slopeBlendMinimum); } else if (sBlended > slopeBlendMaximum) { sBlended = 1; } slopeMapData[Px, Py] = sBlended; splatMapData[Px, Py, 0] = sBlended; } } // Blend height maps... for (int i = 1; i < nTextures; i++) { for (Py = 0; Py < Th; Py++) { for (Px = 0; Px < Tw; Px++) { float hBlendInMinimum = 0; float hBlendInMaximum = 0; float hBlendOutMinimum = 1; float hBlendOutMaximum = 1; float hValue; float hBlended = 0; if (i > 1) { hBlendInMinimum = (float) heightBlendPoints[i * 2 - 4]; hBlendInMaximum = (float) heightBlendPoints[i * 2 - 3]; } if (i < nTextures - 1) { hBlendOutMinimum = (float) heightBlendPoints[i * 2 - 2]; hBlendOutMaximum = (float) heightBlendPoints[i * 2 - 1]; } hValue = heightMapData[Px, Py]; if (hValue >= hBlendInMaximum && hValue <= hBlendOutMinimum) { // Full... hBlended = 1; } else if (hValue >= hBlendInMinimum && hValue < hBlendInMaximum) { // Blend in... hBlended = (hValue - hBlendInMinimum) / (hBlendInMaximum - hBlendInMinimum); } else if (hValue > hBlendOutMinimum && hValue <= hBlendOutMaximum) { // Blend out... hBlended = 1 - ((hValue - hBlendOutMinimum) / (hBlendOutMaximum - hBlendOutMinimum)); } // Subtract slope... float sValue = slopeMapData[Px, Py]; hBlended -= sValue; if (hBlended < 0) { hBlended = 0; } splatMapData[Px, Py, i] = hBlended; } } } // Generate splat maps... textureProgressDelegate("Procedural Terrain Texture", "Generating splat map. Please wait.", 0.9f); terData.SetAlphamaps(0, 0, splatMapData); // Clean up... heightMapData = null; slopeMapData = null; splatMapData = null; } catch (Exception e) { // Clean up... heightMapData = null; slopeMapData = null; splatMapData = null; Debug.LogError("An error occurred: "+e); } }
public void TextureTerrain(float[] slopeStops, float[] heightStops, Texture2D[] textures) { if (slopeStops.Length != 2) { Debug.LogError("Error: slopeStops must have 2 values"); return; } if (heightStops.Length > 8) { Debug.LogError("Error: heightStops must have no more than 8 values"); return; } if (heightStops.Length % 2 != 0) { Debug.LogError("Error: heightStops must have an even number of values"); return; } int numTextures = textures.Length; int numTexturesByStops = (heightStops.Length / 2) + 2; if (numTextures != numTexturesByStops) { Debug.LogError("Error: heightStops contains an incorrect number of values"); return; } foreach (float stop in slopeStops) { if (stop < 0 || stop > 90) { Debug.LogError("Error: The value of all slopeStops must be in the range 0.0 to 90.0"); return; } } foreach (float stop in heightStops) { if (stop < 0 || stop > 1) { Debug.LogError("Error: The value of all heightStops must be in the range 0.0 to 1.0"); return; } } Terrain ter = (Terrain) GetComponent(typeof(Terrain)); TerrainData terData = ter.terrainData; splatPrototypes = terData.splatPrototypes; deleteAllSplatPrototypes(); int n = 0; foreach (Texture2D tex in textures) { addSplatPrototype(tex, n); n++; } slopeBlendMinAngle = slopeStops[0]; slopeBlendMaxAngle = slopeStops[1]; n = 0; foreach (float stop in heightStops) { heightBlendPoints[n] = stop; n++; } terData.splatPrototypes = splatPrototypes; TextureProgressDelegate textureProgressDelegate = new TextureProgressDelegate(dummyTextureProgress); textureTerrain(textureProgressDelegate); }