public override void Generate(Chunk chunk, Biome biome = null) { //getting inputs SpatialHash objects = (SpatialHash)objectsIn.GetObject(chunk); Matrix src = (Matrix)canvasIn.GetObject(chunk); //return on stop/disable/null input if (chunk.stop || objects == null) { return; } if (!enabled) { output.SetObject(chunk, src); return; } //preparing output Matrix dst; if (src != null) { dst = src.Copy(null); } else { dst = chunk.defaultMatrix; } //finding maximum radius float maxRadius = radius; if (sizeFactor > 0.00001f) { float maxObjSize = 0; foreach (SpatialObject obj in objects.AllObjs()) { if (obj.size > maxObjSize) { maxObjSize = obj.size; } } maxObjSize = maxObjSize / MapMagic.instance.terrainSize * MapMagic.instance.resolution; //transforming to map-space maxRadius = radius * (1 - sizeFactor) + radius * maxObjSize * sizeFactor; } //preparing procedural matrices Matrix noiseMatrix = new Matrix(new CoordRect(0, 0, maxRadius * 2 + 2, maxRadius * 2 + 2)); Matrix percentMatrix = new Matrix(new CoordRect(0, 0, maxRadius * 2 + 2, maxRadius * 2 + 2)); foreach (SpatialObject obj in objects.AllObjs()) { //finding current radius float curRadius = radius * (1 - sizeFactor) + radius * obj.size * sizeFactor; curRadius = curRadius / MapMagic.instance.terrainSize * MapMagic.instance.resolution; //transforming to map-space //resizing procedural matrices CoordRect matrixSize = new CoordRect(0, 0, curRadius * 2 + 2, curRadius * 2 + 2); noiseMatrix.ChangeRect(matrixSize); percentMatrix.ChangeRect(matrixSize); //apply stamp noiseMatrix.rect.offset = new Coord((int)(obj.pos.x - curRadius - 1), (int)(obj.pos.y - curRadius - 1)); percentMatrix.rect.offset = new Coord((int)(obj.pos.x - curRadius - 1), (int)(obj.pos.y - curRadius - 1)); CoordRect intersection = CoordRect.Intersect(noiseMatrix.rect, dst.rect); 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++) { float dist = Mathf.Sqrt((x - obj.pos.x + 0.5f) * (x - obj.pos.x + 0.5f) + (z - obj.pos.y + 0.5f) * (z - obj.pos.y + 0.5f)); float percent = 1f - dist / curRadius; if (percent < 0 || dist > curRadius) { percent = 0; } percentMatrix[x, z] = percent; } } //adjusting value by curve Curve c = new Curve(curve); for (int i = 0; i < percentMatrix.array.Length; i++) { percentMatrix.array[i] = c.Evaluate(percentMatrix.array[i]); } //adding some noise if (useNoise) { NoiseGenerator.Noise(noiseMatrix, noiseSize, 0.5f, offset: Vector2.zero); for (int x = min.x; x < max.x; x++) { for (int z = min.z; z < max.z; z++) { float val = percentMatrix[x, z]; if (val < 0.0001f) { continue; } float noise = noiseMatrix[x, z]; if (val < 0.5f) { noise *= val * 2; } else { noise = 1 - (1 - noise) * (1 - val) * 2; } percentMatrix[x, z] = noise * noiseAmount + val * (1 - noiseAmount); } } } //applying matrices for (int x = min.x; x < max.x; x++) { for (int z = min.z; z < max.z; z++) { //float distSq = (x-obj.pos.x)*(x-obj.pos.x) + (z-obj.pos.y)*(z-obj.pos.y); //if (distSq > radius*radius) continue; float percent = percentMatrix[x, z]; dst[x, z] = (maxHeight? 1:obj.height) * percent + dst[x, z] * (1 - percent); } } } Matrix mask = (Matrix)maskIn.GetObject(chunk); if (mask != null) { Matrix.Mask(src, dst, mask); } if (safeBorders != 0) { Matrix.SafeBorders(src, dst, safeBorders); } //setting output if (chunk.stop) { return; } output.SetObject(chunk, dst); }
public static void Noise(Matrix matrix, float size, float intensity = 1, float bias = 0, float detail = 0.5f, Vector2 offset = new Vector2(), int seed = 12345, Matrix mask = null) { int step = (int)(4096f / matrix.rect.size.x); int totalSeedX = ((int)offset.x + MapMagic.instance.seed + seed * 7) % 77777; int totalSeedZ = ((int)offset.y + MapMagic.instance.seed + seed * 3) % 73333; //get number of iterations int numIterations = 1; //max size iteration included float tempSize = size; for (int i = 0; i < 100; i++) { tempSize = tempSize / 2; if (tempSize < 1) { break; } numIterations++; } //making some noise Coord min = matrix.rect.Min; Coord max = matrix.rect.Max; for (int x = min.x; x < max.x; x++) { for (int z = min.z; z < max.z; z++) { float result = 0.5f; float curSize = size * 10; float curAmount = 1; //applying noise for (int i = 0; i < numIterations; i++) { float perlin = Mathf.PerlinNoise( (x + totalSeedX + 1000 * (i + 1)) * step / (curSize + 1), (z + totalSeedZ + 100 * i) * step / (curSize + 1)); perlin = (perlin - 0.5f) * curAmount + 0.5f; //applying overlay if (perlin > 0.5f) { result = 1 - 2 * (1 - result) * (1 - perlin); } else { result = 2 * perlin * result; } curSize *= 0.5f; curAmount *= detail; //detail is 0.5 by default } //apply contrast and bias result = result * intensity; result -= 0 * (1 - bias) + (intensity - 1) * bias; //0.5f - intensity*bias; if (result < 0) { result = 0; } if (result > 1) { result = 1; } if (mask == null) { matrix[x, z] += result; } else { matrix[x, z] += result * mask[x, z]; } } } }
public override void Generate(Chunk chunk, Biome biome = null) { Matrix matrix = (Matrix)input.GetObject(chunk); if (matrix != null) { matrix = matrix.Copy(null); } if (matrix == null) { matrix = chunk.defaultMatrix; } Matrix mask = (Matrix)maskIn.GetObject(chunk); if (chunk.stop) { return; } if (!enabled || intensity == 0 || cellCount == 0) { output.SetObject(chunk, matrix); return; } //NoiseGenerator.Noise(matrix,200,0.5f,Vector2.zero); //matrix.Multiply(amount); InstanceRandom random = new InstanceRandom(MapMagic.instance.seed + seed); //creating point matrix float cellSize = 1f * matrix.rect.size.x / cellCount; Matrix2 <Vector3> points = new Matrix2 <Vector3>(new CoordRect(0, 0, cellCount + 2, cellCount + 2)); points.rect.offset = new Coord(-1, -1); Coord matrixSpaceOffset = new Coord((int)(matrix.rect.offset.x / cellSize), (int)(matrix.rect.offset.z / cellSize)); //scattering points for (int x = -1; x < points.rect.size.x - 1; x++) { for (int z = -1; z < points.rect.size.z - 1; z++) { Vector3 randomPoint = new Vector3(x + random.CoordinateRandom(x + matrixSpaceOffset.x, z + matrixSpaceOffset.z), 0, z + random.NextCoordinateRandom()); Vector3 centerPoint = new Vector3(x + 0.5f, 0, z + 0.5f); Vector3 point = randomPoint * (1 - uniformity) + centerPoint * uniformity; point = point * cellSize + new Vector3(matrix.rect.offset.x, 0, matrix.rect.offset.z); point.y = random.NextCoordinateRandom(); points[x, z] = point; } } Coord min = matrix.rect.Min; Coord max = matrix.rect.Max; for (int x = min.x; x < max.x; x++) { for (int z = min.z; z < max.z; z++) { //finding current cell Coord cell = new Coord((int)((x - matrix.rect.offset.x) / cellSize), (int)((z - matrix.rect.offset.z) / cellSize)); //finding min dist float minDist = 200000000; float secondMinDist = 200000000; float minHeight = 0; //float secondMinHeight = 0; for (int ix = -1; ix <= 1; ix++) { for (int iz = -1; iz <= 1; iz++) { Coord nearCell = new Coord(cell.x + ix, cell.z + iz); //if (!points.rect.CheckInRange(nearCell)) continue; //no need to perform test as points have 1-cell border around matrix Vector3 point = points[nearCell]; float dist = (x - point.x) * (x - point.x) + (z - point.z) * (z - point.z); if (dist < minDist) { secondMinDist = minDist; minDist = dist; minHeight = point.y; } else if (dist < secondMinDist) { secondMinDist = dist; } } } float val = 0; switch (blendType) { case BlendType.flat: val = minHeight; break; case BlendType.closest: val = minDist / (MapMagic.instance.resolution * 16); break; case BlendType.secondClosest: val = secondMinDist / (MapMagic.instance.resolution * 16); break; case BlendType.cellular: val = (secondMinDist - minDist) / (MapMagic.instance.resolution * 16); break; case BlendType.organic: val = (secondMinDist + minDist) / 2 / (MapMagic.instance.resolution * 16); break; } if (mask == null) { matrix[x, z] += val * intensity; } else { matrix[x, z] += val * intensity * mask[x, z]; } } } if (chunk.stop) { return; //do not write object is generating is stopped } output.SetObject(chunk, matrix); }
public static void Process(CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func <float, bool> stop = null) { #if VOXELAND if (stop != null && stop(0)) { return; } if (voxeland == null) { return; } //finding area by rect offset Coord areaCoord = Coord.PickCell(rect.offset.x, rect.offset.z, voxeland.data.areaSize); Voxeland5.Data.Area area = voxeland.data.areas[areaCoord.x, areaCoord.z]; //clearing grass area.ClearGrass(); //preparing random //Noise noise = new Noise(12345); //to switch grass depending on it's opacity //processing foreach (VoxelandGrassOutput gen in gens.GeneratorsOfType <VoxelandGrassOutput>(onlyEnabled:true, checkBiomes:true)) { //reading output directly if (stop != null && stop(0)) { return; //checking stop before reading output } //loading biome matrix Matrix biomeMask = null; if (gen.biome != null) { object biomeMaskObj = gen.biome.mask.GetObject(results); if (biomeMaskObj == null) { continue; //adding nothing if biome has no mask } biomeMask = (Matrix)biomeMaskObj; if (biomeMask == null) { continue; } if (biomeMask.IsEmpty()) { continue; //optimizing empty biomes } } //iterating layers for (int l = 0; l < gen.layers.Length; l++) { Layer layer = gen.layers[l]; //loading inputs Matrix src = (Matrix)layer.input.GetObject(results); if (src == null) { continue; } //multiplying with biome mask - in SetGrassLayer //apply //area.SetGrassLayer(src, (byte)l, layer.density, noise:noise, layerNum:l, mask:biomeMask); area.SetGrassLayer(src.rect.offset.x, src.rect.offset.z, src.rect.size.x, src.array, (byte)l, layer.density, l, biomeMask == null? null : biomeMask.array); } } //pushing to apply if (stop != null && stop(0)) { return; } results.apply.CheckAdd(typeof(VoxelandOutput), null, replace: true); #endif }
public override void Generate(Chunk chunk, Biome biome = null) { if (!enabled || chunk.stop) { return; } CoordRect scaledRect = new CoordRect( (int)(offset.x * MapMagic.instance.resolution / MapMagic.instance.terrainSize), (int)(offset.y * MapMagic.instance.resolution / MapMagic.instance.terrainSize), (int)(MapMagic.instance.resolution * scale), (int)(MapMagic.instance.resolution * scale)); Matrix stampMatrix = new Matrix(scaledRect); float gradientStep = 1f / stampMatrix.rect.size.x; Coord center = scaledRect.Center; float radius = stampMatrix.rect.size.x / 2f; Coord min = stampMatrix.rect.Min; Coord max = stampMatrix.rect.Max; switch (type) { case FormType.GradientX: for (int x = min.x; x < max.x; x++) { for (int z = min.z; z < max.z; z++) { stampMatrix[x, z] = x * gradientStep; } } break; case FormType.GradientZ: for (int x = min.x; x < max.x; x++) { for (int z = min.z; z < max.z; z++) { stampMatrix[x, z] = z * gradientStep; } } break; case FormType.Pyramid: for (int x = min.x; x < max.x; x++) { for (int z = min.z; z < max.z; z++) { float valX = x * gradientStep; if (valX > 1 - valX) { valX = 1 - valX; } float valZ = z * gradientStep; if (valZ > 1 - valZ) { valZ = 1 - valZ; } stampMatrix[x, z] = valX < valZ? valX * 2 : valZ * 2; } } break; case FormType.Cone: for (int x = min.x; x < max.x; x++) { for (int z = min.z; z < max.z; z++) { float val = 1 - (Coord.Distance(new Coord(x, z), center) / radius); if (val < 0) { val = 0; } stampMatrix[x, z] = val; } } break; } Matrix matrix = chunk.defaultMatrix; matrix.Replicate(stampMatrix, tile: tile); matrix.Multiply(intensity); //if (tile) textureMatrix.FromTextureTiled(texture); //else textureMatrix.FromTexture(texture); //if (!Mathf.Approximately(scale,1)) textureMatrix = textureMatrix.Resize(matrix.rect, result:matrix); if (chunk.stop) { return; } output.SetObject(chunk, matrix); }
public static void Process(CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func <float, bool> stop = null) { #if VOXELAND if (stop != null && stop(0)) { return; } if (voxeland == null) { return; } //TODO get height factor int heightFactor = 200; //finding area by rect offset Coord areaCoord = Coord.PickCell(rect.offset.x, rect.offset.z, voxeland.data.areaSize); Voxeland5.Data.Area area = voxeland.data.areas[areaCoord.x, areaCoord.z]; //clearing objects area.ClearObjects(); //preparing random Noise noise = new Noise(12345); //to disable biome objects //processing foreach (VoxelandObjectsOutput gen in gens.GeneratorsOfType <VoxelandObjectsOutput>(onlyEnabled:true, checkBiomes:true)) { //reading output directly //Output output = gen.areaOutput; if (stop != null && stop(0)) { return; //checking stop before reading output } //if (!results.results.ContainsKey(output)) continue; //Voxeland5.Data.Area genArea = (Voxeland5.Data.Area)results.results[output]; //loading biome matrix Matrix biomeMask = null; if (gen.biome != null) { object biomeMaskObj = gen.biome.mask.GetObject(results); if (biomeMaskObj == null) { continue; //adding nothing if biome has no mask } biomeMask = (Matrix)biomeMaskObj; if (biomeMask == null) { continue; } if (biomeMask.IsEmpty()) { continue; //optimizing empty biomes } } //iterating layers for (int l = 0; l < gen.layers.Length; l++) { Layer layer = gen.layers[l]; //loading inputs SpatialHash src = (SpatialHash)layer.input.GetObject(results); if (src == null) { continue; } foreach (SpatialObject obj in src.AllObjs()) { int objX = (int)(obj.pos.x + 0.5f); int objZ = (int)(obj.pos.y + 0.5f); //biome masking float biomeVal = 1; if (gen.biome != null) { if (biomeMask == null) { biomeVal = 0; } else { biomeVal = biomeMask[objX, objZ]; } } if (biomeVal < noise.Random(objX, objZ)) { continue; } //flooring float terrainHeight = layer.relativeHeight? results.heights[objX, objZ] : 0; int objHeight = (int)((obj.height + terrainHeight) * heightFactor + 0.5f); //area.AddObject(new CoordDir(objX, objHeight, objZ), (short)l); area.AddObject(objX, objHeight, objZ, 0, (short)l); } } } //pushing to apply if (stop != null && stop(0)) { return; } results.apply.CheckAdd(typeof(VoxelandOutput), null, replace: true); #endif }
public static void Process(CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func <float, bool> stop = null) { #if VOXELAND if (stop != null && stop(0)) { return; } if (voxeland == null) { return; } //TODO get height factor int heightFactor = 200; //finding area by rect offset Coord areaCoord = Coord.PickCell(rect.offset.x, rect.offset.z, voxeland.data.areaSize); Voxeland5.Data.Area area = voxeland.data.areas[areaCoord.x, areaCoord.z]; //clearing area area.ClearLand(); //finding a list of areas and their opacities List <Voxeland5.Data.Area> areas = new List <Voxeland5.Data.Area>(); List <Matrix> opacities = new List <Matrix>(); foreach (VoxelandOutput gen in gens.GeneratorsOfType <VoxelandOutput>(onlyEnabled:true, checkBiomes:true)) { //reading output directly Output output = gen.areaOutput; if (stop != null && stop(0)) { return; //checking stop before reading output } if (!results.results.ContainsKey(output)) { continue; } Voxeland5.Data.Area genArea = (Voxeland5.Data.Area)results.results[output]; //loading biome matrix Matrix biomeMask = null; if (gen.biome != null) { object biomeMaskObj = gen.biome.mask.GetObject(results); if (biomeMaskObj == null) { continue; //adding nothing if biome has no mask } biomeMask = (Matrix)biomeMaskObj; if (biomeMask == null) { continue; } if (biomeMask.IsEmpty()) { continue; //optimizing empty biomes } } areas.Add(genArea); opacities.Add(biomeMask); } //merge areas using biome mask if (areas.Count >= 2) //area.MixAreas(areas.ToArray(), opacities.ToArray()); { float[][] opacityArrays = new float[opacities.Count][]; for (int i = 0; i < opacityArrays.Length; i++) { if (opacities[i] != null) { opacityArrays[i] = opacities[i].array; } } area.MixAreas(areas.ToArray(), rect.offset.x, rect.offset.z, rect.size.x, opacityArrays); } else { Voxeland5.Data.Area.CopyLand(areas[0], area); } //reading heights if (results.heights == null || results.heights.rect.size.x != rect.size.x) { results.heights = new Matrix(rect); } if (results.heights.rect != rect) { results.heights.Resize(rect); } results.heights.Clear(); for (int x = 0; x < results.heights.rect.size.x; x++) { for (int z = 0; z < results.heights.rect.size.z; z++) { results.heights[x + results.heights.rect.offset.x, z + results.heights.rect.offset.z] = 1f * area.lines[x].columns[z].topLevel / heightFactor; } } //pushing to apply if (stop != null && stop(0)) { return; } results.apply.CheckAdd(typeof(VoxelandOutput), null, replace: true); #endif }
public IEnumerator Apply(MapMagic.CoordRect rect, Terrain terrain, object dataBox, Func <float, bool> stop = null) { TupleSet <float[, , ], SplatPrototypeWrapper[]> splatsTuple = (TupleSet <float[, , ], SplatPrototypeWrapper[]>)dataBox; float[,,] splats3D = splatsTuple.item1; SplatPrototypeWrapper[] prototypes = splatsTuple.item2; if (splats3D.GetLength(2) == 0) { Purge(rect, terrain); yield break; } //TerrainData data = terrain.terrainData; //setting resolution //int size = splats3D.GetLength(0); //if (data.alphamapResolution != size) data.alphamapResolution = size; //checking prototypes texture for (int i = 0; i < prototypes.Length; i++) { if (prototypes[i].Texture == null) { prototypes[i].Texture = defaultTex; } } yield return(null); //welding if (MapMagic.MapMagic.instance != null && MapMagic.MapMagic.instance.splatsWeldMargins != 0) { MapMagic.Coord coord = MapMagic.Coord.PickCell(rect.offset, MapMagic.MapMagic.instance.resolution); //Chunk chunk = MapMagic.MapMagic.instance.chunks[coord.x, coord.z]; Chunk neigPrevX = MapMagic.MapMagic.instance.chunks[coord.x - 1, coord.z]; if (neigPrevX != null && neigPrevX.worker.ready) { WeldTerrains.WeldSplatToPrevX(ref splats3D, neigPrevX.terrain, MapMagic.MapMagic.instance.splatsWeldMargins); } Chunk neigNextX = MapMagic.MapMagic.instance.chunks[coord.x + 1, coord.z]; if (neigNextX != null && neigNextX.worker.ready) { WeldTerrains.WeldSplatToNextX(ref splats3D, neigNextX.terrain, MapMagic.MapMagic.instance.splatsWeldMargins); } Chunk neigPrevZ = MapMagic.MapMagic.instance.chunks[coord.x, coord.z - 1]; if (neigPrevZ != null && neigPrevZ.worker.ready) { WeldTerrains.WeldSplatToPrevZ(ref splats3D, neigPrevZ.terrain, MapMagic.MapMagic.instance.splatsWeldMargins); } Chunk neigNextZ = MapMagic.MapMagic.instance.chunks[coord.x, coord.z + 1]; if (neigNextZ != null && neigNextZ.worker.ready) { WeldTerrains.WeldSplatToNextZ(ref splats3D, neigNextZ.terrain, MapMagic.MapMagic.instance.splatsWeldMargins); } } yield return(null); terrain.terrainData.splatPrototypes = new[] { new SplatPrototype() { texture = defaultTex } }; // To stop MapMagic purging what we're doing here alter on... var wrapper = terrain.gameObject.GetOrAddComponent <TerrainWrapper>(); var MMTerrainLayer = wrapper.GetLayer <MMTerrainLayer>(LayerName, false, true); MMTerrainLayer.SplatData.Clear(); var splatWidth = splats3D.GetLength(0); var splatHeight = splats3D.GetLength(1); if (terrain.terrainData.alphamapResolution != splatWidth) { Debug.Log("Set alphamapResolution to " + splatWidth); terrain.terrainData.alphamapResolution = splatWidth; } var data = new float[splatWidth, splatHeight]; for (int i = 0; i < prototypes.Length; i++) { var splatPrototypeWrapper = prototypes[i]; for (var u = 0; u < splatWidth; ++u) { for (var v = 0; v < splatHeight; ++v) { data[v, u] = splats3D[u, v, i]; } } MMTerrainLayer.SetSplatmap(splatPrototypeWrapper, 0, 0, data, splatWidth); } global::MapMagic.MapMagic.OnApplyCompleted -= MapMagicIntegrationUtilities.MapMagicOnOnApplyCompleted; global::MapMagic.MapMagic.OnApplyCompleted += MapMagicIntegrationUtilities.MapMagicOnOnApplyCompleted; wrapper.SetDirtyAbove(MMTerrainLayer); yield return(null); }
static void DrawMatrices() { //refreshing matrices if needed if (RefreshMatricesNeeded()) { RefreshMatrices(); } //getting pixel size float pixelSize = GetPixelSize(); //preparing shader Shader previewShader = MapMagic.instance.previewShader; //Shader.Find("MapMagic/TerrainPreview"); //apply matrix textures to all objects foreach (Transform tfm in mapMagic.Transforms()) { MeshRenderer renderer = tfm.GetComponent <MeshRenderer>(); Terrain terrain = tfm.GetComponent <Terrain>(); if (renderer == null && terrain == null) { continue; } //finding object rect Rect worldRect = new Rect(0, 0, 0, 0); if (renderer != null) { worldRect = new Rect(renderer.bounds.min.x, renderer.bounds.min.z, renderer.bounds.size.x, renderer.bounds.size.z); } else if (terrain != null) { worldRect = new Rect(terrain.transform.localPosition.x, terrain.transform.localPosition.z, terrain.terrainData.size.x, terrain.terrainData.size.z); } CoordRect matrixRect = CoordRect.PickIntersectingCellsByPos(worldRect, pixelSize); //finding a matrix/texture that object should use Coord center = matrixRect.Center; foreach (KeyValuePair <Matrix, Texture2D> kvp in matrices) { Matrix matrix = kvp.Key; // Using the matrix that contains center - it would be the biggest intersection if (matrix.rect.Contains(center.x, center.z)) { Texture2D texture = kvp.Value; //assigning material Material material = null; if (renderer != null) { if (renderer.sharedMaterial.shader != previewShader) { if (!originalMaterials.ContainsKey(tfm)) { originalMaterials.Add(tfm, renderer.sharedMaterial); } renderer.sharedMaterial = new Material(previewShader); } material = renderer.sharedMaterial; } else if (terrain != null) { #if UNITY_2019_2_OR_NEWER if (terrain.materialTemplate == null || terrain.materialTemplate.shader != previewShader) { if (!originalMaterials.ContainsKey(tfm)) { originalMaterials.Add(tfm, terrain.materialTemplate); } else { originalMaterials[tfm] = terrain.materialTemplate; } terrain.materialTemplate = new Material(previewShader); } #else if (terrain.materialTemplate == null || terrain.materialTemplate.shader != previewShader) { if (terrain.materialType == Terrain.MaterialType.Custom && !originalMaterials.ContainsKey(tfm)) { originalMaterials.Add(tfm, terrain.materialTemplate); } terrain.materialTemplate = new Material(previewShader); } terrain.materialType = Terrain.MaterialType.Custom; #endif material = terrain.materialTemplate; } //assigning texture and params material.name = tfm.name + " Preview"; //calculate parent MM object offset //Vector3 offset = tfm.parent.position / (worldRect.size.x/matrix.rect.size.x); // /pixelsize material.SetTexture("_Preview", texture); material.SetVector("_Rect", new Vector4(matrix.rect.offset.x, matrix.rect.offset.z, matrix.rect.size.x, matrix.rect.size.z)); material.SetFloat("_Scale", pixelSize); break; //interrupting when texture assigned (to center) } } } }
public IEnumerator Apply(MapMagic.CoordRect rect, Terrain terrain, object dataBox, Func <float, bool> stop = null) { //init heights #if UN_MapMagic #if WDEBUG Profiler.BeginSample("UNature"); #endif uNatureHeightTuple heightTuple; float[,] heights2D; if (FoliageCore_MainManager.instance != null) { heightTuple = (uNatureHeightTuple)dataBox; // get data heights2D = heightTuple.normalizedHeights; UNMapMagic_Manager.ApplyHeightOutput(heightTuple, terrain); } else { //Debug.LogError("uNature_MapMagic extension is enabled but no foliage manager exists on the scene."); //yield break; heights2D = (float[, ])dataBox; } #if WDEBUG Profiler.EndSample(); #endif #else float[,] heights2D = (float[, ])dataBox; #endif heights2D = heights2D.Flip(); //quick lod apply /*if (chunk.lod) * { * //if (chunk.lodTerrain == null) { chunk.lodTerrain = (MapMagic.instance.transform.AddChild("Terrain " + chunk.coord.x + "," + chunk.coord.z + " LOD")).gameObject.AddComponent<Terrain>(); chunk.lodTerrain.terrainData = new TerrainData(); } * if (chunk.lodTerrain.terrainData==null) chunk.lodTerrain.terrainData = new TerrainData(); * * chunk.lodTerrain.Resize(heights2D.GetLength(0), new Vector3(MapMagic.instance.terrainSize, MapMagic.instance.terrainHeight, MapMagic.instance.terrainSize)); * chunk.lodTerrain.terrainData.SetHeightsDelayLOD(0,0,heights2D); * * yield break; * }*/ //determining data if (terrain == null || terrain.terrainData == null) { yield break; //chunk removed during apply } TerrainData data = terrain.terrainData; //resizing terrain (standard terrain resize is extremely slow. Even when creating a new terrain) Vector3 terrainSize = terrain.terrainData.size; //new Vector3(MapMagic.instance.terrainSize, MapMagic.instance.terrainHeight, MapMagic.instance.terrainSize); int terrainResolution = heights2D.GetLength(0); //heights2D[0].GetLength(0); if ((data.size - terrainSize).sqrMagnitude > 0.01f || data.heightmapResolution != terrainResolution) { if (terrainResolution <= 64) //brute force { data.heightmapResolution = terrainResolution; data.size = new Vector3(terrainSize.x, terrainSize.y, terrainSize.z); } else //setting res 64, re-scaling to 1/64, and then changing res { data.heightmapResolution = 65; terrain.Flush(); //otherwise unity crushes without an error int resFactor = (terrainResolution - 1) / 64; data.size = new Vector3(terrainSize.x / resFactor, terrainSize.y, terrainSize.z / resFactor); data.heightmapResolution = terrainResolution; } } yield return(null); var heightSize = heights2D.GetLength(0); for (int x = 0; x < heightSize - 1; x++) { for (int z = 0; z < heightSize - 1; z++) { heights2D[z, x] = Mathf.Clamp01(heights2D[z, x]); } } var wrapper = terrain.gameObject.GetOrAddComponent <TerrainWrapper>(); var MMTerrainLayer = wrapper.GetLayer <MMTerrainLayer>(LayerName, false, true); MMTerrainLayer.SetHeights(0, 0, heights2D, MapMagic.MapMagic.instance.resolution + 1); _pendingWrappers.Remove(rect); //welding if (MapMagic.MapMagic.instance != null && MapMagic.MapMagic.instance.heightWeldMargins != 0) { MapMagic.Coord coord = MapMagic.Coord.PickCell(rect.offset, MapMagic.MapMagic.instance.resolution); Chunk chunk = MapMagic.MapMagic.instance.chunks[coord.x, coord.z]; Chunk neigPrevX = MapMagic.MapMagic.instance.chunks[coord.x - 1, coord.z]; if (neigPrevX != null && !_pendingWrappers.Contains(neigPrevX.rect) && neigPrevX.terrain && neigPrevX.terrain.terrainData.heightmapResolution == terrainResolution) { var neighbourWrapper = neigPrevX.terrain.GetComponent <TerrainWrapper>(); if (neigPrevX.worker.ready && neighbourWrapper) { WeldTerrains.WeldToPrevZ(ref heights2D, neighbourWrapper, MapMagic.MapMagic.instance.heightWeldMargins); } //WeldTerrains.WeldToPrevX(ref heights2D, neighbourWrapper, MapMagic.MapMagic.instance.heightWeldMargins); Chunk.SetNeigsX(neigPrevX, chunk); } Chunk neigNextX = MapMagic.MapMagic.instance.chunks[coord.x + 1, coord.z]; if (neigNextX != null && !_pendingWrappers.Contains(neigNextX.rect) && neigNextX.terrain.terrainData.heightmapResolution == terrainResolution) { var neighbourWrapper = neigNextX.terrain.GetComponent <TerrainWrapper>(); if (neigNextX.worker.ready && neighbourWrapper) { WeldTerrains.WeldToNextZ(ref heights2D, neighbourWrapper, MapMagic.MapMagic.instance.heightWeldMargins); } //WeldTerrains.WeldToNextX(ref heights2D, neighbourWrapper, MapMagic.MapMagic.instance.heightWeldMargins); Chunk.SetNeigsX(chunk, neigNextX); } Chunk neigPrevZ = MapMagic.MapMagic.instance.chunks[coord.x, coord.z - 1]; if (neigPrevZ != null && !_pendingWrappers.Contains(neigPrevZ.rect) && neigPrevZ.terrain.terrainData.heightmapResolution == terrainResolution) { var neighbourWrapper = neigPrevZ.terrain.GetComponent <TerrainWrapper>(); if (neigPrevZ.worker.ready && neighbourWrapper) { //WeldTerrains.WeldToNextX(ref heights2D, neighbourWrapper, MapMagic.MapMagic.instance.heightWeldMargins); WeldTerrains.WeldToPrevX(ref heights2D, neighbourWrapper, MapMagic.MapMagic.instance.heightWeldMargins); } Chunk.SetNeigsZ(neigPrevZ, chunk); } Chunk neigNextZ = MapMagic.MapMagic.instance.chunks[coord.x, coord.z + 1]; if (neigNextZ != null && !_pendingWrappers.Contains(neigNextZ.rect) && neigNextZ.terrain.terrainData.heightmapResolution == terrainResolution) { var neighbourWrapper = neigNextZ.terrain.GetComponent <TerrainWrapper>(); if (neigNextZ.worker.ready && neighbourWrapper) { //WeldTerrains.WeldToPrevX(ref heights2D, neighbourWrapper, MapMagic.MapMagic.instance.heightWeldMargins); WeldTerrains.WeldToNextX(ref heights2D, neighbourWrapper, MapMagic.MapMagic.instance.heightWeldMargins); } Chunk.SetNeigsZ(chunk, neigNextZ); } } yield return(null); MMTerrainLayer.SetHeights(0, 0, heights2D, MapMagic.MapMagic.instance.resolution + 1); global::MapMagic.MapMagic.OnApplyCompleted -= MapMagicIntegrationUtilities.MapMagicOnOnApplyCompleted; global::MapMagic.MapMagic.OnApplyCompleted += MapMagicIntegrationUtilities.MapMagicOnOnApplyCompleted; wrapper.SetDirtyAbove(MMTerrainLayer); yield return(null); }