Пример #1
0
        private void RenderBiomeOrderEditor()
        {
            BiomeNode[] biomes = En.GetBiomes();
            _biomeOrderProperty = serializedObject.FindProperty("BiomeOrder");

            if (_biomeOrderProperty.arraySize == biomes.Length)
            {
                return;
            }
            _biomeOrderProperty.ClearArray();

            for (int i = 0; i < biomes.Length; i++)
            {
                _biomeOrderProperty.arraySize++;
                _biomeOrderProperty.GetArrayElementAtIndex(i).intValue = i;
            }

            serializedObject.ApplyModifiedProperties();
            _reorderableList = new ReorderableList(
                serializedObject, _biomeOrderProperty, true, false, false, false
                )
            {
                drawElementCallback = (rect, index, active, focused) => {
                    BiomeNode selectedBiome =
                        En.GetBiomes()[index];
                    string name = String.IsNullOrEmpty(selectedBiome.Name) ? "Unnamed Biome" : selectedBiome.Name;
                    EditorGUI.LabelField(
                        new Rect(rect.x, rect.y, GetWidth() - 10, EditorGUIUtility.singleLineHeight),
                        name);
                }
            };
        }
Пример #2
0
        public Texture2D GetPreviewTexture(int size)
        {
            BiomeNode[] nodes = _combiner.GetConnectedBiomeNodes();
            Texture2D   tex   = new Texture2D(size, size);

            float[,,] map = GetBiomeMap(size);

            for (int x = 0; x < size; x++)
            {
                for (int y = 0; y < size; y++)
                {
                    Color final = new Color(0, 0, 0);

                    for (int z = 0; z < nodes.Length; z++)
                    {
                        float     weight = map[x, y, z];
                        BiomeNode biome  = nodes[z];

                        final += biome.PreviewColor * weight;
                    }

                    tex.SetPixel(x, y, final);
                }
            }

            tex.Apply();
            return(tex);
        }
Пример #3
0
        public BiomeNode[] GetBiomes()
        {
            BiomeNode[] biomes = GetInputValues <BiomeNode>("Biomes");
            if (BlendStrategy != BlendStrategy.ORDERED || BiomeOrder.Length != biomes.Length)
            {
                return(biomes);
            }

            BiomeNode[] sorted = new BiomeNode[biomes.Length];
            foreach (int i in BiomeOrder)
            {
                sorted[i] = biomes[BiomeOrder[i]];
            }

            return(sorted);
        }
        public override void OnBodyGUI()
        {
            //Output
            NodeEditorGUILayout.PropertyField(serializedObject.FindProperty("Output"));

            //Draw mix method enum
            SerializedProperty mixType = serializedObject.FindProperty("Mix");

            NodeEditorGUILayout.PropertyField(mixType, new GUIContent("Mix Type"));

            //Draw Instance Ports with colors
            if (!Bcn.DidAddPort)
            {
                NodePort[] ports = Bcn.GetInstanceInputs();

                for (var i = 0; i < ports.Length; i++)
                {
                    NodePort p = ports[i];
                    EditorGUILayout.BeginHorizontal();
                    NodeEditorGUILayout.PortField(p, GUILayout.ExpandWidth(false));

                    BiomeNode node = p.GetInputValue <BiomeNode>();
                    if (node != null)
                    {
#if UNITY_2018_1_OR_NEWER
                        EditorGUILayout.ColorField(GUIContent.none, node.PreviewColor, false, false, false,
                                                   GUILayout.MaxWidth(32f));
#else
                        EditorGUILayout.ColorField(GUIContent.none, node.PreviewColor,
                                                   false, false, false, null, GUILayout.MaxWidth(32f));
#endif
                    }

                    EditorGUILayout.EndHorizontal();
                }
            }
            else
            {
                Bcn.DidAddPort = false;
            }


            //Show Preview
            PreviewField.Show(Bcn);
        }
Пример #5
0
        /// <summary>
        /// Generates a map of biomes constructed from connected biome nodes.
        /// </summary>
        /// <param name="position">Position of this biome map in the grid of tiles</param>
        /// <param name="length">Length of a tile</param>
        /// <param name="spread">Divide x & z coordinates of the polled position by this number</param>
        /// <param name="resolution">Resolution of map</param>
        /// <returns></returns>
        public float[,,] GetBiomeMap(GridPosition position, int length, float spread, int resolution)
        {
            BiomeNode[] connected = _combiner.GetConnectedBiomeNodes();

            float[,,] biomeMap = new float[resolution, resolution, connected.Length];
            List <float[, ]> weightedBiomeValues = new List <float[, ]>(biomeMap.Length);

            //Gather each biome's values
            lock (_valueLock) {
                for (var i = 0; i < connected.Length; i++)
                {
                    BiomeNode biome = connected[i];
                    BiomeNode.BiomeMapResult biomeResults = biome.GetMapsValues(position, resolution, spread, length);
                    if (_cachedMinMax == null)
                    {
                        _cachedMinMax = CalculateMinMax(TerraConfig.Instance.Generator.RemapResolution);
                    }

                    float[,] weighted = biome.GetWeightedValues(biomeResults.Values, _cachedMinMax.Value.Min, _cachedMinMax.Value.Max);
                    weightedBiomeValues.Add(weighted);
                }
            }

            lock (_weightLock) {
                for (int x = 0; x < resolution; x++)
                {
                    for (int y = 0; y < resolution; y++)
                    {
                        float[] map = CalculateBiomeWeightsAt(x, y, connected, weightedBiomeValues);

                        for (int z = 0; z < map.Length; z++)
                        {
                            biomeMap[x, y, z] = map[z];
                        }
                    }
                }
            }

            return(biomeMap);
        }
Пример #6
0
        /// <summary>
        /// Generates a map of biomes constructed from connected biome nodes.
        /// </summary>
        /// <param name="position">Position of this biome map in the grid of tiles</param>
        /// <param name="length">Length of a tile</param>
        /// <param name="spread">Divide x & z coordinates of the polled position by this number</param>
        /// <param name="resolution">Resolution of map</param>
        /// <returns>
        /// Index of a biome enabled at each x, y coordinate. The index corresponds
        /// to the order of biomes defined in the node graph. e.g. an index of 0
        /// represents the first biome.
        /// </returns>
        public int[,] GetBiomeMap(GridPosition position, int length, float spread, int resolution)
        {
            List <float[, ]> allBiomeWeights = new List <float[, ]>(_biomes.Length);

            //Gather each biome's weights
            lock (_valueLock) {
                for (var i = 0; i < _biomes.Length; i++)
                {
                    BiomeNode biome = _biomes[i];
                    allBiomeWeights.Add(biome.GetWeights(position, resolution, spread, length));
                }
            }

            // Choose biome to display
            int[,] biomeMap = new int[resolution, resolution];
            BlendStrategy blendStrategy = TerraConfig.Instance.Graph.GetEndNode().BlendStrategy;

            MathUtil.LoopXY(resolution, (x, y) => {
                int toShow = 0;

                switch (blendStrategy)
                {
                case BlendStrategy.RANDOM:
                    toShow = GetShownBiomeRandom(x, y, allBiomeWeights);
                    break;

                case BlendStrategy.ORDERED:
                    toShow = GetShownBiomeOrdered(x, y, allBiomeWeights);
                    break;
                }

                biomeMap[x, y] = toShow;
            });

            return(biomeMap);
        }
        /// <summary>
        /// Adds trees according to the <see cref="_biomeMap"/> in
        /// this <see cref="Tile"/>
        /// </summary>
        public IEnumerator AddTrees()
        {
            if (_biomeMap == null)
            {
                yield break;
            }

            //Collect prototypes from tree nodes
            TreeDetailNode[] allTreeNodes = _painter.Biomes
                                            .SelectMany(biome => biome.GetTreeInputs())
                                            .ToArray();
            List <TreePrototype> prototypes = new List <TreePrototype>(allTreeNodes.Length);

            foreach (TreeDetailNode treeNode in allTreeNodes)
            {
                prototypes.Add((TreePrototype)treeNode.GetDetailPrototype());
            }

            int            coroutineRes = TerraConfig.Instance.Generator.CoroutineRes;
            int            iterations   = 0;
            GenerationData conf         = TerraConfig.Instance.Generator;

            _terrain.terrainData.treePrototypes = prototypes.ToArray();
            _terrain.terrainData.RefreshPrototypes();
            _terrain.treeDistance            = conf.TreeDistance;
            _terrain.treeBillboardDistance   = conf.BillboardStart;
            _terrain.treeMaximumFullLODCount = conf.MaxMeshTrees;

            BiomeNode[] biomeNodes     = _painter.Biomes;
            int         prototypeIndex = 0;

            for (int i = 0; i < biomeNodes.Length; i++)
            {
                //Collect all trees for this biome
                BiomeNode        biome     = biomeNodes[i];
                TreeDetailNode[] treeNodes = biome.GetTreeInputs();

                if (treeNodes.Length == 0)   //A biome may contain no trees
                {
                    continue;
                }

                foreach (TreeDetailNode treeNode in treeNodes)
                {
                    //Get map of normalized "tree positions"
                    Vector2[] samples = null;
                    if (!TerraConfig.Instance.IsEditor)
                    {
                        bool           isDone = false;
                        TreeDetailNode node   = treeNode;
                        TerraConfig.Instance.Worker.Enqueue(() => samples = node.SamplePositions(_tile.Random), () => isDone = true);

                        while (!isDone)
                        {
                            yield return(null);
                        }
                    }
                    else
                    {
                        samples = treeNode.SamplePositions(_tile.Random);
                    }

                    foreach (Vector2 sample in samples)
                    {
                        int selectedBiome = _sampler.GetBiomeAtInterpolatedCoords(_biomeMap, sample.x, sample.y);

                        if (iterations > coroutineRes)
                        {
                            iterations = 0;
                            yield return(null);
                        }
                        if (selectedBiome != i)
                        {
                            continue; //Not in this biome, skip
                        }

                        //Check whether a tree can be placed here
                        float   amp    = TerraConfig.Instance.Generator.Amplitude;
                        float   height = _terrain.terrainData.GetInterpolatedHeight(sample.x, sample.y) / amp;
                        float   angle  = Vector3.Angle(Vector3.up, _terrain.terrainData.GetInterpolatedNormal(sample.x, sample.y)) / 90;
                        Vector2 world  = MathUtil.NormalToWorld(_tile.GridPosition, sample);

                        if (treeNode.ShouldPlaceAt(world.x, world.y, height, angle))
                        {
                            //Add tree to terrain
                            Vector3 treeLoc = new Vector3(sample.x, height, sample.y);

                            //Tree sample set index matches the tree prototype index (j)
                            TreeInstance tree = treeNode.GetTreeInstance(treeLoc, prototypeIndex, _tile.Random);
                            _terrain.AddTreeInstance(tree);
                        }
                    }

                    prototypeIndex++;
                }
            }
        }
        /// <summary>
        /// Adds all non-tree details to the Terrain according to the
        /// <see cref="_biomeMap"/> in this <see cref="Tile"/>. This adds
        /// grass and detail meshes.
        /// </summary>
        public IEnumerator AddDetailLayers()
        {
            BiomeNode[] biomeNodes = _painter.Biomes;
            int         res        = TerraConfig.Instance.Generator.DetailmapResolution;

            //Collect prototypes
            GrassDetailNode[] allDetailNodes = biomeNodes
                                               .SelectMany(bn => bn.GetGrassInputs())
                                               .ToArray();
            List <DetailPrototype> prototypes = new List <DetailPrototype>(allDetailNodes.Length);

            foreach (GrassDetailNode detailNode in allDetailNodes)
            {
                prototypes.Add((DetailPrototype)detailNode.GetDetailPrototype());
            }

            int            coroutineRes   = TerraConfig.Instance.Generator.CoroutineRes;
            int            iterations     = 0;
            int            prototypeIndex = 0;
            GenerationData conf           = TerraConfig.Instance.Generator;

            _terrain.terrainData.SetDetailResolution(res, 16);
            _terrain.terrainData.detailPrototypes = prototypes.ToArray();
            _terrain.detailObjectDistance         = conf.DetailDistance;
            _terrain.detailObjectDensity          = conf.DetailDensity;

            for (int i = 0; i < biomeNodes.Length; i++)
            {
                //Collect all details for this biome
                BiomeNode         biome      = biomeNodes[i];
                GrassDetailNode[] grassNodes = biome.GetGrassInputs();

                if (grassNodes.Length == 0)   //A biome may contain no grass nodes
                {
                    continue;
                }

                foreach (GrassDetailNode grassNode in grassNodes)
                {
                    int[,] layer = new int[res, res];

                    //Get map of normalized placement positions
                    Vector2[] samples = null;
                    if (!TerraConfig.Instance.IsEditor)
                    {
                        bool            isDone = false;
                        GrassDetailNode node   = grassNode;
                        TerraConfig.Instance.Worker.Enqueue(() => samples = node.SamplePositions(_tile.Random), () => isDone = true);

                        while (!isDone)
                        {
                            yield return(null);
                        }
                    }
                    else
                    {
                        samples = grassNode.SamplePositions(_tile.Random);
                    }

                    foreach (Vector2 sample in samples)
                    {
                        iterations++;

                        if (iterations > coroutineRes)
                        {
                            iterations = 0;
                            yield return(null);
                        }

                        int selectedBiome = _sampler.GetBiomeAtInterpolatedCoords(_biomeMap, sample.x, sample.y);
                        if (selectedBiome != i)
                        {
                            continue; //Not in this biome, skip
                        }

                        //Check whether an object can be placed here
                        float   amp    = TerraConfig.Instance.Generator.Amplitude;
                        float   height = _terrain.terrainData.GetInterpolatedHeight(sample.x, sample.y) / amp;
                        float   angle  = Vector3.Angle(Vector3.up, _terrain.terrainData.GetInterpolatedNormal(sample.x, sample.y)) / 90;
                        Vector2 world  = MathUtil.NormalToWorld(_tile.GridPosition, sample);

                        if (grassNode.ShouldPlaceAt(world.x, world.y, height, angle))
                        {
                            //Convert normalized x,y coordinates to positions in layer map
                            Vector2 sampleWorld = sample * res;
                            int     x           = Mathf.Clamp(Mathf.RoundToInt(sampleWorld.x), 0, res - 1);
                            int     y           = Mathf.Clamp(Mathf.RoundToInt(sampleWorld.y), 0, res - 1);

                            layer[y, x] = 1; //Display object here
                        }
                    }

                    _terrain.terrainData.SetDetailLayer(0, 0, prototypeIndex, layer);
                    prototypeIndex++;
                }
            }
        }