private GetAlphamaps ( int x, int y, int width, int height ) : float[,,] | ||
x | int | |
y | int | |
width | int | |
height | int | |
return | float[,,] |
private static TextureData GetTerrainTextures(TerrainData terrainData) { return new TextureData { SplatMaps = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight), ControlTextureResolution = terrainData.alphamapResolution }; }
internal static void RemoveSplatTexture(TerrainData terrainData, int index) { Undo.RegisterCompleteObjectUndo((Object) terrainData, "Remove texture"); int alphamapWidth = terrainData.alphamapWidth; int alphamapHeight = terrainData.alphamapHeight; float[,,] alphamaps = terrainData.GetAlphamaps(0, 0, alphamapWidth, alphamapHeight); int length1 = alphamaps.GetLength(2); int length2 = length1 - 1; float[,,] map = new float[alphamapHeight, alphamapWidth, length2]; for (int index1 = 0; index1 < alphamapHeight; ++index1) { for (int index2 = 0; index2 < alphamapWidth; ++index2) { for (int index3 = 0; index3 < index; ++index3) map[index1, index2, index3] = alphamaps[index1, index2, index3]; for (int index3 = index + 1; index3 < length1; ++index3) map[index1, index2, index3 - 1] = alphamaps[index1, index2, index3]; } } for (int index1 = 0; index1 < alphamapHeight; ++index1) { for (int index2 = 0; index2 < alphamapWidth; ++index2) { float num1 = 0.0f; for (int index3 = 0; index3 < length2; ++index3) num1 += map[index1, index2, index3]; if ((double) num1 >= 0.01) { float num2 = 1f / num1; for (int index3 = 0; index3 < length2; ++index3) map[index1, index2, index3] *= num2; } else { for (int index3 = 0; index3 < length2; ++index3) map[index1, index2, index3] = index3 != 0 ? 0.0f : 1f; } } } SplatPrototype[] splatPrototypes = terrainData.splatPrototypes; SplatPrototype[] splatPrototypeArray = new SplatPrototype[splatPrototypes.Length - 1]; for (int index1 = 0; index1 < index; ++index1) splatPrototypeArray[index1] = splatPrototypes[index1]; for (int index1 = index + 1; index1 < length1; ++index1) splatPrototypeArray[index1 - 1] = splatPrototypes[index1]; terrainData.splatPrototypes = splatPrototypeArray; terrainData.SetAlphamaps(0, 0, map); }
/// <summary> /// Write the specified value using the writer. /// </summary> /// <param name="value">Value.</param> /// <param name="writer">Writer.</param> public override void Write(object value, ISaveGameWriter writer) { UnityEngine.TerrainData terrainData = (UnityEngine.TerrainData)value; float [,,] alphamaps = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight); float [,] heights = terrainData.GetHeights(0, 0, terrainData.heightmapResolution, terrainData.heightmapResolution); writer.WriteProperty("alphamaps", alphamaps); writer.WriteProperty("heights", heights); writer.WriteProperty("heightmapResolution", terrainData.heightmapResolution); writer.WriteProperty("size", terrainData.size); writer.WriteProperty("thickness", terrainData.thickness); writer.WriteProperty("wavingGrassStrength", terrainData.wavingGrassStrength); writer.WriteProperty("wavingGrassAmount", terrainData.wavingGrassAmount); writer.WriteProperty("wavingGrassSpeed", terrainData.wavingGrassSpeed); writer.WriteProperty("wavingGrassTint", terrainData.wavingGrassTint); writer.WriteProperty("detailPrototypes", terrainData.detailPrototypes); writer.WriteProperty("treeInstances", terrainData.treeInstances); writer.WriteProperty("treePrototypes", terrainData.treePrototypes); writer.WriteProperty("alphamapResolution", terrainData.alphamapResolution); writer.WriteProperty("baseMapResolution", terrainData.baseMapResolution); writer.WriteProperty("splatPrototypes", terrainData.splatPrototypes); writer.WriteProperty("name", terrainData.name); writer.WriteProperty("hideFlags", terrainData.hideFlags); }
/// <summary> /// Preprocess the terrain to clamp down on the number of splat maps which have weights on each control point. First pass /// limits the number of weights to the specified amount per control point. Since each rendered pixel is a blend of 4 possible /// control points, this still means a given pixel may need up to 4 weights even if the control point is clamped to 1 weight. /// In the second pass, we check all of the neighoring pixels to see if they have different weights- if they do, we clamp /// down to one less weight on this control point. The idea here is to create some extra headroom for the blend, but since /// you can still need 4 blend weights in some cases, there is no perfect solution to this issue when running with less than /// 4 blend weights. It does, however, greatly help when running under those constraints. /// /// </summary> /// <param name="bt">Bt.</param> /// <param name="maxWeights">Max weights.</param> /// <param name="secondPass">If set to <c>true</c> second pass.</param> public static void WeightLimitTerrain(MicroSplatTerrain bt, int maxWeights, bool secondPass = false) { Terrain t = bt.GetComponent <Terrain>(); if (t == null) { return; } UnityEngine.TerrainData td = t.terrainData; if (td == null) { return; } int w = td.alphamapWidth; int h = td.alphamapHeight; int l = td.alphamapLayers; Undo.RegisterCompleteObjectUndo(t, "Weight Limit Terrain"); var splats = td.GetAlphamaps(0, 0, w, h); float[] data = new float[16]; List <WeightPair> sorted = new List <WeightPair>(); List <int> validIndexes = new List <int>(); for (int x = 0; x < w; ++x) { for (int y = 0; y < h; ++y) { // gather all weights for (int i = 0; i < l; ++i) { data[i] = splats[x, y, i]; } sorted.Clear(); for (int i = 0; i < 16; ++i) { var wp = new WeightPair(); wp.index = i; wp.weight = data[i]; sorted.Add(wp); } sorted.Sort((w0, w1) => w1.weight.CompareTo(w0.weight)); // remove lower weights int allowedWeights = maxWeights; while (sorted.Count > allowedWeights) { sorted.RemoveAt(sorted.Count - 1); } // generate valid index list validIndexes.Clear(); for (int i = 0; i < sorted.Count; ++i) { if (sorted[i].weight > 0) { validIndexes.Add(sorted[i].index); } } // figure out if our neighbors have weights which we don't have- if so, clamp down harder to make room for blending.. // if not, allow us to blend fully. We do this in a second pass so that small weights are reduced before we make // this decision.. if (secondPass) { for (int xm = -1; xm < 2; ++xm) { for (int ym = -1; ym < 2; ++ym) { int nx = x + xm; int ny = y + ym; if (nx >= 0 && ny >= 0 && nx < w && ny < y) { for (int layer = 0; layer < l; ++layer) { float weight = splats[nx, ny, layer]; if (weight > 0 && !validIndexes.Contains(layer)) { allowedWeights = maxWeights - 1; } } } } } while (sorted.Count > allowedWeights) { sorted.RemoveAt(sorted.Count - 1); } // generate valid index list validIndexes.Clear(); for (int i = 0; i < sorted.Count; ++i) { if (sorted[i].weight > 0) { validIndexes.Add(sorted[i].index); } } } // clear non-valid indexes for (int j = 0; j < 16; ++j) { if (!validIndexes.Contains(j)) { data[j] = 0; } } // now normalize weights so that they total one on each pixel float total = 0; for (int j = 0; j < 16; ++j) { total += data[j]; } float scale = 1.0f / total; for (int j = 0; j < 16; ++j) { data[j] *= scale; } // now map back to splat data array for (int i = 0; i < l; ++i) { splats[x, y, i] = data[i]; } } } td.SetAlphamaps(0, 0, splats); }
void Start() { craterWidth = crater.width; craterHeight = crater.height; terrain = GetComponent<Terrain> (); data = terrain.terrainData; heightRestore = data.GetHeights (0, 0, data.heightmapWidth, data.heightmapHeight); alphaRestore = data.GetAlphamaps (0, 0, data.alphamapHeight, data.alphamapWidth); template = crater.GetPixels (); worker = new Thread (WorkerMethod); worker.Start (); StartCoroutine (ApplyDamage ()); }
public void PlaceDetails(ProgressDetailsDelegate progressDelegate) { Terrain ter = (Terrain) GetComponent(typeof(Terrain)); terrainData = ter.terrainData; int alphamapWidth = terrainData.alphamapWidth; int alphamapHeight = terrainData.alphamapHeight; int detailWidth = terrainData.detailResolution; int detailHeight = detailWidth; float resolutionDiffFactor = (float)alphamapWidth/detailWidth; float[,,] splatmap = terrainData.GetAlphamaps(0,0,alphamapWidth,alphamapHeight); float alphaValue = 0; int count = terrainData.detailPrototypes.Length * DetailPlacement.Textures.Count; float increment = 1 / count; float percentCompleted = 0.0f; //how big is one unit in real world xUnit = (float)terrainData.size.x / (float)(detailWidth); yUnit = (float)terrainData.size.z / (float)(detailHeight); System.Random random = new System.Random(); int randomInt; for(int detailIndex = 0; detailIndex < terrainData.detailPrototypes.Length; detailIndex++) { int[,] newDetailLayer = new int[detailWidth,detailHeight]; foreach(DetailTextureSettings texture in DetailPlacement.Textures) { DetailSettings ds = texture.Details[detailIndex]; ds.MinimumHeight = (int)ds.MinHeight; ds.MaximumHeight = (int)ds.MaxHeight; percentCompleted += increment; progressDelegate("Placing details", "Placing details", percentCompleted); if (ds.IsUsed == false) continue; //find where the texture is present for (int j = 0; j < detailWidth; j++) { for (int k = 0; k < detailHeight; k++) { alphaValue = splatmap[(int)(resolutionDiffFactor*j),(int)(resolutionDiffFactor*k),texture.Index]; if (alphaValue >= ds.AlphamapValue && !ds.FluentCoverage) { //recalculate this position to real height //also check if minimum height is allowed for this texture if (CalculateHeight(ter, j, k, ds)) { //rare plant is only low chance if (ds.Rare) { randomInt = random.Next(ds.ChanceToFind); if (randomInt == 1) newDetailLayer[j,k] = ds.Intensity; else newDetailLayer[j,k] = 0; } else { newDetailLayer[j,k] = ds.Intensity; } } else { newDetailLayer[j,k] = 0; } } else if (ds.FluentCoverage && alphaValue >= ds.AlphamapValue) { if (!CalculateHeight(ter, j, k, ds)) { newDetailLayer[j,k] = 0; continue; } float wholeCoverage = 1 - ds.AlphamapValue; float partCoverage = 1 - alphaValue; int intensity = 1; if (wholeCoverage != 0 && partCoverage != 0) { float percent = (wholeCoverage * 100) / partCoverage - 100; intensity = (int)(ds.Intensity * percent / 100 / ds.Smoothness); if (intensity == 0) intensity = 1; if (intensity > ds.Intensity) intensity = ds.Intensity; } if (alphaValue == 1 || ds.AlphamapValue == 1) intensity = ds.Intensity; newDetailLayer[j,k] = intensity; } } } } terrainData.SetDetailLayer(0,0,detailIndex,newDetailLayer); } }
// Use this for initialization private void Start() { m_CharacterController = GetComponent<CharacterController>(); m_Camera = Camera.main; m_OriginalCameraPosition = m_Camera.transform.localPosition; m_FovKick.Setup(m_Camera); m_HeadBob.Setup(m_Camera, m_StepInterval); m_StepCycle = 0f; m_NextStep = m_StepCycle/2f; m_Jumping = false; m_AudioSource = GetComponent<AudioSource>(); m_MouseLook.Init(transform , m_Camera.transform); mTerrainData = Terrain.activeTerrain.terrainData; alphamapWidth = mTerrainData.alphamapWidth; alphamapHeight = mTerrainData.alphamapHeight; mSplatmapData = mTerrainData.GetAlphamaps (0, 0, alphamapWidth, alphamapHeight); mNumTextures = mSplatmapData.Length / (alphamapWidth * alphamapHeight); }
static public void AddSplatmaps (TerrainData data, Matrix[] matrices, int[] channels, float[] opacity, float[,,] array=null, float brushFallof=0.5f) { int numChannels = data.alphamapLayers; bool[] usedChannels = new bool[numChannels]; for (int i=0; i<channels.Length; i++) usedChannels[channels[i]] = true; float[] slice = new float[numChannels]; Coord dataSize = new Coord(data.alphamapResolution, data.alphamapResolution); CoordRect dataRect = new CoordRect(new Coord(0,0), dataSize); CoordRect intersection = CoordRect.Intersect(dataRect, matrices[0].rect); if (array==null) array = data.GetAlphamaps(intersection.offset.x, intersection.offset.z, intersection.size.x, intersection.size.z); Coord min = intersection.Min; Coord max = intersection.Max; for (int x=min.x; x<max.x; x++) for (int z=min.z; z<max.z; z++) { //calculating fallof and opacity float fallofFactor = matrices[0].Fallof(x,z,brushFallof); if (Mathf.Approximately(fallofFactor,0)) continue; //reading slice for (int c=0; c<numChannels; c++) slice[c] = array[z-min.z, x-min.x, c]; //converting matrices to additive for (int i=0; i<matrices.Length; i++) matrices[i][x,z] = Mathf.Max(0, matrices[i][x,z] - slice[channels[i]]); //apply fallof for (int i=0; i<matrices.Length; i++) matrices[i][x,z] *= fallofFactor * opacity[i]; //calculating sum of adding values float addedSum = 0; //the sum of adding channels for (int i=0; i<matrices.Length; i++) addedSum += matrices[i][x,z]; //if (addedSum < 0.00001f) continue; //no need to do anything //if addedsum exceeds 1 - equalizing matrices if (addedSum > 1f) { for (int i=0; i<matrices.Length; i++) matrices[i][x,z] /= addedSum; addedSum=1; } //multiplying all values on a remaining amount float multiplier = 1-addedSum; for (int c=0; c<numChannels; c++) slice[c] *= multiplier; //adding matrices for (int i=0; i<matrices.Length; i++) slice[channels[i]] += matrices[i][x,z]; //saving slice for (int c=0; c<numChannels; c++) array[z-min.z, x-min.x, c] = slice[c]; } data.SetAlphamaps(intersection.offset.x, intersection.offset.z, array); }
public float[,,] ReadSplatmap (TerrainData data, int channel, float[,,] array=null) { CoordRect intersection = CoordRect.Intersect(rect, new CoordRect(0,0,data.alphamapResolution, data.alphamapResolution)); //get heights if (array==null) array = data.GetAlphamaps(intersection.offset.x, intersection.offset.z, intersection.size.x, intersection.size.z); //returns x and z swapped //reading array Coord min = intersection.Min; Coord max = intersection.Max; for (int x=min.x; x<max.x; x++) for (int z=min.z; z<max.z; z++) this[x,z] = array[z-min.z, x-min.x, channel]; //removing borders RemoveBorders(intersection); return array; }
public void generer(float lx, float lz) { this.lx = lx; this.lz = lz; data = terrain.terrainData; float[, ,] alphas = data.GetAlphamaps(0, 0, data.alphamapWidth, data.alphamapHeight); Debug.Log ("alpha width : " + data.alphamapWidth); Debug.Log ("alpha he : " + data.alphamapWidth); Debug.Log ("world size : " + data.size); Debug.Log ("distance between patch X : " + data.size[0] / data.alphamapWidth); Debug.Log ("distance between patch Y : " + data.size[1] / data.alphamapHeight); dx = data.size [0] / data.alphamapWidth; dz = data.size [2] / data.alphamapHeight; for (int i = 0; i < data.alphamapWidth; i++) { for (int j = 0; j < data.alphamapHeight; j++) { foreach (Terrains t in Enum.GetValues(typeof(Terrains))) { alphas[j, i, (int) t] = 0; } alphas[j, i, (int) Terrains.BANQUISE] = 100; } } data.SetAlphamaps(0, 0, alphas); changeHexagoneTexture (0, 0, Terrains.BANQUISE); }
/*returns an array containing the relative mix of textures on the main terrain at this world position.*/ private float[] GetTextureMix(Vector3 worldPos) { terrain = Terrain.activeTerrain; terrainData = terrain.terrainData; Vector3 terrainPos = terrain.transform.position; int mapX = (int)(((worldPos.x - terrainPos.x) / terrainData.size.x) * terrainData.alphamapWidth); int mapZ = (int)(((worldPos.z - terrainPos.z) / terrainData.size.z) * terrainData.alphamapHeight); float[,,] splatmapData = terrainData.GetAlphamaps(mapX,mapZ,1,1); float[] cellMix = new float[splatmapData.GetUpperBound(2)+1]; for (int n=0; n<cellMix.Length; ++n){ cellMix[n] = splatmapData[0,0,n]; } return cellMix; }
internal static void RemoveSplatTexture(TerrainData terrainData, int index) { Undo.RegisterCompleteObjectUndo(terrainData, "Remove texture"); int alphamapWidth = terrainData.alphamapWidth; int alphamapHeight = terrainData.alphamapHeight; float[,,] alphamaps = terrainData.GetAlphamaps(0, 0, alphamapWidth, alphamapHeight); int length = alphamaps.GetLength(2); int num = length - 1; float[,,] array = new float[alphamapHeight, alphamapWidth, num]; for (int i = 0; i < alphamapHeight; i++) { for (int j = 0; j < alphamapWidth; j++) { for (int k = 0; k < index; k++) { array[i, j, k] = alphamaps[i, j, k]; } for (int l = index + 1; l < length; l++) { array[i, j, l - 1] = alphamaps[i, j, l]; } } } for (int m = 0; m < alphamapHeight; m++) { for (int n = 0; n < alphamapWidth; n++) { float num2 = 0f; for (int num3 = 0; num3 < num; num3++) { num2 += array[m, n, num3]; } if ((double)num2 >= 0.01) { float num4 = 1f / num2; for (int num5 = 0; num5 < num; num5++) { array[m, n, num5] *= num4; } } else { for (int num6 = 0; num6 < num; num6++) { array[m, n, num6] = ((num6 != 0) ? 0f : 1f); } } } } SplatPrototype[] splatPrototypes = terrainData.splatPrototypes; SplatPrototype[] array2 = new SplatPrototype[splatPrototypes.Length - 1]; for (int num7 = 0; num7 < index; num7++) { array2[num7] = splatPrototypes[num7]; } for (int num8 = index + 1; num8 < length; num8++) { array2[num8 - 1] = splatPrototypes[num8]; } terrainData.splatPrototypes = array2; terrainData.SetAlphamaps(0, 0, array); }
/// <summary> /// Remove splatprototype /// </summary> /// <param name="td"></param> /// <param name="index"></param> public static void RemoveSplatTexture(TerrainData td, int index) { Point size = new Point(td.alphamapWidth, td.alphamapHeight); float[,,] alphamaps = td.GetAlphamaps(0, 0, size.x, size.y); float[,,] newAlphaMaps = new float[alphamaps.GetLength(0), alphamaps.GetLength(1), alphamaps.GetLength(2) - 1]; // Duplicate except the removed for (int i = 0; i < size.y; i++) { for (int j = 0; j < size.x; j++) { for (int k = 0; k < index; k++) { newAlphaMaps[i, j, k] = alphamaps[i, j, k]; } for (int l = index + 1; l < alphamaps.GetLength(2); l++) { newAlphaMaps[i, j, l - 1] = alphamaps[i, j, l]; } } } for (int i = 0; i < size.y; i++) { for (int j = 0; j < size.x; j++) { float alpha = 0f; for (int k = 0; k < alphamaps.GetLength(2) - 1; k++) { alpha += newAlphaMaps[i, j, k]; } if (alpha >= 0.01f) { for (int k = 0; k < alphamaps.GetLength(2) - 1; k++) { newAlphaMaps[i, j, k] *= (1.0f / alpha); } } else { for (int k = 0; k < alphamaps.GetLength(2) - 1; k++) { newAlphaMaps[i, j, k] = ((k != 0) ? 0f : 1f); } } } } SplatPrototype[] newSplat = new SplatPrototype[td.splatPrototypes.Length - 1]; for (int i = 0; i < index; i++) { newSplat[i] = td.splatPrototypes[i]; } for (int i = index + 1; i < alphamaps.GetLength(2); i++) { newSplat[i - 1] = td.splatPrototypes[i]; } td.splatPrototypes = newSplat; td.SetAlphamaps(0, 0, newAlphaMaps); }
void UpdateTerrainTexture( TerrainData terrainData ) { if(disableProceduralTerrain) return; float[, ,] alphas = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight); float alphaToHeightMapCoordsW = terrainData.heightmapWidth/terrainData.alphamapWidth; float alphaToHeightMapCoordsH = terrainData.heightmapHeight/terrainData.alphamapHeight; for (int i = 0; i < terrainData.alphamapWidth; i++) { for (int j = 0; j < terrainData.alphamapHeight; j++) { int hi = (int)(i*alphaToHeightMapCoordsW); int hj = (int)(j*alphaToHeightMapCoordsH); float terrainInterp = Mathf.Clamp((_heightMap[hi,hj] / snowHeight),0f,1f); alphas[i, j, 0] = 1f - terrainInterp; alphas[i, j, 1] = terrainInterp; } } terrainData.SetAlphamaps(0, 0, alphas); }
internal static void RemoveSplatTexture(TerrainData terrainData, int index) { Undo.RegisterCompleteObjectUndo(terrainData, "Remove texture"); int alphamapWidth = terrainData.alphamapWidth; int alphamapHeight = terrainData.alphamapHeight; float[,,] numArray = terrainData.GetAlphamaps(0, 0, alphamapWidth, alphamapHeight); int length = numArray.GetLength(2); int num4 = length - 1; float[,,] map = new float[alphamapHeight, alphamapWidth, num4]; for (int i = 0; i < alphamapHeight; i++) { for (int n = 0; n < alphamapWidth; n++) { for (int num7 = 0; num7 < index; num7++) { map[i, n, num7] = numArray[i, n, num7]; } for (int num8 = index + 1; num8 < length; num8++) { map[i, n, num8 - 1] = numArray[i, n, num8]; } } } for (int j = 0; j < alphamapHeight; j++) { for (int num10 = 0; num10 < alphamapWidth; num10++) { float num11 = 0f; for (int num12 = 0; num12 < num4; num12++) { num11 += map[j, num10, num12]; } if (num11 >= 0.01) { float num13 = 1f / num11; for (int num14 = 0; num14 < num4; num14++) { float single1 = map[j, num10, num14]; single1[0] *= num13; } } else { for (int num15 = 0; num15 < num4; num15++) { map[j, num10, num15] = (num15 != 0) ? 0f : 1f; } } } } SplatPrototype[] splatPrototypes = terrainData.splatPrototypes; SplatPrototype[] prototypeArray2 = new SplatPrototype[splatPrototypes.Length - 1]; for (int k = 0; k < index; k++) { prototypeArray2[k] = splatPrototypes[k]; } for (int m = index + 1; m < length; m++) { prototypeArray2[m - 1] = splatPrototypes[m]; } terrainData.splatPrototypes = prototypeArray2; terrainData.SetAlphamaps(0, 0, map); }
float[] GetTerrainTextureMix(Vector3 worldPos, TerrainData terrainData, Vector3 terrainPos) { // returns an array containing the relative mix of textures // on the main terrain at this world position. // The number of values in the array will equal the number // of textures added to the terrain. // calculate which splat map cell the worldPos falls within (ignoring y) int mapX = (int)(((worldPos.x - terrainPos.x) / terrainData.size.x) * terrainData.alphamapWidth); int mapZ = (int)(((worldPos.z - terrainPos.z) / terrainData.size.z) * terrainData.alphamapHeight); // get the splat data for this cell as a 1x1xN 3d array (where N = number of textures) float[,,] splatmapData = terrainData.GetAlphamaps(mapX, mapZ, 1, 1); // extract the 3D array data to a 1D array: float[] cellMix = new float[splatmapData.GetUpperBound(2) + 1]; for(int n = 0;n < cellMix.Length;n++) { cellMix[n] = splatmapData[0, 0, n]; } return cellMix; }