public override void OnGUI(GeneratorsAsset gens) { Transform mm = MapMagic.MapMagic.instance.gameObject.transform; stamper = mm.GetComponentInChildren <MapMagicStamper>(); base.OnGUI(gens); if ((null == stamper || null != stamper && stamper.Generator != this) && layout.Button("Show Stamper")) { if (null == stamper || stamper.Generator != this) { if (null != stamper) { GameObject.DestroyImmediate(stamper.gameObject); } GameObject go = new GameObject("Stamper"); go.transform.parent = mm; stamper = go.AddComponent <MapMagicStamper>(); stamper.Generator = this; Selection.activeObject = stamper; } } else if (null != stamper && stamper.Generator == this && layout.Button("Hide Stamper")) { GameObject.DestroyImmediate(stamper.gameObject); } }
public override void OnGUI(GeneratorsAsset gens) { layout.Par(20); maskIn.DrawIcon(layout, "Mask"); layout.fieldSize = .6f; layout.Field(ref LayerName, "Layer"); layout.fieldSize = .5f; layout.Field(ref patchResolution, "Patch Res", min: 4, max: 64, fieldSize: 0.35f); patchResolution = Mathf.ClosestPowerOfTwo(patchResolution); layout.Field(ref obscureLayers, "Obscure Layers", fieldSize: 0.35f); //layer buttons layout.Par(3); layout.Par(); layout.Label("Layers:", layout.Inset(0.4f)); layout.DrawArrayAdd(ref baseLayers, ref selected, rect: layout.Inset(0.15f), reverse: true, createElement: () => new Layer()); layout.DrawArrayRemove(ref baseLayers, ref selected, rect: layout.Inset(0.15f), reverse: true, onBeforeRemove: UnlinkLayer); layout.DrawArrayDown(ref baseLayers, ref selected, rect: layout.Inset(0.15f), dispUp: true); layout.DrawArrayUp(ref baseLayers, ref selected, rect: layout.Inset(0.15f), dispDown: true); //layers layout.Par(3); for (int num = baseLayers.Length - 1; num >= 0; num--) { layout.DrawLayer(baseLayers[num].OnGUI, ref selected, num); } layout.fieldSize = 0.4f; layout.margin = 10; layout.rightMargin = 10; layout.Par(5); }
public override void OnGUI(GeneratorsAsset gens) { layout.Par(20); input.DrawIcon(layout); output.DrawIcon(layout); layout.Field(ref kernelType, "Kernel Size"); }
public override void OnGUI(GeneratorsAsset gens) { layout.Par(20); input.DrawIcon(layout); output.DrawIcon(layout); layout.Field(ref heightMin, "Height Min"); layout.Field(ref heightMax, "Height Max"); }
public override void OnGUI(GeneratorsAsset gens) { layout.fieldSize = .6f; layout.Field(ref LayerName, "Layer"); layout.fieldSize = .5f; layout.Par(20); input.DrawIcon(layout, "Stencil"); layout.Par(5); if (output == null) { output = new Output(InoutType.Map); } }
public override void OnGUI(GeneratorsAsset gens) { layout.fieldSize = .6f; layout.Field(ref LayerName, "Layer"); layout.fieldSize = .5f; layout.Par(20); input.DrawIcon(layout, "Height"); layout.Par(5); if (output == null) { output = new Output(InoutType.Map); } layout.Field(ref scale, "Scale", min: 1, max: 4f); scale = Mathf.NextPowerOfTwo(scale); }
public override void OnGUI(GeneratorsAsset gens) { layout.fieldSize = .6f; layout.Field(ref LayerName, "Layer"); layout.fieldSize = .5f; //Layer buttons layout.Par(); layout.Label("Layers:", layout.Inset(0.4f)); layout.DrawArrayAdd(ref baseLayers, ref selected, rect: layout.Inset(0.15f), reverse: true, createElement: () => new Layer(), onAdded: UnlinkBaseLayer); layout.DrawArrayRemove(ref baseLayers, ref selected, rect: layout.Inset(0.15f), reverse: true, onBeforeRemove: UnlinkLayer, onRemoved: UnlinkBaseLayer); layout.DrawArrayDown(ref baseLayers, ref selected, rect: layout.Inset(0.15f), dispUp: true, onSwitch: UnlinkBaseLayer); layout.DrawArrayUp(ref baseLayers, ref selected, rect: layout.Inset(0.15f), dispDown: true, onSwitch: UnlinkBaseLayer); //layers layout.Par(3); for (int num = baseLayers.Length - 1; num >= 0; num--) { layout.DrawLayer(baseLayers[num].OnGUI, ref selected, num); } }
public override void OnGUI(GeneratorsAsset gens) { #if VEGETATION_STUDIO_PRO //VegetationPackagePro package = (VegetationPackagePro)serializedPackage; layout.Field(ref package, "Package", fieldSize: 0.6f); //serializedPackage = package; //filling object names array for popup if (package != null) { objectNames = new string[package.VegetationInfoList.Count]; for (int i = 0; i < objectNames.Length; i++) { objectNames[i] = package.VegetationInfoList[i].Name; } } else { objectNames = null; } //layer buttons layout.Par(); layout.Label("Layers:", layout.Inset(0.4f)); layout.DrawArrayAdd(ref baseLayers, ref selected, rect: layout.Inset(0.15f), createElement: () => new Layer()); layout.DrawArrayRemove(ref baseLayers, ref selected, rect: layout.Inset(0.15f), onBeforeRemove: UnlinkLayer); layout.DrawArrayUp(ref baseLayers, ref selected, rect: layout.Inset(0.15f)); layout.DrawArrayDown(ref baseLayers, ref selected, rect: layout.Inset(0.15f)); //layers layout.Par(3); for (int num = 0; num < baseLayers.Length; num++) { layout.DrawLayer(baseLayers[num].OnGUI, ref selected, num, this); } #endif }
public override void OnGUI(GeneratorsAsset gens) { #if VEGETATION_STUDIO_PRO layout.Field(ref package, "Package", fieldSize: 0.6f); #endif layout.Field(ref obscureLayers, "Obscure Layers", fieldSize: 0.35f); //layer buttons layout.Par(); layout.Label("Layers:", layout.Inset(0.4f)); layout.DrawArrayAdd(ref baseLayers, ref selected, rect: layout.Inset(0.15f), createElement: () => new Layer()); layout.DrawArrayRemove(ref baseLayers, ref selected, rect: layout.Inset(0.15f), onBeforeRemove: UnlinkLayer); layout.DrawArrayUp(ref baseLayers, ref selected, rect: layout.Inset(0.15f)); layout.DrawArrayDown(ref baseLayers, ref selected, rect: layout.Inset(0.15f)); //layers layout.Par(3); for (int num = 0; num < baseLayers.Length; num++) { layout.DrawLayer(baseLayers[num].OnGUI, ref selected, num, this); } }
public override void OnGUI(GeneratorsAsset gens) { layout.fieldSize = .6f; layout.Field(ref LayerName, "Layer"); layout.fieldSize = .5f; layout.Field(ref ApplyStamps, "Apply Stamps"); //layer buttons layout.Par(); layout.Label("Layers:", layout.Inset(0.4f)); layout.DrawArrayAdd(ref baseLayers, ref selected, rect: layout.Inset(0.15f), createElement: () => new Layer()); layout.DrawArrayRemove(ref baseLayers, ref selected, rect: layout.Inset(0.15f), onBeforeRemove: UnlinkLayer); layout.DrawArrayUp(ref baseLayers, ref selected, rect: layout.Inset(0.15f)); layout.DrawArrayDown(ref baseLayers, ref selected, rect: layout.Inset(0.15f)); //layers layout.Par(3); for (int num = 0; num < baseLayers.Length; num++) { layout.DrawLayer(baseLayers[num].OnGUI, ref selected, num); } }
public static void Process(MapMagic.CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func <float, bool> stop = null) { if (stop != null && stop(0)) { return; } //values to calculate density float pixelSize = terrainSize.pixelSize; float pixelSquare = pixelSize * pixelSize; //a random needed to convert float to int InstanceRandom rnd = new InstanceRandom(terrainSize.Seed(rect)); //calculating the totoal number of prototypes int prototypesNum = 0; foreach (MadMapsGrassOutput grassOut in gens.GeneratorsOfType <MadMapsGrassOutput>()) { prototypesNum += grassOut.baseLayers.Length; } //preparing results List <int[, ]> detailsList = new List <int[, ]>(); List <DetailPrototypeWrapper> prototypesList = new List <DetailPrototypeWrapper>(); //filling result foreach (MadMapsGrassOutput gen in gens.GeneratorsOfType <MadMapsGrassOutput>(onlyEnabled: true, checkBiomes: true)) { //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 } } for (int i = 0; i < gen.baseLayers.Length; i++) { if (stop != null && stop(0)) { return; } //loading objects from input //Matrix matrix = (Matrix)gen.baseLayers[i].input.GetObject(chunk); //if (matrix == null) continue; //reading output directly Output output = gen.baseLayers[i].output; if (stop != null && stop(0)) { return; //checking stop before reading output } if (!results.results.ContainsKey(output)) { continue; } Matrix matrix = (Matrix)results.results[output]; //filling array int[,] detail = new int[matrix.rect.size.x, 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]; float biomeVal = 1; if (gen.biome != null) { if (biomeMask == null) { biomeVal = 0; } else { biomeVal = biomeMask[x + matrix.rect.offset.x, z + matrix.rect.offset.z]; } } detail[z, x] = rnd.RandomToInt(val * gen.baseLayers[i].density * pixelSquare * biomeVal); } } //adding to arrays detailsList.Add(detail); prototypesList.Add(gen.baseLayers[i].Wrapper); } } //pushing to apply if (stop != null && stop(0)) { return; } TupleSet <int[][, ], DetailPrototypeWrapper[]> grassTuple = new TupleSet <int[][, ], DetailPrototypeWrapper[]>(detailsList.ToArray(), prototypesList.ToArray()); results.apply.CheckAdd(typeof(MadMapsGrassOutput), grassTuple, replace: true); }
public static void Process(MapMagic.CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func <float, bool> stop = null) { if (stop != null && stop(0)) { return; } Noise noise = new Noise(12345, permutationCount: 128); //to pick objects based on biome //preparing output Dictionary <Transform, List <ObjectPool.Transition> > transitions = new Dictionary <Transform, List <ObjectPool.Transition> >(); //find all of the biome masks - they will be used to determine object probability List <TupleSet <MadMapsObjectOutput, Matrix> > allGensMasks = new List <TupleSet <MadMapsObjectOutput, Matrix> >(); foreach (MadMapsObjectOutput gen in gens.GeneratorsOfType <MadMapsObjectOutput>(onlyEnabled: true, checkBiomes: true)) { 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 } } allGensMasks.Add(new TupleSet <MadMapsObjectOutput, Matrix>(gen, biomeMask)); } int allGensMasksCount = allGensMasks.Count; //biome rect to find array pos faster MapMagic.CoordRect biomeRect = new MapMagic.CoordRect(); for (int g = 0; g < allGensMasksCount; g++) { if (allGensMasks[g].item2 != null) { biomeRect = allGensMasks[g].item2.rect; break; } } //prepare biome mask values stack to re-use it to find per-coord biome float[] biomeVals = new float[allGensMasksCount]; //+1 for not using any object at all //iterating all gens for (int g = 0; g < allGensMasksCount; g++) { MadMapsObjectOutput gen = allGensMasks[g].item1; //iterating in layers for (int b = 0; b < gen.baseLayers.Length; b++) { if (stop != null && stop(0)) { return; //checking stop before reading output } Layer layer = gen.baseLayers[b]; if (!layer.prefab) { continue; } //loading objects from input SpatialHash hash = (SpatialHash)gen.baseLayers[b].input.GetObject(results); if (hash == null) { continue; } //finding/creating proper transitions list List <ObjectPool.Transition> transitionsList; if (!transitions.ContainsKey(layer.prefab)) { transitionsList = new List <ObjectPool.Transition>(); transitions.Add(layer.prefab, transitionsList); } else { transitionsList = transitions[layer.prefab]; } //filling instances (no need to check/add key in multidict) foreach (SpatialObject obj in hash.AllObjs()) { //blend biomes - calling continue if improper biome if (biomeBlendType == BiomeBlendType.Sharp) { float biomeVal = 1; if (allGensMasks[g].item2 != null) { biomeVal = allGensMasks[g].item2[obj.pos]; } if (biomeVal < 0.5f) { continue; } } else if (biomeBlendType == BiomeBlendType.AdditiveRandom) { float biomeVal = 1; if (allGensMasks[g].item2 != null) { biomeVal = allGensMasks[g].item2[obj.pos]; } float rnd = noise.Random((int)obj.pos.x, (int)obj.pos.y); if (biomeVal > 0.5f) { rnd = 1 - rnd; } if (biomeVal < rnd) { continue; } } else if (biomeBlendType == BiomeBlendType.NormalizedRandom) { //filling biome masks values int pos = biomeRect.GetPos(obj.pos); for (int i = 0; i < allGensMasksCount; i++) { if (allGensMasks[i].item2 != null) { biomeVals[i] = allGensMasks[i].item2.array[pos]; } else { biomeVals[i] = 1; } } //calculate normalized sum float sum = 0; for (int i = 0; i < biomeVals.Length; i++) { sum += biomeVals[i]; } if (sum > 1) //note that if sum is <1 usedBiomeNum can exceed total number of biomes - it means that none object is used here { for (int i = 0; i < biomeVals.Length; i++) { biomeVals[i] = biomeVals[i] / sum; } } //finding used biome num float rnd = noise.Random((int)obj.pos.x, (int)obj.pos.y); int usedBiomeNum = biomeVals.Length; //none biome by default sum = 0; for (int i = 0; i < biomeVals.Length; i++) { sum += biomeVals[i]; if (sum > rnd) { usedBiomeNum = i; break; } } //disable object using biome mask if (usedBiomeNum != g) { continue; } } //scale mode is applied a bit later //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; //world-space object position Vector3 position = new Vector3( (obj.pos.x) / hash.size * terrainSize.dimensions, // relative (0-1) position * terrain dimension (obj.height + terrainHeight) * terrainSize.height, (obj.pos.y) / hash.size * terrainSize.dimensions); //rotation + taking terrain normal Quaternion rotation; float objRotation = layer.rotate ? obj.rotation % 360 : 0; if (layer.takeTerrainNormal) { Vector3 terrainNormal = 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 == BiomeBlendType.Scale) { float biomeVal = 1; if (allGensMasks[g].item2 != null) { biomeVal = allGensMasks[g].item2[obj.pos]; } if (biomeVal < 0.001f) { continue; } scale *= biomeVal; } transitionsList.Add(new ObjectPool.Transition() { pos = position, rotation = rotation, scale = scale }); } } } //queue apply if (stop != null && stop(0)) { return; } results.apply.CheckAdd(typeof(MadMapsObjectOutput), transitions, replace: true); }
public void Process(global::MapMagic.CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func <float, bool> stop = null) { if (stop != null && stop(0)) { return; } Matrix result = new Matrix(rect); foreach (MadMapsStencilOutput gen in gens.GeneratorsOfType <MadMapsStencilOutput>(onlyEnabled: true, checkBiomes: true)) { Matrix input = (Matrix)gen.input.GetObject(results); if (input == null) { continue; } //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 } } //adding to final result if (gen.biome == null) { result.Add(input); } else if (biomeMask != null) { result.Add(input, biomeMask); } } //creating 2d array if (stop != null && stop(0)) { return; } int heightSize = terrainSize.resolution; var stencil = new Stencil(heightSize, heightSize); int key = 1; for (int x = 0; x < heightSize - 1; x++) { for (int z = 0; z < heightSize - 1; z++) { float strength; int disposableKey; MiscUtilities.DecompressStencil(stencil[x, z], out disposableKey, out strength); var writeValue = result[x + results.heights.rect.offset.x, z + results.heights.rect.offset.z]; stencil[x, z] = MiscUtilities.CompressStencil(key, strength + writeValue); } } //pushing to apply if (stop != null && stop(0)) { return; } results.apply.CheckAdd(typeof(MadMapsStencilOutput), stencil, replace: true); }
public static void Process(MapMagic.CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func <float, bool> stop = null) { if (stop != null && stop(0)) { return; } Noise noise = new Noise(12345, permutationCount: 128); //to pick objects based on biome List <TreeInstance> instancesList = new List <TreeInstance>(); List <TreePrototype> prototypesList = new List <TreePrototype>(); //find all of the biome masks - they will be used to determine object probability List <TupleSet <MadMapsTreeOutput, Matrix> > allGensMasks = new List <TupleSet <MadMapsTreeOutput, Matrix> >(); foreach (MadMapsTreeOutput gen in gens.GeneratorsOfType <MadMapsTreeOutput>(onlyEnabled: true, checkBiomes: true)) { 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 } } allGensMasks.Add(new TupleSet <MadMapsTreeOutput, Matrix>(gen, biomeMask)); } int allGensMasksCount = allGensMasks.Count; //biome rect to find array pos faster MapMagic.CoordRect biomeRect = new MapMagic.CoordRect(); for (int g = 0; g < allGensMasksCount; g++) { if (allGensMasks[g].item2 != null) { biomeRect = allGensMasks[g].item2.rect; break; } } //prepare biome mask values stack to re-use it to find per-coord biome float[] biomeVals = new float[allGensMasksCount]; //+1 for not using any object at all //iterating all gens for (int g = 0; g < allGensMasksCount; g++) { MadMapsTreeOutput gen = allGensMasks[g].item1; //iterating in layers for (int b = 0; b < gen.baseLayers.Length; b++) { if (stop != null && stop(0)) { return; //checking stop before reading output } Layer layer = gen.baseLayers[b]; // if (layer.prefab == null) continue; //loading objects from input SpatialHash hash = (SpatialHash)gen.baseLayers[b].input.GetObject(results); if (hash == null) { continue; } //adding prototype // if (layer.prefab == null) continue; TreePrototype prototype = new TreePrototype() { prefab = layer.prefab, bendFactor = layer.bendFactor }; prototypesList.Add(prototype); int prototypeNum = prototypesList.Count - 1; //filling instances (no need to check/add key in multidict) foreach (SpatialObject obj in hash.AllObjs()) { //blend biomes - calling continue if improper biome if (biomeBlendType == BiomeBlendType.Sharp) { float biomeVal = 1; if (allGensMasks[g].item2 != null) { biomeVal = allGensMasks[g].item2[obj.pos]; } if (biomeVal < 0.5f) { continue; } } else if (biomeBlendType == BiomeBlendType.AdditiveRandom) { float biomeVal = 1; if (allGensMasks[g].item2 != null) { biomeVal = allGensMasks[g].item2[obj.pos]; } float rnd = noise.Random((int)obj.pos.x, (int)obj.pos.y); if (biomeVal > 0.5f) { rnd = 1 - rnd; } if (biomeVal < rnd) { continue; } } else if (biomeBlendType == BiomeBlendType.NormalizedRandom) { //filling biome masks values int pos = biomeRect.GetPos(obj.pos); for (int i = 0; i < allGensMasksCount; i++) { if (allGensMasks[i].item2 != null) { biomeVals[i] = allGensMasks[i].item2.array[pos]; } else { biomeVals[i] = 1; } } //calculate normalized sum float sum = 0; for (int i = 0; i < biomeVals.Length; i++) { sum += biomeVals[i]; } if (sum > 1) //note that if sum is <1 usedBiomeNum can exceed total number of biomes - it means that none object is used here { for (int i = 0; i < biomeVals.Length; i++) { biomeVals[i] = biomeVals[i] / sum; } } //finding used biome num float rnd = noise.Random((int)obj.pos.x, (int)obj.pos.y); int usedBiomeNum = biomeVals.Length; //none biome by default sum = 0; for (int i = 0; i < biomeVals.Length; i++) { sum += biomeVals[i]; if (sum > rnd) { usedBiomeNum = i; break; } } //disable object using biome mask if (usedBiomeNum != g) { continue; } } //scale mode is applied a bit later //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; } TreeInstance tree = new TreeInstance(); tree.position = new Vector3( (obj.pos.x - hash.offset.x) / hash.size, obj.height + terrainHeight, (obj.pos.y - hash.offset.y) / hash.size); tree.rotation = layer.rotate ? obj.rotation % 360 : 0; tree.widthScale = layer.widthScale ? obj.size : 1; tree.heightScale = layer.heightScale ? obj.size : 1; tree.prototypeIndex = prototypeNum; tree.color = layer.color; tree.lightmapColor = layer.color; if (biomeBlendType == BiomeBlendType.Scale) { float biomeVal = 1; if (allGensMasks[g].item2 != null) { biomeVal = allGensMasks[g].item2[obj.pos]; } if (biomeVal < 0.001f) { continue; } tree.widthScale *= biomeVal; tree.heightScale *= biomeVal; } instancesList.Add(tree); } } } //setting output if (stop != null && stop(0)) { return; } if (instancesList.Count == 0 && prototypesList.Count == 0) { return; //empty, process is caused by height change } TupleSet <TreeInstance[], TreePrototype[]> treesTuple = new TupleSet <TreeInstance[], TreePrototype[]>(instancesList.ToArray(), prototypesList.ToArray()); results.apply.CheckAdd(typeof(MadMapsTreeOutput), treesTuple, replace: true); }
public static void Process(CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func <float, bool> stop = null) { #if VEGETATION_STUDIO_PRO if (stop != null && stop(0)) { return; } //gathering prototypes and matrices lists List <Layer> prototypesList = new List <Layer>(); List <Matrix> matrices = new List <Matrix>(); List <Matrix> biomeMasks = new List <Matrix>(); VegetationPackagePro package = null; foreach (VSProMapsOutput gen in gens.GeneratorsOfType <VSProMapsOutput>(onlyEnabled: true, checkBiomes: true)) { //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 } } for (int i = 0; i < gen.baseLayers.Length; i++) { //reading output directly Output output = gen.baseLayers[i].output; if (stop != null && stop(0)) { return; //checking stop before reading output } if (!results.results.ContainsKey(output)) { continue; } Matrix matrix = (Matrix)results.results[output]; matrix.Clamp01(); //adding to lists matrices.Add(matrix); biomeMasks.Add(gen.biome == null ? null : biomeMask); prototypesList.Add(gen.baseLayers[i]); package = gen.package; } } //optimizing matrices list if they are not used // for (int i = matrices.Count - 1; i >= 0; i--) // if (opacities[i] < 0.001f || matrices[i].IsEmpty() || (biomeMasks[i] != null && biomeMasks[i].IsEmpty())) // { prototypesList.RemoveAt(i); opacities.RemoveAt(i); matrices.RemoveAt(i); biomeMasks.RemoveAt(i); } int numLayers = matrices.Count; if (numLayers == 0) { results.apply.CheckAdd(typeof(VSProMapsOutput), new TupleSet <Color[][], int[], VegetationPackagePro>(new Color[0][], new int[0], package), replace: true); return; } int maxX = MapMagic.instance.resolution; int maxZ = MapMagic.instance.resolution; Dictionary <int, Color[]> grNumToColors = new Dictionary <int, Color[]>(); for (int i = 0; i < numLayers; i++) { int grNum = prototypesList[i].maskGroup; if (!grNumToColors.ContainsKey(grNum)) { grNumToColors.Add(grNum, new Color[maxX * maxZ]); } } //filling colors if (stop != null && stop(0)) { return; } float[] values = new float[numLayers]; //row, to avoid reading/writing 3d array (it is too slow) for (int x = 0; x < maxX; x++) { for (int z = 0; z < maxZ; z++) { int pos = rect.GetPos(x + rect.offset.x, z + rect.offset.z); float sum = 0; //getting values for (int i = 0; i < numLayers; i++) { float val = matrices[i].array[pos]; if (biomeMasks[i] != null) { val *= biomeMasks[i].array[pos]; //if mask is not assigned biome was ignored, so only main outs with mask==null left here } if (val < 0) { val = 0; } if (val > 1) { val = 1; } sum += val; //normalizing: calculating sum values[i] = val; } //normalizing for (int i = 0; i < numLayers; i++) { values[i] = values[i] / sum; } //setting color for (int i = 0; i < numLayers; i++) { Layer layer = prototypesList[i]; Color[] texColors = grNumToColors[layer.maskGroup]; int texturePos = z * maxX + x; float val = values[i]; switch (layer.textureChannel) { case 0: texColors[texturePos].r = val; break; case 1: texColors[texturePos].g = val; break; case 2: texColors[texturePos].b = val; break; case 3: texColors[texturePos].a = val; break; } } } } //creating arrays Color[][] colors = new Color[grNumToColors.Count][]; int[] maskGroupNums = new int[grNumToColors.Count]; int counter = 0; foreach (var kvp in grNumToColors) { maskGroupNums[counter] = kvp.Key; colors[counter] = kvp.Value; counter++; } //pushing to apply if (stop != null && stop(0)) { return; } TupleSet <Color[][], int[], VegetationPackagePro> mapsTuple = new TupleSet <Color[][], int[], VegetationPackagePro>(colors, maskGroupNums, package); results.apply.CheckAdd(typeof(VSProMapsOutput), mapsTuple, replace: true); #endif }
public static void Process(MapMagic.CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func <float, bool> stop = null) { if (stop != null && stop(0)) { return; } //gathering prototypes and matrices lists List <SplatPrototypeWrapper> prototypesList = new List <SplatPrototypeWrapper>(); List <float> opacities = new List <float>(); List <Matrix> matrices = new List <Matrix>(); List <Matrix> biomeMasks = new List <Matrix>(); foreach (MadMapsSplatOutput gen in gens.GeneratorsOfType <MadMapsSplatOutput>(onlyEnabled: true, checkBiomes: true)) { //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 } } for (int i = 0; i < gen.baseLayers.Length; i++) { if (!gen.baseLayers[i].Wrapper) { continue; } //reading output directly Output output = gen.baseLayers[i].output; if (stop != null && stop(0)) { return; //checking stop before reading output } if (!results.results.ContainsKey(output)) { continue; } Matrix matrix = (Matrix)results.results[output]; matrix.Clamp01(); //adding to lists matrices.Add(matrix); biomeMasks.Add(gen.biome == null ? null : biomeMask); prototypesList.Add(gen.baseLayers[i].Wrapper); opacities.Add(gen.baseLayers[i].opacity); } } //optimizing matrices list if they are not used // for (int i = matrices.Count - 1; i >= 0; i--) // if (opacities[i] < 0.001f || matrices[i].IsEmpty() || (biomeMasks[i] != null && biomeMasks[i].IsEmpty())) // { prototypesList.RemoveAt(i); opacities.RemoveAt(i); matrices.RemoveAt(i); biomeMasks.RemoveAt(i); } //creating array float[,,] splats3D = new float[terrainSize.resolution, terrainSize.resolution, prototypesList.Count]; if (matrices.Count == 0) { results.apply.CheckAdd(typeof(MadMapsSplatOutput), new TupleSet <float[, , ], SplatPrototypeWrapper[]>(splats3D, new SplatPrototypeWrapper[0]), replace: true); return; } //filling array if (stop != null && stop(0)) { return; } int numLayers = matrices.Count; int maxX = splats3D.GetLength(0); int maxZ = splats3D.GetLength(1); //MapMagic.instance.resolution should not be used because of possible lods //MapMagic.CoordRect rect = matrices[0].rect; float[] values = new float[numLayers]; //row, to avoid reading/writing 3d array (it is too slow) for (int x = 0; x < maxX; x++) { for (int z = 0; z < maxZ; z++) { int pos = rect.GetPos(x + rect.offset.x, z + rect.offset.z); float sum = 0; //getting values for (int i = 0; i < numLayers; i++) { float val = matrices[i].array[pos]; if (biomeMasks[i] != null) { val *= biomeMasks[i].array[pos]; //if mask is not assigned biome was ignored, so only main outs with mask==null left here } if (val < 0) { val = 0; } if (val > 1) { val = 1; } sum += val; //normalizing: calculating sum values[i] = val; } //setting color for (int i = 0; i < numLayers; i++) { splats3D[z, x, i] = values[i] / sum; } } } //pushing to apply if (stop != null && stop(0)) { return; } TupleSet <float[, , ], SplatPrototypeWrapper[]> splatsTuple = new TupleSet <float[, , ], SplatPrototypeWrapper[]>(splats3D, prototypesList.ToArray()); results.apply.CheckAdd(typeof(MadMapsSplatOutput), splatsTuple, replace: true); }
public static void Process(MapMagic.CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func <float, bool> stop = null) { if (stop != null && stop(0)) { return; } //reading height outputs if (results.heights == null || results.heights.rect.size.x != rect.size.x) { results.heights = new Matrix(rect); } results.heights.rect.offset = rect.offset; results.heights.Clear(); _pendingWrappers.Add(rect); //processing main height foreach (MadMapsHeightOutput gen in gens.GeneratorsOfType <MadMapsHeightOutput>(onlyEnabled: true, checkBiomes: true)) { //if (stop!=null && stop(0)) return; //do not break while results.heights is empty! //loading inputs Matrix heights = (Matrix)gen.input.GetObject(results); if (heights == null) { continue; } //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 } } //adding to final result if (gen.biome == null) { results.heights.Add(heights); } else if (biomeMask != null) { results.heights.Add(heights, biomeMask); } } //creating 2d array if (stop != null && stop(0)) { return; } int heightSize = terrainSize.resolution * scale + 1; float[,] heights2D = new float[heightSize, heightSize]; for (int x = 0; x < heightSize - 1; x++) { for (int z = 0; z < heightSize - 1; z++) { if (scale == 1) { heights2D[z, x] += results.heights[x + results.heights.rect.offset.x, z + results.heights.rect.offset.z]; } else { float fx = 1f * x / scale; float fz = 1f * z / scale; heights2D[z, x] = results.heights.GetInterpolated(fx + results.heights.rect.offset.x, fz + results.heights.rect.offset.z); } } } //blur only original base verts if (scale == 2) { float blurVal = 0.2f; for (int z = 0; z < heightSize - 1; z += 2) { for (int x = 2; x < heightSize - 1; x += 2) { heights2D[x, z] = (heights2D[x - 1, z] + heights2D[x + 1, z]) / 2 * blurVal + heights2D[x, z] * (1 - blurVal); } } for (int x = 0; x < heightSize - 1; x += 2) { for (int z = 2; z < heightSize - 1; z += 2) { heights2D[x, z] = (heights2D[x, z - 1] + heights2D[x, z + 1]) / 2 * blurVal + heights2D[x, z] * (1 - blurVal); } } } //blur high scale values if (scale == 4) { int blurIterations = 2; for (int i = 0; i < blurIterations; i++) { float prev = 0; float curr = 0; float next = 0; for (int x = 0; x < heightSize; x++) { prev = heights2D[x, 0]; curr = prev; for (int z = 1; z < heightSize - 2; z++) { next = heights2D[x, z + 1]; curr = (next + prev) / 2; // * blurVal + curr*(1-blurVal); heights2D[x, z] = curr; prev = curr; curr = next; } } for (int z = 0; z < heightSize; z++) { prev = heights2D[0, z]; curr = prev; for (int x = 1; x < heightSize - 2; x++) { next = heights2D[x + 1, z]; curr = (next + prev) / 2; // * blurVal + curr*(1-blurVal); heights2D[x, z] = curr; prev = curr; curr = next; } } } } //processing sides for (int x = 0; x < heightSize; x++) { float prevVal = heights2D[heightSize - 3, x]; //size-2 float currVal = heights2D[heightSize - 2, x]; //size-1, point on border float nextVal = currVal - (prevVal - currVal); heights2D[heightSize - 1, x] = nextVal; } for (int z = 0; z < heightSize; z++) { float prevVal = heights2D[z, heightSize - 3]; //size-2 float currVal = heights2D[z, heightSize - 2]; //size-1, point on border float nextVal = currVal - (prevVal - currVal); heights2D[z, heightSize - 1] = nextVal; } heights2D[heightSize - 1, heightSize - 1] = heights2D[heightSize - 1, heightSize - 2]; for (int x = 0; x < heightSize - 1; x++) { for (int z = 0; z < heightSize - 1; z++) { heights2D[z, x] = Mathf.Clamp01(heights2D[z, x]); } } //pushing to apply if (stop != null && stop(0)) { return; } #if UN_MapMagic if (FoliageCore_MainManager.instance != null) { float resolutionDifferences = (float)MapMagic.instance.terrainSize / terrainSize.resolution; uNatureHeightTuple heightTuple = new uNatureHeightTuple(heights2D, new Vector3(rect.Min.x * resolutionDifferences, 0, rect.Min.z * resolutionDifferences)); // transform coords results.apply.CheckAdd(typeof(MadMapsHeightOutput), heightTuple, replace: true); } else { //Debug.LogError("uNature_MapMagic extension is enabled but no foliage manager exists on the scene."); //return; results.apply.CheckAdd(typeof(MadMapsHeightOutput), heights2D, replace: true); } #else results.apply.CheckAdd(typeof(MadMapsHeightOutput), heights2D, replace: true); #endif }
public override void OnGUI(GeneratorsAsset gens) { layout.Field(ref LayerName, "Layer"); #if VEGETATION_STUDIO layout.Par(30); layout.Icon("VegetationStudioSplashSmall", layout.Inset(), Layout.IconAligment.resize, Layout.IconAligment.resize); layout.Par(5); layout.fieldSize = 0.6f; package = layout.Field(package, "Package"); //layers if (package != null) { if (layers.Length != package.VegetationInfoList.Count) { layers = new Layer[package.VegetationInfoList.Count]; } layout.Par(5); for (int num = 0; num < layers.Length; num++) { layout.DrawLayer(OnLayerGUI, ref selected, num); } } else { layers = new Layer[0]; } //warnings layout.margin = 5; if (package != null) { if (package.UseTerrainTextures) { layout.Par(42); layout.Label("Package Update Terrain Textures On Init is turned on.", rect: layout.Inset(0.8f), helpbox: true); if (layout.Button("Fix", rect: layout.Inset(0.2f))) { package.UseTerrainTextures = false; } } bool runtimeSpawnEnabled = false; foreach (var v in package.VegetationInfoList) { if (v.EnableRuntimeSpawn) { runtimeSpawnEnabled = true; break; } } if (runtimeSpawnEnabled) { layout.Par(42); layout.Label("Runtime spawn is enabled on some Vegetetaion Items.", rect: layout.Inset(0.8f), helpbox: true); if (layout.Button("Fix", rect: layout.Inset(0.2f))) { foreach (var v in package.VegetationInfoList) { v.EnableRuntimeSpawn = false; } } } } #endif }
public 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; } Noise noise = new Noise(12345, permutationCount: 128); //to pick objects based on biome if (stop != null && stop(0)) { return; } List <VegetationStudioInstance> instances = new List <VegetationStudioInstance>(); //object outputs foreach (MadMapsVSOutput gen in gens.GeneratorsOfType <MadMapsVSOutput>(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, (obj.height + terrainHeight) * terrainSize.height, (obj.pos.y - hash.offset.y) / hash.size); //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; } instances.Add(new VegetationStudioInstance() { VSID = id, Guid = System.Guid.NewGuid().ToString(), Package = package, Position = position, Scale = scale, Rotation = rotation.eulerAngles, }); } if (stop != null && stop(0)) { return; } } int cellXCount = Mathf.CeilToInt(terrainSize.dimensions / cellSize); int cellZCount = Mathf.CeilToInt(terrainSize.dimensions / cellSize); //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); var position = new Vector3(mx, 0, mz); instances.Add(new VegetationStudioInstance() { VSID = id, Guid = System.Guid.NewGuid().ToString(), Package = package, Position = position, Scale = scale, Rotation = rotation.eulerAngles, }); } } } 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(MadMapsVSOutput), instances, replace: true); }