public void OnGUI(Layout layout, bool selected, int num, object parent) { #if VEGETATION_STUDIO_PRO VSProObjectsOutput vsOut = (VSProObjectsOutput)parent; VegetationPackagePro package = vsOut.package; //(VegetationPackagePro)vsOut.serializedPackage; VegetationSystemPro system = GameObject.FindObjectOfType <VegetationSystemPro>(); Layer layer = vsOut.baseLayers[num]; layout.margin = 20; layout.rightMargin = 5; layout.Par(20); input.DrawIcon(layout); if (package != null) { int itemInfoIndex = package.VegetationInfoList.FindIndex(i => i.VegetationItemID == layer.id); VegetationItemInfoPro itemInfo = itemInfoIndex >= 0 ? package.VegetationInfoList[itemInfoIndex] : null; Texture2D icon = null; if (itemInfo != null) { #if UNITY_EDITOR if (itemInfo.PrefabType == VegetationPrefabType.Mesh) { icon = AssetPreviewCache.GetAssetPreview(itemInfo.VegetationPrefab); } else { icon = AssetPreviewCache.GetAssetPreview(itemInfo.VegetationTexture); } #endif } layout.Icon(icon, rect: layout.Inset(20), frame: true, alphaBlend: false); layout.Inset(10); itemInfoIndex = layout.Popup(itemInfoIndex, objectNames, rect: layout.Inset(layout.field.width - 20 - 45)); if (itemInfoIndex >= 0) { layer.id = package.VegetationInfoList[itemInfoIndex].VegetationItemID; } } if (selected) { layout.Toggle(ref relativeHeight, "Relative Height"); layout.Toggle(ref rotate, "Rotate"); layout.Toggle(ref takeTerrainNormal, "Incline by Terrain"); layout.Par(); layout.Toggle(ref scale, "Scale", rect: layout.Inset(60)); layout.disabled = !scale; layout.Toggle(ref scaleY, rect: layout.Inset(18)); layout.Label("Y only", rect: layout.Inset(45)); //if (layout.lastChange) scaleU = false; layout.disabled = false; } #endif }
public static void Process(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 //find all of the biome masks - they will be used to determine object probability List <TupleSet <VSProObjectsOutput, Matrix> > allGensMasks = new List <TupleSet <VSProObjectsOutput, Matrix> >(); foreach (VSProObjectsOutput gen in gens.GeneratorsOfType <VSProObjectsOutput>(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 <VSProObjectsOutput, Matrix>(gen, biomeMask)); } int allGensMasksCount = allGensMasks.Count; //biome rect to find array pos faster CoordRect biomeRect = new 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 //preparing output Dictionary <string, List <ObjectPool.Transition> > transitions = new Dictionary <string, List <ObjectPool.Transition> >(); //iterating all gens for (int g = 0; g < allGensMasksCount; g++) { VSProObjectsOutput 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]; //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.id)) { transitionsList = new List <ObjectPool.Transition>(); transitions.Add(layer.id, transitionsList); } else { transitionsList = transitions[layer.id]; } //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); position += MapMagic.position; //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(VSProObjectsOutput), transitions, replace: true); }