public override void Generate(CoordRect rect, Chunk.Results results, Chunk.Size terrainSize, int seed, Func <float, bool> stop = null) { object obj = null; if (input.link != null && enabled) { obj = input.GetObject(results); } else { if (type == InoutType.Map) { obj = new Matrix(rect); } if (type == InoutType.Objects) { obj = new SpatialHash(new Vector2(rect.offset.x, rect.offset.z), rect.size.x, 16); } } if (stop != null && stop(0)) { return; } output.SetObject(results, obj); }
public override void Generate(Chunk chunk, Biome biome = null) { //getting inputs SpatialHash objs = (SpatialHash)objsIn.GetObject(chunk); /*Matrix substrate = (Matrix)substrateIn.GetObject(chunk); * * //return on stop/disable/null input * if (chunk.stop || objs==null) return; * if (!enabled || substrate==null) { objsOut.SetObject(chunk, objs); return; } * * //preparing output * objs = objs.Copy(); * * for (int c=0; c<objs.cells.Length; c++) * { * List<SpatialObject> objList = objs.cells[c].objs; * int objsCount = objList.Count; * for (int i=0; i<objsCount; i++) * { * SpatialObject obj = objList[i]; * //obj.height = substrate[(int)obj.pos.x, (int)obj.pos.y]; * obj.height = substrate.GetInterpolatedValue(obj.pos); * } * } * * //setting output * if (chunk.stop) return;*/ objsOut.SetObject(chunk, objs); }
static public void DrawObjects() { foreach (Chunk.Results result in mapMagic.Results()) { if (result == null || !result.results.ContainsKey(previewOutput)) { continue; } object objsBox = Preview.previewOutput.GetObject <object>(result); SpatialHash objs = null; if (objsBox is SpatialHash) { objs = (SpatialHash)objsBox; } if (objs == null) { continue; } float pixelSize = GetPixelSize(); float terrainHeight = GetTerrainHeight(); int objsCount = objs.Count; foreach (SpatialObject obj in objs) { float height = 0; if (result.heights != null) { height = result.heights.GetInterpolated(obj.pos.x, obj.pos.y); } Vector3 pos = new Vector3(obj.pos.x * pixelSize, (obj.height + height) * terrainHeight, obj.pos.y * pixelSize); pos += MapMagic.instance.transform.position; UnityEditor.Handles.color = new Color(0.3f, 1, 0.2f, 1); UnityEditor.Handles.DrawLine(pos + new Vector3(obj.size / 2f, 0, 0), pos - new Vector3(obj.size / 2f, 0, 0)); UnityEditor.Handles.DrawLine(pos + new Vector3(0, 0, obj.size / 2f), pos - new Vector3(0, 0, obj.size / 2f)); if (objsCount < 300) { Vector3 oldPoint = pos; foreach (Vector3 point in pos.CircleAround(obj.size / 2f, objsCount < 100? 12 : 4, true)) { UnityEditor.Handles.DrawLine(oldPoint, point); oldPoint = point; } } UnityEditor.Handles.color = new Color(0.3f, 1, 0.2f, 0.3333f); UnityEditor.Handles.DrawLine(new Vector3(pos.x, 0, pos.z), new Vector3(pos.x, terrainHeight, pos.z)); } // in objects } //foreach chunk }
} //no extend, non-generic public void Add(SpatialHash addHash) { if (addHash.cells.Length != cells.Length) { UnityEngine.Debug.LogError("Add SpatialHash: cell number is different"); return; } for (int c = 0; c < cells.Length; c++) { cells[c].objs.AddRange(addHash.cells[c].objs); Count += cells[c].objs.Count; } }
public void ChangeResolution(int newResolution) { SpatialHash newHash = new SpatialHash(offset, size, newResolution); foreach (SpatialObject obj in AllObjs()) { newHash.Add(obj); } resolution = newResolution; cells = newHash.cells; }
public override void Generate(Chunk chunk, Biome biome = null) { SpatialHash spatialHash = chunk.defaultSpatialHash; if (!enabled) { output.SetObject(chunk, spatialHash); return; } if (chunk.stop) { return; } // Note - it's important that we *don't* change the seed based on the chunk coordinates, or else // we risk generating two different points. InstanceRandom rnd = new InstanceRandom(MapMagic.instance.seed + seed /* + chunk.coord.x*1000 + chunk.coord.z */); Vector2 candidate = new Vector2(xMin + rnd.Random() * (xMax - xMin), zMin + rnd.Random() * (zMax - zMin)); // MM works with coordinates specified in "terrain space". If the user specifies coordinates in // absolute world position, need to scale these based on resolution and size of terrain before // adding to the spatialhash if (coordinateSpace == CoordinateSpace.World) { float scaleFactor = (float)MapMagic.instance.resolution / (float)MapMagic.instance.terrainSize; candidate *= scaleFactor; } // If the spatial hash for this chunk does not contain the candidate point, simply return the default // spatial hash if ( spatialHash.offset.x + spatialHash.size <= candidate.x || /* candidate point lies too far to the right */ spatialHash.offset.x > candidate.x || /* candidate point lies too far to the left */ spatialHash.offset.y + spatialHash.size <= candidate.y || /* candidate point lies too far forward */ spatialHash.offset.y > candidate.y /* candidate point lies too far backward */ ) { output.SetObject(chunk, spatialHash); return; } // If the candidate lies within this chunk's bounds, add it to the hash else { spatialHash.Add(candidate, 0, 0, 1); } if (chunk.stop) { return; } output.SetObject(chunk, spatialHash); }
public void Purge () { HeightOutput ho = MapMagic.instance.gens.GetGenerator<HeightOutput>(); if (ho==null || !ho.enabled) HeightOutput.Purge(this); SplatOutput so = MapMagic.instance.gens.GetGenerator<SplatOutput>(); PreviewOutput po = MapMagic.instance.gens.GetGenerator<PreviewOutput>(); if ( (po == null || !po.enabled) && (so==null || !so.enabled) ) SplatOutput.Purge(this); if (po == null || !po.enabled) previewObjs = null; GrassOutput go = MapMagic.instance.gens.GetGenerator<GrassOutput>(); if (go==null || !go.enabled) GrassOutput.Purge(this); ObjectOutput oo = MapMagic.instance.gens.GetGenerator<ObjectOutput>(); if (oo==null || !oo.enabled) ObjectOutput.Purge(this); TreesOutput to = MapMagic.instance.gens.GetGenerator<TreesOutput>(); if (to==null || !to.enabled) TreesOutput.Purge(this); purge = false; }
public SpatialHash Copy() { SpatialHash result = new SpatialHash(offset, size, resolution); for (int i = 0; i < cells.Length; i++) { result.cells[i].min = cells[i].min; result.cells[i].max = cells[i].max; result.cells[i].objs = new List <SpatialObject>(cells[i].objs); List <SpatialObject> objs = result.cells[i].objs; for (int o = objs.Count - 1; o >= 0; o--) { objs[o] = objs[o].Copy(); } } result.Count = Count; return(result); }
public override void Generate(Chunk chunk, Biome biome = null) { SpatialHash spatialHash = chunk.defaultSpatialHash; if (!enabled) { output.SetObject(chunk, spatialHash); return; } if (chunk.stop) { return; } // Note that spacing is specified in terms of the resolution of the terrain. // The *world spacing* will be equal to the spacing specified here / the terrain size * terrain resolution for (float z = zOffset; z < spatialHash.size; z += zSpacing) { for (float x = xOffset; x < spatialHash.size; x += xSpacing) { Vector2 candidate = new Vector2((spatialHash.offset.x + x), (spatialHash.offset.y + z)); spatialHash.Add(candidate, 0, 0, 1); //adding only if some suitable candidate found if (xSpacing == 0) { break; } } if (zSpacing == 0) { break; } } if (chunk.stop) { return; } output.SetObject(chunk, spatialHash); }
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 }
void OnGUI() { //updating layouts if (baseLayout == null) { baseLayout = new Layout(); } baseLayout.maxZoom = 8; baseLayout.minZoom = 0.125f; baseLayout.zoomStep = 0.125f; baseLayout.Zoom(); baseLayout.Scroll(); //scrolling and zooming if (infoLayout == null) { infoLayout = new Layout(); } infoLayout.cursor = new Rect(); infoLayout.margin = 10; infoLayout.rightMargin = 10; infoLayout.field = new Rect(this.position.width - 200 - 10, this.position.height - 100 - 10, 200, 100); //no output exit if (Preview.previewOutput == null) { baseLayout.Label("No preview output is selected"); return; } //drawing main object //TODO: preview all of the textures in window int counter = 0; foreach (Chunk.Results result in Preview.mapMagic.Results()) { //displaing currently selected chunk if (counter != displayedObjectNum) { counter++; continue; } //no object if (result == null) { baseLayout.Label("Please wait until preview \nresult is being generated."); return; } object previewBox = Preview.previewOutput.GetObject <object>(result); if (previewBox == null) { baseLayout.Label("Please wait until preview \nobject is being generated."); return; } //displaying matrix if (Preview.previewOutput.type == Generator.InoutType.Map) { //refreshing matrices if needed if (Preview.RefreshMatricesNeeded()) { Preview.RefreshMatrices(range.x, range.y); } //finding matrix and texture Matrix matrix = (Matrix)previewBox; Texture2D texture = Preview.matrices[matrix]; //drawing texture EditorGUI.DrawPreviewTexture(baseLayout.ToDisplay(new Rect(0, 0, texture.width, texture.height)), texture); //drawing texture info UnityEditor.EditorGUI.HelpBox(infoLayout.field, "", UnityEditor.MessageType.None); UnityEditor.EditorGUI.HelpBox(infoLayout.field, "", UnityEditor.MessageType.None); infoLayout.Par(2); infoLayout.Field(ref displayedObjectNum, "Tile number", fieldSize: 0.3f); infoLayout.fieldSize = 0.7f; //infoLayout.inputSize = 0.3f; infoLayout.Label("Size: " + texture.width + "x" + texture.height); infoLayout.Field(ref baseLayout.zoom, "Zoom: ", min: baseLayout.minZoom, max: baseLayout.maxZoom, slider: true, quadratic: true); infoLayout.Field(ref range, "Range: ", min: 0, max: 1, slider: true); if (infoLayout.lastChange) { Preview.RefreshMatrices(range.x, range.y); } infoLayout.Par(3); if (infoLayout.Button("Save To Texture")) { #if !UNITY_WEBPLAYER //you cannot get access to files for web player platform. Even for an editor. Seems to be Unity bug. string path = UnityEditor.EditorUtility.SaveFilePanel( "Save Output Texture", "Assets", "OutputTexture.png", "png"); if (path != null && path.Length != 0) { byte[] bytes = texture.EncodeToPNG(); System.IO.File.WriteAllBytes(path, bytes); } #endif } } else if (Preview.previewOutput.type == Generator.InoutType.Objects) { SpatialHash spatialHash = (SpatialHash)previewBox; for (int i = 0; i < spatialHash.cells.Length; i++) { SpatialHash.Cell cell = spatialHash.cells[i]; //drawing grid UnityEditor.Handles.color = new Color(0.6f, 0.6f, 0.6f); //TODO: meight be too light in pro skin UnityEditor.Handles.DrawPolyLine( baseLayout.ToDisplay((cell.min - spatialHash.offset) / spatialHash.size * 1000), baseLayout.ToDisplay((new Vector2(cell.max.x, cell.min.y) - spatialHash.offset) / spatialHash.size * 1000), baseLayout.ToDisplay((cell.max - spatialHash.offset) / spatialHash.size * 1000), baseLayout.ToDisplay((new Vector2(cell.min.x, cell.max.y) - spatialHash.offset) / spatialHash.size * 1000), baseLayout.ToDisplay((cell.min - spatialHash.offset) / spatialHash.size * 1000)); //drawing objects UnityEditor.Handles.color = new Color(0.3f, 0.5f, 0.1f); for (int j = 0; j < cell.objs.Count; j++) { Vector2 pos = baseLayout.ToDisplay((cell.objs[j].pos - spatialHash.offset) / spatialHash.size * 1000); float radius = cell.objs[j].size * baseLayout.zoom / 2; if (radius < 3) { radius = 3; } UnityEditor.Handles.DrawAAConvexPolygon( pos + new Vector2(0, 1) * radius, pos + new Vector2(0.71f, 0.71f) * radius, pos + new Vector2(1, 0) * radius, pos + new Vector2(0.71f, -0.71f) * radius, pos + new Vector2(0, -1) * radius, pos + new Vector2(-0.71f, -0.71f) * radius, pos + new Vector2(-1, 0) * radius, pos + new Vector2(-0.71f, 0.71f) * radius); } } //drawing info UnityEditor.EditorGUI.HelpBox(infoLayout.field, "", UnityEditor.MessageType.None); UnityEditor.EditorGUI.HelpBox(infoLayout.field, "", UnityEditor.MessageType.None); infoLayout.Par(); infoLayout.fieldSize = 0.7f; //infoLayout.inputSize = 0.3f; infoLayout.Label("Count: " + spatialHash.Count); } break; //no need to do anything when selected chunk showed } //foreach in results } //OnGUI
void OnGUI() { //finding the preiew object if (mapMagic == null) { mapMagic = FindObjectOfType <MapMagic>(); } if (mapMagic == null) { EditorGUI.LabelField(new Rect(10, 10, 200, 200), "No MapMagic object found, re-open the window."); return; } Vector3 camPos = new Vector3(); if (UnityEditor.SceneView.lastActiveSceneView != null) { camPos = UnityEditor.SceneView.lastActiveSceneView.camera.transform.position; } Chunk.Results closestResults = mapMagic.ClosestResults(camPos); if (closestResults == null) { EditorGUI.LabelField(new Rect(10, 10, 200, 200), "No terrains are pinned for preview"); return; } if (Preview.previewOutput == null) { EditorGUI.LabelField(new Rect(10, 10, 200, 200), "No preview output is selected"); return; } object currentObj = Preview.previewOutput.GetObject <object>(closestResults); if (currentObj == null) { EditorGUI.LabelField(new Rect(10, 10, 200, 200), "Please wait until preview \nobject is being generated."); return; } if (currentObj != lastUsedObject) { Repaint(); } //updating layouts if (baseLayout == null) { baseLayout = new Layout(); } baseLayout.maxZoom = 8; baseLayout.minZoom = 0.125f; baseLayout.zoomStep = 0.125f; baseLayout.Zoom(); baseLayout.Scroll(); //scrolling and zooming if (infoLayout == null) { infoLayout = new Layout(); } infoLayout.cursor = new Rect(); infoLayout.margin = 10; infoLayout.rightMargin = 10; infoLayout.field = new Rect(this.position.width - 200 - 10, this.position.height - 80 - 10, 200, 80); //drawing hash preview if (currentObj is SpatialHash) { SpatialHash spatialHash = (SpatialHash)currentObj; for (int i = 0; i < spatialHash.cells.Length; i++) { SpatialHash.Cell cell = spatialHash.cells[i]; //drawing grid UnityEditor.Handles.color = Color.gray; UnityEditor.Handles.DrawPolyLine( baseLayout.ToDisplay((cell.min - spatialHash.offset) / spatialHash.size * 1000), baseLayout.ToDisplay((new Vector2(cell.max.x, cell.min.y) - spatialHash.offset) / spatialHash.size * 1000), baseLayout.ToDisplay((cell.max - spatialHash.offset) / spatialHash.size * 1000), baseLayout.ToDisplay((new Vector2(cell.min.x, cell.max.y) - spatialHash.offset) / spatialHash.size * 1000), baseLayout.ToDisplay((cell.min - spatialHash.offset) / spatialHash.size * 1000)); //drawing objects UnityEditor.Handles.color = new Color(0.4f, 0.9f, 0.2f); for (int j = 0; j < cell.objs.Count; j++) { DrawCircle(baseLayout.ToDisplay((cell.objs[j].pos - spatialHash.offset) / spatialHash.size * 1000), 5); } } //drawing info UnityEditor.EditorGUI.HelpBox(infoLayout.field, "", UnityEditor.MessageType.None); UnityEditor.EditorGUI.HelpBox(infoLayout.field, "", UnityEditor.MessageType.None); infoLayout.Par(); infoLayout.fieldSize = 0.7f; //infoLayout.inputSize = 0.3f; infoLayout.Label("Count: " + spatialHash.Count); } //drawing matrix preview else if (currentObj is Matrix) { Matrix matrix = (Matrix)currentObj; //refreshing texture if matrix has changed if (matrix != lastUsedObject || (range - lastUsedRange).sqrMagnitude > 0.01f) { lastUsedObject = matrix; lastUsedRange = range; texture = new Texture2D(matrix.rect.size.x, matrix.rect.size.z); texture.filterMode = FilterMode.Point; matrix.SimpleToTexture(texture, rangeMin: range.x, rangeMax: range.y); } //drawing texture UnityEditor.EditorGUI.DrawPreviewTexture(baseLayout.ToDisplay(new Rect(0, 0, texture.width, texture.height)), texture); //drawing texture info UnityEditor.EditorGUI.HelpBox(infoLayout.field, "", UnityEditor.MessageType.None); UnityEditor.EditorGUI.HelpBox(infoLayout.field, "", UnityEditor.MessageType.None); infoLayout.fieldSize = 0.7f; //infoLayout.inputSize = 0.3f; infoLayout.Label("Size: " + texture.width + "x" + texture.height); infoLayout.Field(ref baseLayout.zoom, "Zoom: ", min: baseLayout.minZoom, max: baseLayout.maxZoom, slider: true, quadratic: true); if (matrix != null) { infoLayout.Field(ref range, "Range: ", min: 0, max: 1, slider: true); infoLayout.Par(3); if (infoLayout.Button("Save To Texture")) { #if !UNITY_WEBPLAYER string path = UnityEditor.EditorUtility.SaveFilePanel( "Save Output Texture", "Assets", "OutputTexture.png", "png"); if (path != null && path.Length != 0) { byte[] bytes = texture.EncodeToPNG(); System.IO.File.WriteAllBytes(path, bytes); } #endif } } } }
public override void Generate(Chunk chunk, Biome biome = null) { //getting inputs SpatialHash minuend = (SpatialHash)minuendIn.GetObject(chunk); SpatialHash subtrahend = (SpatialHash)subtrahendIn.GetObject(chunk); //return on stop/disable/null input if (chunk.stop || minuend == null) { return; } if (!enabled || subtrahend == null || subtrahend.Count == 0) { minuendOut.SetObject(chunk, minuend); return; } //preparing output SpatialHash result = new SpatialHash(minuend.offset, minuend.size, minuend.resolution); //transforming distance to map-space float dist = distance / MapMagic.instance.terrainSize * MapMagic.instance.resolution; //finding maximum seek distance float maxObjSize = 0; foreach (SpatialObject obj in subtrahend.AllObjs()) { if (obj.size > maxObjSize) { maxObjSize = obj.size; } } maxObjSize = maxObjSize / MapMagic.instance.terrainSize * MapMagic.instance.resolution; //transforming to map-space float maxDist = dist * (1 - sizeFactor) + dist * maxObjSize * sizeFactor; foreach (SpatialObject obj in minuend.AllObjs()) { bool inRange = false; foreach (SpatialObject closeObj in subtrahend.ObjsInRange(obj.pos, maxDist)) { float minDist = (obj.pos - closeObj.pos).magnitude; if (minDist < dist * (1 - sizeFactor) + dist * closeObj.size * sizeFactor) { inRange = true; break; } } if (!inRange) { result.Add(obj); } //SpatialObject closestObj = subtrahend.Closest(obj.pos,false); //float minDist = (obj.pos - closestObj.pos).magnitude; //if (minDist > dist*(1-sizeFactor) + dist*closestObj.size*sizeFactor) result.Add(obj); } //setting output if (chunk.stop) { return; } minuendOut.SetObject(chunk, result); }
public static void Process(CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func <float, bool> stop = null) { #if VEGETATION_STUDIO if (stop != null && stop(0)) { return; } //preparing and clearing storage if (vetStorComponents == null || vetStorComponents.Count == 0) { return; //vs not used (process runs anyway) } PersistentVegetationStorage storage = vetStorComponents[rect]; int cellXCount = Mathf.CeilToInt(terrainSize.dimensions / cellSize); int cellZCount = Mathf.CeilToInt(terrainSize.dimensions / cellSize); Noise noise = new Noise(12345, permutationCount: 128); //to pick objects based on biome //clearing all of the items foreach (VegetationStudioOutput gen in gens.GeneratorsOfType <VegetationStudioOutput>(onlyEnabled:true, checkBiomes:true)) { for (int b = 0; b < gen.layers.Length; b++) { string id = gen.package.VegetationInfoList[b].VegetationItemID; storage.RemoveVegetationItemInstances(id, VS_MM_id); } break; //iterating in one generator only - they use the same layers } if (stop != null && stop(0)) { return; } //object outputs foreach (VegetationStudioOutput gen in gens.GeneratorsOfType <VegetationStudioOutput>(onlyEnabled:true, checkBiomes:true)) { //gen biome mask 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 in layers for (int b = 0; b < gen.layers.Length; b++) { if (stop != null && stop(0)) { return; //checking stop before reading output } Layer layer = gen.layers[b]; string id = gen.package.VegetationInfoList[b].VegetationItemID; //objects layer if (layer.type == Layer.Type.Object) { //loading objects from input SpatialHash hash = (SpatialHash)gen.layers[b].objInput.GetObject(results); if (hash == null) { continue; } //filling instances (no need to check/add key in multidict) foreach (SpatialObject obj in hash.AllObjs()) { //skipping on biome not used float biomeFactor = 0; if (gen.biome == null) { biomeFactor = 1; } else if (biomeMask != null) { biomeFactor = biomeMask.GetInterpolated(obj.pos.x, obj.pos.y); } if (biomeFactor < 0.00001f) { continue; } float rnd; switch (biomeBlendType) { case ObjectOutput.BiomeBlendType.Sharp: rnd = 0.5f; break; case ObjectOutput.BiomeBlendType.AdditiveRandom: case ObjectOutput.BiomeBlendType.NormalizedRandom: rnd = noise.Random((int)obj.pos.x, (int)obj.pos.y); if (biomeFactor > 0.5f) { rnd = 1 - rnd; //test } break; case ObjectOutput.BiomeBlendType.Scale: rnd = 0.0f; break; default: rnd = 0.5f; break; } if (biomeFactor < rnd) { continue; } //flooring float terrainHeight = 0; if (layer.relativeHeight && results.heights != null) //if checbox enabled and heights exist (at least one height generator is in the graph) { terrainHeight = results.heights.GetInterpolated(obj.pos.x, obj.pos.y); } if (terrainHeight > 1) { terrainHeight = 1; } //terrain-space object position Vector3 position = new Vector3( (obj.pos.x - hash.offset.x) / hash.size * terrainSize.dimensions, (obj.height + terrainHeight) * terrainSize.height, (obj.pos.y - hash.offset.y) / hash.size * terrainSize.dimensions); //cell number int cx = (int)(position.x / cellSize); int cz = (int)(position.z / cellSize); PersistentVegetationCell cell = storage.PersistentVegetationStoragePackage.PersistentVegetationCellList[cz + cx * cellXCount]; //rotation + taking terrain normal Quaternion rotation; float objRotation = layer.rotate ? obj.rotation % 360 : 0; if (layer.takeTerrainNormal) { Vector3 terrainNormal = ObjectOutput.GetTerrainNormal(obj.pos.x, obj.pos.y, results.heights, terrainSize.height, terrainSize.pixelSize); Vector3 sideVector = new Vector3(Mathf.Sin((obj.rotation + 90) * Mathf.Deg2Rad), 0, Mathf.Cos((obj.rotation + 90) * Mathf.Deg2Rad)); Vector3 frontVector = Vector3.Cross(sideVector, terrainNormal); rotation = Quaternion.LookRotation(frontVector, terrainNormal); } else { rotation = objRotation.EulerToQuat(); } //scale + biome scale mode Vector3 scale = layer.scale ? new Vector3(layer.scaleY ? 1 : obj.size, obj.size, layer.scaleY ? 1 : obj.size) : Vector3.one; if (biomeBlendType == ObjectOutput.BiomeBlendType.Scale && gen.biome != null) { float biomeVal = 1; if (biomeMask != null) { biomeVal = biomeMask[obj.pos]; } if (biomeVal < 0.001f) { continue; //skip zero-scaled objects } scale *= biomeVal; } //storage.AddVegetationItemInstance(id, position, scale, rotation, layer.applyMeshRotation, VS_MM_id, true); cell.AddVegetationItemInstance(id, position, scale, rotation, VS_MM_id); } if (stop != null && stop(0)) { return; } } //map outputs if (layer.type == Layer.Type.Map) { //reading output directly //Output output = gen.layers[b].output; //if (stop!=null && stop(0)) return; //checking stop before reading output //if (!results.results.ContainsKey(output)) continue; //Matrix matrix = (Matrix)results.results[output]; //loading from input if (stop != null && stop(0)) { return; } Matrix matrix = (Matrix)gen.layers[b].mapInput.GetObject(results); if (matrix == null) { continue; } Matrix heights = results.heights; //get heights before the chunk is removed //setting bush by bush using the sample dist float sampleDist = 1f / layer.density; //filling float terrainPosX = 1f * rect.offset.x / terrainSize.resolution * terrainSize.dimensions; float terrainPosZ = 1f * rect.offset.z / terrainSize.resolution * terrainSize.dimensions; for (int cx = 0; cx <= cellXCount - 1; cx++) { for (int cz = 0; cz <= cellZCount - 1; cz++) { Vector3 cellCorner = new Vector3(terrainPosX + (cellSize * cx), 0, terrainPosZ + (cellSize * cz)); PersistentVegetationCell cell = storage.PersistentVegetationStoragePackage.PersistentVegetationCellList[cz + cx * cellXCount]; for (float x = 0; x < cellSize; x += sampleDist) { for (float z = 0; z < cellSize; z += sampleDist) { //world position float wx = cellSize * cx + x; float wz = cellSize * cz + z; //randomizing position wx += noise.Random((int)(wx * 10), (int)(wz * 10), 2) * sampleDist - sampleDist / 2; wz += noise.Random((int)(wx * 10), (int)(wz * 10), 3) * sampleDist - sampleDist / 2; //map position float mx = wx / terrainSize.dimensions * rect.size.x + rect.offset.x; // relative (0-1) position * terrain res float mz = wz / terrainSize.dimensions * rect.size.z + rect.offset.z; float val = matrix.GetInterpolated(mx, mz); float biomeFactor = 0; if (gen.biome == null) { biomeFactor = 1; } else if (biomeMask != null) { biomeFactor = biomeMask.GetInterpolated(mx, mz); } //placing object float rnd = (noise.Random((int)(wx * 10), (int)(wz * 10))); if (rnd < val * biomeFactor) { float terrainHeight = heights.GetInterpolated(mx, mz) * terrainSize.height; //rotation + taking terrain normal Quaternion rotation; float rotRnd = noise.Random((int)(wx * 10), (int)(wz * 10), 1); float objRotation = layer.rotate ? rotRnd * 360 : 0; if (layer.takeTerrainNormal) { Vector3 terrainNormal = ObjectOutput.GetTerrainNormal(mx, mz, heights, terrainSize.height, terrainSize.pixelSize); Vector3 sideVector = new Vector3(Mathf.Sin((objRotation + 90) * Mathf.Deg2Rad), 0, Mathf.Cos((objRotation + 90) * Mathf.Deg2Rad)); Vector3 frontVector = Vector3.Cross(sideVector, terrainNormal); rotation = Quaternion.LookRotation(frontVector, terrainNormal); } else { rotation = objRotation.EulerToQuat(); } //scale float rndScale = noise.Random((int)(wx * 10), (int)(wz * 10), 1); rndScale = layer.scaleMinMax.x + (layer.scaleMinMax.y - layer.scaleMinMax.x) * rndScale; Vector3 scale = new Vector3(rndScale, rndScale, rndScale); //storage.AddVegetationItemInstance(id, new Vector3(wx,terrainHeight,wz), scale, rotation, layer.applyMeshRotation, VS_MM_id, true); cell.AddVegetationItemInstance(id, new Vector3(wx, terrainHeight, wz), scale, rotation, VS_MM_id); } } } if (stop != null && stop(0)) { return; } } } } } } //refreshing billboards //calling it from thread ruins all the billboards //BillboardSystem billboardSys = billboardComponents[rect]; //if (billboardSys != null) // billboardSys.RefreshBillboards(); #endif //pushing anything to apply if (stop != null && stop(0)) { return; } results.apply.CheckAdd(typeof(VegetationStudioOutput), null, replace: true); }
public void Preview () { #if UNITY_EDITOR if (Event.current == null || Event.current.type != EventType.Repaint) return; //clearing preview if prevew generator is off (or non-map) if (MapMagic.instance.previewOutput==null || MapMagic.instance.previewOutput.type!=Generator.InoutType.Map) { if (terrain.materialTemplate != null && terrain.materialTemplate.shader.name == "MapMagic/TerrainPreviewFirstPass") { terrain.materialType = MapMagic.ToUnityTerrMatType(MapMagic.instance.terrainMaterialType); terrain.materialTemplate = previewBackupMaterial; previewBackupMaterial = null; lastPreviewedMatrix = null; UnityEditor.SceneView.RepaintAll(); } } if (MapMagic.instance.previewOutput!=null && MapMagic.instance.previewOutput.type == Generator.InoutType.Map) { //loading preview material from terrain (or creating new) Material previewMat = null; if (terrain.materialTemplate!=null && terrain.materialTemplate.shader.name=="MapMagic/TerrainPreviewFirstPass") previewMat = terrain.materialTemplate; if (previewMat == null) { Shader previewShader = Shader.Find("MapMagic/TerrainPreviewFirstPass"); previewMat = new Material(previewShader); previewBackupMaterial = terrain.materialTemplate; terrain.materialTemplate = previewMat; terrain.materialType = Terrain.MaterialType.Custom; UnityEditor.SceneView.RepaintAll(); } //loading matrix Matrix matrix = MapMagic.instance.previewOutput.GetObject<Matrix>(this); //refreshing preview texture if (matrix != lastPreviewedMatrix) { Texture2D tex = null; //populate if (matrix != null) { tex = new Texture2D(matrix.rect.size.x, matrix.rect.size.z); Color[] line = new Color[matrix.rect.size.z]; for (int x=0; x<matrix.rect.size.x; x++) { for (int z=0; z<matrix.rect.size.z; z++) { float val = matrix[x+matrix.rect.offset.x, z+matrix.rect.offset.z]; line[z] = new Color(val, val, val); } tex.SetPixels(x,0,1,line.Length,line); } } else //in case the output is not generated { tex = Extensions.ColorTexture(2,2,Color.gray); } //apply tex.Apply(); previewMat.SetTexture("_Preview", tex); if (MapMagic.instance.guiDebug) Debug.Log("Preview Applied"); lastPreviewedMatrix = matrix; UnityEditor.SceneView.RepaintAll(); } } //spatial hash if (MapMagic.instance.previewOutput!=null && MapMagic.instance.previewOutput.type == Generator.InoutType.Objects) { float pixelSize = 1f * MapMagic.instance.terrainSize / MapMagic.instance.resolution; SpatialHash objs = MapMagic.instance.previewOutput.GetObject<SpatialHash>(this); if (objs != null) { int objsCount = objs.Count; foreach (SpatialObject obj in objs) { float terrainHeight = 0; if (heights != null) terrainHeight = heights.GetInterpolated(obj.pos.x, obj.pos.y); Vector3 pos = new Vector3(obj.pos.x*pixelSize, (obj.height+terrainHeight)*MapMagic.instance.terrainHeight, obj.pos.y*pixelSize); pos += MapMagic.instance.transform.position; UnityEditor.Handles.color = new Color(1,1,1,1); UnityEditor.Handles.DrawLine(pos+new Vector3(obj.size/2f,0,0), pos-new Vector3(obj.size/2f,0,0)); UnityEditor.Handles.DrawLine(pos+new Vector3(0,0,obj.size/2f), pos-new Vector3(0,0,obj.size/2f)); if (objsCount < 100) { Vector3 oldPoint = pos; foreach (Vector3 point in pos.CircleAround(obj.size/2f, 12, true)) { UnityEditor.Handles.DrawLine(oldPoint,point); oldPoint = point; } } UnityEditor.Handles.color = new Color(1,1,1,0.15f); UnityEditor.Handles.DrawLine(new Vector3(pos.x, 0, pos.z), new Vector3(pos.x, MapMagic.instance.terrainHeight, pos.z)); } } } #endif }
public float uniformity = 0.1f; //aka candidatesNum/100 public override void Generate(Chunk chunk, Biome biome = null) { Matrix probMatrix = (Matrix)probability.GetObject(chunk); SpatialHash spatialHash = chunk.defaultSpatialHash; if (!enabled) { output.SetObject(chunk, spatialHash); return; } if (chunk.stop) { return; } // If the bounds of this chunk don't contain the specified zValue then return the // default spatialHash if (spatialHash.offset.y > zValue || spatialHash.offset.y + spatialHash.size <= zValue) { output.SetObject(chunk, spatialHash); return; } InstanceRandom rnd = new InstanceRandom(MapMagic.instance.seed + seed + chunk.coord.x * 1000 + chunk.coord.z); int candidatesNum = (int)(uniformity * 100); for (int i = 0; i < count; i++) { Vector2 bestCandidate = Vector3.zero; float bestDist = 0; for (int c = 0; c < candidatesNum; c++) { Vector2 candidate = new Vector2((spatialHash.offset.x + 1) + (rnd.Random() * (spatialHash.size - 2.01f)), zValue); //checking if candidate available here according to probability map if (probMatrix != null && probMatrix[candidate] < rnd.Random()) { continue; } //checking if candidate is the furthest one float dist = spatialHash.MinDist(candidate); if (dist > bestDist) { bestDist = dist; bestCandidate = candidate; } } if (bestDist > 0.001f) { spatialHash.Add(bestCandidate, 0, 0, 1); //adding only if some suitable candidate found } } if (chunk.stop) { return; } output.SetObject(chunk, spatialHash); }
public override void Generate(MapMagic.Chunk chunk) { //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 float uniformity = 0.1f; //aka candidatesNum/100 public override void Generate(Chunk chunk, Biome biome = null) { Matrix probMatrix = (Matrix)probability.GetObject(chunk); SpatialHash spatialHash = chunk.defaultSpatialHash; if (!enabled) { output.SetObject(chunk, spatialHash); return; } if (chunk.stop) { return; } InstanceRandom rnd = new InstanceRandom(MapMagic.instance.seed + seed + chunk.coord.x * 1000 + chunk.coord.z); //Rect terrainRect = terrain.coord.ToRect(terrain.size); //terrainRect.position += Vector2.one; terrainRect.size-=Vector2.one*2; //SpatialHash spatialHash = new SpatialHash(terrain.coord.ToVector2(terrain.size), terrain.size, 16); //float square = terrainRect.width * terrainRect.height; //float count = square*(density/1000000); //number of items per terrain //positioned scatter /*float sideCount = Mathf.Sqrt(count); * float step = spatialHash.size / sideCount; * * //int uniformity = 100; * //Random.seed = 12345; * for (float x=spatialHash.offset.x+step/2; x<spatialHash.offset.x+spatialHash.size-step/2; x+=step) * for (float y=spatialHash.offset.y+step/2; y<spatialHash.offset.y+spatialHash.size-step/2; y+=step) * { * Vector2 offset = new Vector2(((Random.value*2-1)*uniformity), ((Random.value*2-1)*uniformity)); * Vector2 point = new Vector2(x,y) + offset; * if (point.x > spatialHash.size) point.x -= spatialHash.size; if (point.x < 0) point.x += spatialHash.size; * if (point.y > spatialHash.size) point.y -= spatialHash.size; if (point.y < 0) point.y += spatialHash.size; * spatialHash.Add(point, 0,0,0); * }*/ //realRandom algorithm int candidatesNum = (int)(uniformity * 100); for (int i = 0; i < count; i++) { Vector2 bestCandidate = Vector3.zero; float bestDist = 0; for (int c = 0; c < candidatesNum; c++) { Vector2 candidate = new Vector2((spatialHash.offset.x + 1) + (rnd.Random() * (spatialHash.size - 2.01f)), (spatialHash.offset.y + 1) + (rnd.Random() * (spatialHash.size - 2.01f))); //checking if candidate available here according to probability map if (probMatrix != null && probMatrix[candidate] < rnd.Random() + 0.0001f) { continue; } //checking if candidate is the furthest one float dist = spatialHash.MinDist(candidate); if (dist > bestDist) { bestDist = dist; bestCandidate = candidate; } } if (bestDist > 0.001f) { spatialHash.Add(bestCandidate, 0, 0, 1); //adding only if some suitable candidate found } } if (chunk.stop) { return; } output.SetObject(chunk, spatialHash); }