Пример #1
0
        /// <summary>
        /// Works the same as <see cref="GenerateCoroutine"/> without the
        /// yield instructions. Runs synchronously.
        /// </summary>
        /// <param name="remapMin"></param>
        /// <param name="remapMax"></param>
        private void GenerateEditor(float remapMin = 0f, float remapMax = 1f)
        {
            TerraConfig.Log($"Started tile {GridPosition.ToString()}");

            //Make & set heightmap
            MeshManager.CalculateHeightmap(GridPosition, remapMin, remapMax);

            MeshManager.SetTerrainHeightmap();
            MeshManager.SetVisible();

            //Create TilePaint object
            TilePaint painter = new TilePaint(this);

            //Make biomemap
            int[,] map = painter.GetBiomeMap();

            //Paint terrain
            painter.Paint(map);

            //Apply details to terrain
            // ReSharper disable once IteratorMethodResultIsIgnored
            ApplyDetails(painter, map);
            MeshManager.SetVisible(true);

            TerraConfig.Log("Completed tile " + GridPosition);
        }
Пример #2
0
        private IEnumerator GenerateCoroutine(Action onComplete, float remapMin = 0f, float remapMax = 1f)
        {
            TerraConfig conf = TerraConfig.Instance;

            TerraConfig.Log("Started tile " + GridPosition);

            //Make & set heightmap
            bool madeHm = false;

            MeshManager.CalculateHeightmapAsync(remapMin, remapMax, () => madeHm = true);
            while (!madeHm)
            {
                yield return(null);
            }

            MeshManager.SetTerrainHeightmap();
            MeshManager.SetVisible();

            //Create TilePaint object
            TilePaint painter = new TilePaint(this);

            //Make biomemap
            bool madeBm = false;

            int[,] map = null;
            conf.Worker.Enqueue(() => map = painter.GetBiomeMap(), () => madeBm = true);
            while (!madeBm)
            {
                yield return(null); //Skip frame until biomemap made
            }
            //Paint terrain
            bool madePaint = false;

            yield return(StartCoroutine(painter.PaintAsync(map, () => madePaint = true)));

            while (!madePaint)
            {
                yield return(null);
            }

            //Apply details to terrain
            bool madeDetails = false;

            yield return(StartCoroutine(ApplyDetails(painter, map, () => madeDetails = true)));

            while (!madeDetails)
            {
                yield return(null);
            }

            MeshManager.SetVisible(true);

            TerraConfig.Log("Completed tile " + GridPosition);
            onComplete();
        }
Пример #3
0
        /// <summary>
        /// Calculates the min and maximum values to use when applying a heightmap
        /// remap. This sets <see cref="RemapMax"/> and <see cref="RemapMin"/>.
        /// </summary>
        public void CalculateHeightmapRemap()
        {
            bool      shouldProfile = TerraConfig.Instance.EditorState.ShowDebugMessages;
            Stopwatch sw            = null;

            if (shouldProfile)
            {
                sw = new Stopwatch();
                sw.Start();
            }

            float min       = float.PositiveInfinity;
            float max       = float.NegativeInfinity;
            int   res       = Config.Generator.RemapResolution;
            var   generator = Config.Graph.GetEndGenerator();

            for (int x = 0; x < res; x++)
            {
                for (int z = 0; z < res; z++)
                {
                    float value = generator.GetValue(x / (float)res, z / (float)res, 0f);

                    if (value > max)
                    {
                        max = value;
                    }
                    if (value < min)
                    {
                        min = value;
                    }
                }
            }

            //Set remap values for instance
            _remapMin = min;
            _remapMax = max;

            if (shouldProfile)
            {
                sw.Stop();
                TerraConfig.Log("CalculateHeightmapRemap took " + sw.ElapsedMilliseconds + "ms to complete. " +
                                "New min=" + min + " New max=" + max);
            }
        }
Пример #4
0
        /// <summary>
        /// Sets the heightmap to the current LOD asynchronously
        /// </summary>
        public IEnumerator UpdateHeightmapAsync(Action onComplete, float remapMin, float remapMax)
        {
            MeshManager.Lod = GetLodLevel();

            bool updatedHm = false;

            TerraConfig.Log("Updating heightmap start");
            MeshManager.CalculateHeightmapAsync(remapMin, remapMax, () => {
                MeshManager.SetTerrainHeightmap();
                updatedHm = true;
            });

            while (!updatedHm)
            {
                yield return(null);
            }

            if (onComplete != null)
            {
                onComplete();
            }
        }
Пример #5
0
        /// <summary>
        /// Creates a heightmap of resolution <see cref="HeightmapResolution"/> asynchronously.
        /// If a <see cref="Heightmap"/> of the same resolution or higher has already been
        /// created, this method does nothing.
        /// A heightmap is 2D array of floats that represents the Y values (or heights)
        /// of to-be created vertices in 3D space.
        /// </summary>
        /// <param name="remapMin">Optionally linear transform the heightmap from [min, max] to [0, 1]</param>
        /// <param name="remapMax">Optionally linear transform the heightmap from [min, max] to [0, 1]</param>
        /// <param name="onComplete">Called when the heightmap has been created</param>
        public void CalculateHeightmapAsync(float remapMin = 0f, float remapMax = 1f, Action onComplete = null)
        {
            _lastGeneratedLodLevel = _tile.GetLodLevel();
            Lod = _lastGeneratedLodLevel;
            bool shouldProfile = TerraConfig.Instance.EditorState.ShowDebugMessages;

            Stopwatch wsw = null;

            if (shouldProfile)
            {
                wsw = new Stopwatch();
                wsw.Start();
            }
            TerraConfig.Instance.Worker.Enqueue(() => {
                Stopwatch sw = null;
                if (shouldProfile)
                {
                    sw = new Stopwatch();
                    Profiler.BeginThreadProfiling("Heightmap Workers", "Tile " + _tile.GridPosition);
                    sw.Start();
                }
                CalculateHeightmap(null, remapMin, remapMax);

                if (shouldProfile)
                {
                    sw.Stop();
                    TerraConfig.Log("Tile " + _tile.GridPosition + " heightmap time: " + sw.ElapsedMilliseconds);
                    Profiler.EndThreadProfiling();
                }
            }, () => {
                if (shouldProfile)
                {
                    wsw.Stop();
                    MTDispatch.Instance().Enqueue(() => { TerraConfig.Log("CalculateHM worker time elapsed " + wsw.ElapsedMilliseconds); onComplete(); });
                }
            });
        }
Пример #6
0
        /// <summary>
        /// Updates tiles that are surrounding the tracked GameObject
        /// asynchronously. When calling this method using
        /// <see cref="MonoBehaviour.StartCoroutine(IEnumerator)"/>,
        /// tiles are generated once per frame
        /// </summary>
        public IEnumerator UpdateTiles()
        {
            List <GridPosition> nearbyPositions = GetTilePositionsFromRadius();
            List <GridPosition> newPositions    = Cache.GetNewTilePositions(nearbyPositions);
            List <Tile>         toRegenerate    = new List <Tile>();

            RemoveOldPositions(ref nearbyPositions, ref toRegenerate);

            //Add new positions
            _queuedTiles = newPositions.Count + toRegenerate.Count;

            foreach (GridPosition pos in newPositions)
            {
                if (_isGenerating && Application.isPlaying) //Wait and generate one tile per frame
                {
                    yield return(null);
                }

                Tile cached = Cache.GetCachedTileAtPosition(pos);

                //Attempt to pull from cache, generate if not available
                if (cached != null)
                {
                    if (cached.IsHeightmapLodValid())   //Cached tile is valid, use it
                    {
                        AddTile(cached);
                        _queuedTiles--;

                        continue;
                    }

                    TerraConfig.Log("Cached tile " + cached + " has heightmap res=" + cached.MeshManager.HeightmapResolution +
                                    ". requested res=" + cached.GetLodLevel().Resolution + ". Regenerating.");

                    toRegenerate.Add(cached);
                    Cache.AddActiveTile(cached);
                    continue;
                }

                _isGenerating = true;
                CreateTileAt(pos, tile => {
                    _queuedTiles--;

                    if (_queuedTiles == 0)
                    {
                        UpdateNeighbors(newPositions.ToArray(), false);
                    }

                    _isGenerating = false;
                });
            }

            //Regenerate tiles with outdated heightmaps
            for (int i = 0; i < toRegenerate.Count; i++)
            {
                Tile t = toRegenerate[i];
                TerraConfig.Log("Active tile " + t + " has heightmap res=" + t.MeshManager.HeightmapResolution +
                                ". requested res=" + t.GetLodLevel().Resolution + ". Regenerating.");

                //Generate one tile per frame
                if (Application.isPlaying)
                {
                    yield return(null);
                }

                if (Application.isPlaying)
                {
                    Config.StartCoroutine(t.UpdateHeightmapAsync(() => {
                        UpdateNeighbors(new[] { t.GridPosition }, false);
                        _queuedTiles--;
                    }, RemapMin, RemapMax));
                }
                else
                {
                    t.UpdateHeightmap(RemapMin, RemapMax);
                }
            }

            //If tiles were updated synchronously, notify queue completion
            if (newPositions.Count > 0 && _queuedTiles == 0)
            {
                UpdateNeighbors(newPositions.ToArray(), false);
            }
        }