Example #1
0
    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);
        }