private IEnumerator GenerateSection_CR(SectionCoord coord) { TerrainSection sec; if (terrains.TryGetValue(coord, out sec) && sec != null && sec.terrain != null) { if (numGenThreads > 0) { numGenThreads--; } yield break; } if (sec == null) { sec = new TerrainSection(coord); } float[,] heightmap = null; float[,,] alphamaps = null; int bx, bz; float height; Vector3 targLoc; GameObject go; BiomeData bd; List <SectionCoord> biomeCenters; List <Biome> containedBiomes = null; List <DetailPrototypeData> detailPrototypeDatas = null; List <int[, ]> detailMaps = null; List <TreePrototypeData> treePrototypeDatas = null; List <TreeInstance> treeInstances = null; Thread heightThread = new Thread(() => { #if DEBUG_THREADS UnityEngine.Profiling.Profiler.BeginThreadProfiling( "Heightmap", "" + coord.x + ":" + coord.z); #endif heightmap = GenerateHeightmap(coord); #if DEBUG_THREADS UnityEngine.Profiling.Profiler.EndThreadProfiling(); #endif }); Thread alphaThread = new Thread(() => { #if DEBUG_THREADS UnityEngine.Profiling.Profiler.BeginThreadProfiling( "Alphamap", "" + coord.x + ":" + coord.z); #endif alphamaps = GenerateAlphamaps(coord, out containedBiomes); #if DEBUG_THREADS UnityEngine.Profiling.Profiler.EndThreadProfiling(); #endif }); Thread detailThread = new Thread(() => { #if DEBUG_THREADS UnityEngine.Profiling.Profiler.BeginThreadProfiling( "Detailmap", "" + coord.x + ":" + coord.z); #endif detailMaps = GenerateDetailMaps(coord, out detailPrototypeDatas); #if DEBUG_THREADS UnityEngine.Profiling.Profiler.EndThreadProfiling(); #endif }); Thread treeThread = new Thread(() => { #if DEBUG_THREADS UnityEngine.Profiling.Profiler.BeginThreadProfiling( "Treemap", "" + coord.x + ":" + coord.z); #endif treeInstances = GenerateTreeInstances(coord, out treePrototypeDatas); #if DEBUG_THREADS UnityEngine.Profiling.Profiler.EndThreadProfiling(); #endif }); yield return(null); treeThread.Start(); yield return(null); heightThread.Start(); yield return(null); alphaThread.Start(); yield return(null); detailThread.Start(); yield return(new WaitUntil(() => (heightmap != null && alphamaps != null && detailMaps != null && treeInstances != null && !loadingSection))); TerrainLayer[] terrainLayers = new TerrainLayer[containedBiomes.Count]; loadingSection = true; sectionLoading = coord; TerrainData data = new TerrainData(); data.heightmapResolution = genSettings.heightMapRes; yield return(null); data.alphamapResolution = genSettings.alphaMapRes; data.SetDetailResolution(genSettings.detailMapRes, genSettings.detailMapResPerPatch); data.size = new Vector3(genSettings.length, genSettings.height, genSettings.length); yield return(null); data.SetHeights(0, 0, heightmap); yield return(null); for (int i = 0; i < containedBiomes.Count; i++) { terrainLayers[i] = containedBiomes[i].terrainLayer; } DetailPrototype[] detailPrototypes = null; if (detailPrototypeDatas.Count > 0) { detailPrototypes = new DetailPrototype[detailPrototypeDatas.Count]; } for (int i = 0; i < detailPrototypeDatas.Count; i++) { DetailPrototype dp = detailPrototypes[i] = new DetailPrototype(); DetailPrototypeData dpd = detailPrototypeDatas[i]; dp.bendFactor = dpd.bendFactor; dp.dryColor = dpd.dryColor; dp.healthyColor = dpd.healthyColor; dp.maxHeight = dpd.maxHeight; dp.maxWidth = dpd.maxWidth; dp.minHeight = dpd.minHeight; dp.minWidth = dpd.minWidth; dp.noiseSpread = dpd.noiseSpread; if (dpd.prototype != null) { dp.prototype = dpd.prototype; dp.usePrototypeMesh = true; } else { dp.prototypeTexture = dpd.prototypeTexture; dp.usePrototypeMesh = false; } dp.renderMode = dpd.renderMode; } yield return(null); data.terrainLayers = terrainLayers; data.SetAlphamaps(0, 0, alphamaps); yield return(null); TreePrototype[] treePrototypes = null; if (treePrototypeDatas.Count > 0) { treePrototypes = new TreePrototype[treePrototypeDatas.Count]; } for (int i = 0; i < treePrototypeDatas.Count; i++) { TreePrototype tp = treePrototypes[i] = new TreePrototype(); tp.bendFactor = treePrototypeDatas[i].bendFactor; tp.prefab = treePrototypeDatas[i].prefab; } yield return(null); if (detailPrototypes != null) { data.detailPrototypes = detailPrototypes; yield return(null); for (int i = 0; i < detailMaps.Count; i++) { data.SetDetailLayer(0, 0, i, detailMaps[i]); } yield return(null); } if (treePrototypes != null) { data.treePrototypes = treePrototypes; yield return(null); data.SetTreeInstances(treeInstances.ToArray(), true); } yield return(null); data.RefreshPrototypes(); yield return(null); GameObject obj = Terrain.CreateTerrainGameObject(data); sec.terrain = obj.GetComponent <Terrain>(); sec.terrain.treeBillboardDistance = 150; sec.terrain.materialTemplate = terrainMaterial; sec.terrain.allowAutoConnect = true; obj.transform.position = new Vector3(coord.x * genSettings.length - genSettings.length / 2, 0f, coord.z * genSettings.length - genSettings.length / 2); yield return(null); sec.terrain.Flush(); yield return(null); bx = Mathf.RoundToInt((coord.x * genSettings.length) / biomeCenterSpacing); bz = Mathf.RoundToInt((coord.z * genSettings.length) / biomeCenterSpacing); biomeCenters = SectionsInRadius(new SectionCoord(bx, bx), 2); for (int i = 0; i < biomeCenters.Count; i++) { BiomeCenter center = SafeGetBiomeCenter(biomeCenters[i]); height = sec.terrain.SampleHeight(center.center); targLoc = new Vector3(center.center.x, height, center.center.z + sec.terrain.GetPosition().y); if (sec.terrain.terrainData.bounds.Contains(targLoc - sec.terrain.transform.position)) { if (center.biome.ambientPrefab != null) { go = Instantiate(center.biome.ambientPrefab, targLoc, Quaternion.identity, sec.terrain.transform); } else { go = new GameObject(); go.transform.position = targLoc; go.transform.parent = sec.terrain.transform; } bd = go.AddComponent <TerrainManager.BiomeData>(); bd.biome = center.biome; bd.center = targLoc; bd.boundaries = center.properBounds.Values.ToList(); SimplifyConvexPlanes(bd.boundaries, bd.center); } } yield return(null); terrains.Add(coord, sec); if (numGenThreads > 0) { numGenThreads--; } generating.Remove(coord); if (coord.Equals(sectionLoading)) { loadingSection = false; } }
protected override bool DrawWizardGUI() { EditorGUILayout.LabelField("Add terrains or objects here: "); using (new ScopedLayout(() => { EditorGUILayout.BeginVertical("Box"); }, EBeginMode.BEGIN_HORIZONTAL)) { GameObject possibleTerrains = EditorGUILayout.ObjectField(null, typeof(GameObject), true) as GameObject; if (possibleTerrains != null) { List <Terrain> terrains = new List <Terrain>(); RecursivelyExtractTerrains(possibleTerrains, terrains); for (int i = 0; i < terrains.Count; i++) { Terrain extr = terrains[i]; if (m_TerrainsExtract.Contains(extr) == false) { if (extr.GetComponent <Terrain>() != null) { // If it's the first (main) terrain if (m_TerrainsExtract.Count == 0) { DetailPrototype[] protos = extr.GetComponent <Terrain>().terrainData.detailPrototypes; if (protos != null && protos.Length > 0) { m_TerrainsExtract.Add(extr); } else { EditorUtility.DisplayDialog("Warning!", "The first added (main) terrain does not have any terrain details!", "Ok"); } } else { // Check if the same details appear if (HasSameDetails(m_TerrainsExtract[0].GetComponent <Terrain>(), extr.GetComponent <Terrain>())) { m_TerrainsExtract.Add(extr); } else { EditorUtility.DisplayDialog("Warning!", "The added terrain does not have the same details as the first (main) terrain!", "Ok"); } } } else { EditorUtility.DisplayDialog("Warning!", "You can only extract details from terrains!", "Ok"); } } } } } // Display all the detail data if (m_TerrainsExtract.Count == 0) { return(false); } EditorGUILayout.Space(); // Extracted terrains EditorGUILayout.LabelField("Terrain to extract details from: "); // Show the data using (new ScopedLayout(() => { EditorGUILayout.BeginVertical("Box"); }, EBeginMode.BEGIN_HORIZONTAL)) { for (int i = 0; i < m_TerrainsExtract.Count; i++) { EditorGUILayout.LabelField("(T) " + m_TerrainsExtract[i].name + (i == 0 ? " [Main Details]" : "")); } } EditorGUILayout.Space(); EditorGUILayout.LabelField("Details mappings: "); if (m_Prototypes == null) { m_Prototypes = m_TerrainsExtract[0].GetComponent <Terrain>().terrainData.detailPrototypes; if (m_Prototypes == null || m_Prototypes.Length == 0) { FoliageLog.e("No terrain details found!"); return(false); } // Generate the UI data m_PrototypesData = new DetailPrototypeData[m_Prototypes.Length]; for (int i = 0; i < m_PrototypesData.Length; i++) { m_PrototypesData[i] = new DetailPrototypeData(); m_PrototypesData[i].m_DetailLayer = i; string protoName = m_Prototypes[i].prototype != null ? m_Prototypes[i].prototype.name : m_Prototypes[i].prototypeTexture.name; // Attempt to search through the data to check for a name or something int foundIdx = m_TypesRuntime.FindIndex((x) => { return(x.m_Name.ToLowerInvariant().Replace(" ", "").Contains(protoName.ToLowerInvariant().Replace(" ", ""))); }); if (foundIdx >= 0) { m_PrototypesData[i].m_NoneMapping = false; m_PrototypesData[i].m_FoliageHashMapping = m_TypesRuntime[foundIdx].m_Hash; m_PrototypesData[i].m_FoliageTypeNameMapping = m_TypesRuntime[foundIdx].m_Name; } } } // Set all the data related to that terrain and stuff DetailPrototype[] prototypes = m_Prototypes; using (new ScopedLayout(() => { EditorGUILayout.BeginVertical("Box"); }, EBeginMode.BEGIN_VERTICAL)) { for (int i = 0; i < prototypes.Length; i++) { DetailPrototype proto = prototypes[i]; DetailPrototypeData protoData = m_PrototypesData[i]; using (new ScopedLayout(() => { EditorGUILayout.BeginVertical(); }, EBeginMode.BEGIN_HORIZONTAL)) { string name; if (proto.prototype != null) { name = proto.prototype.name; } else { name = proto.prototypeTexture.name; } // Each prototype data using (new ScopedLayout(() => { EditorGUILayout.BeginHorizontal(); }, EBeginMode.BEGIN_HORIZONTAL)) { protoData.m_ShouldExtract = EditorGUILayout.Toggle(new GUIContent("Extract: [" + name + "]", "If we should extract that type"), protoData.m_ShouldExtract); if (protoData.m_ShouldExtract) { EditorGUILayout.LabelField("as: ", GUILayout.Width(30)); bool dropdown = EditorGUILayout.DropdownButton(new GUIContent(protoData.m_NoneMapping ? "None" : protoData.m_FoliageTypeNameMapping, "To what foliage type this detail will be changed transformed when extracting from the terrain"), FocusType.Passive); if (dropdown) { GenericMenu menu = new GenericMenu(); menu.AddItem(new GUIContent("None"), protoData.m_NoneMapping, (object obj) => { protoData.m_NoneMapping = true; }, null); menu.AddSeparator(""); for (int r = 0; r < m_TypesRuntime.Count; r++) { FoliageTypeRuntime rt = m_TypesRuntime[r]; bool on = protoData.m_NoneMapping == false && protoData.m_FoliageHashMapping == rt.m_Hash; menu.AddItem(new GUIContent(rt.m_Name), on, (object obj) => { protoData.m_NoneMapping = false; protoData.m_FoliageHashMapping = ((FoliageTypeRuntime)obj).m_Hash; protoData.m_FoliageTypeNameMapping = ((FoliageTypeRuntime)obj).m_Name; }, rt); } menu.ShowAsContext(); } } } if (protoData.m_ShouldExtract) { protoData.m_ExtractedDensity = EditorGUILayout.Slider(new GUIContent("[" + name + "] Density [0..1]", "A multiplier for the count of extracted details from the terrain. 1 means extract all instances, 0.5 means extract half of them, 0 extract none. " + "Use mostly for extracted grass, but not details like rocks or anything else like that. Since on the terrain we only have a lot of billboards as " + "grass and we might map them to some 3D mesh clumps it's higly likely that we will only need a half (0.5) or a third (0.3) of that existing terrain data. "), protoData.m_ExtractedDensity, 0, 1); } } } } EditorGUILayout.Space(); // Settings EditorGUILayout.LabelField("Settings: "); using (new ScopedLayout(() => { EditorGUILayout.BeginVertical("Box"); }, EBeginMode.BEGIN_VERTICAL)) { m_DisableAfterExtraction = EditorGUILayout.Toggle(new GUIContent( "Disable After Extraction", "If we should disable the details after we extracted them from the terrain. This will will set 'Terrain.drawTreesAndFoliage' to false."), m_DisableAfterExtraction, GUILayout.ExpandWidth(true)); bool deleteAfterExtraction = EditorGUILayout.Toggle(new GUIContent( "Delete After Extraction", "If this is checked it will delete all the details that were extracted. Will delete the extracted details. Not advisable!"), m_DeleteAfterExtraction, GUILayout.ExpandWidth(true)); if (m_DeleteAfterExtraction != deleteAfterExtraction) { if (deleteAfterExtraction) { bool sure = EditorUtility.DisplayDialog("Warning", "Setting this to true will delete all the extracted details from the terrain! " + "Not recomended if you want to try multiple iterations! Are you sure?", "Yes", "No"); if (sure) { m_DeleteAfterExtraction = true; } } else { m_DeleteAfterExtraction = deleteAfterExtraction; } } } return(false); }