public static void Show(TreeNodeEditor treeNode) { EditorGUI.BeginChangeCheck(); TreeDetailNode treeDetail = treeNode.TreeDetailNode; treeDetail.Prefab = (GameObject) EditorGUILayout.ObjectField(new GUIContent("Tree"), treeDetail.Prefab, typeof(GameObject), false); Show(treeDetail, () => { treeDetail.RandomRotation = EditorGUILayout.Toggle("Random Rotation", treeDetail.RandomRotation); treeDetail.BendFactor = EditorGUILayout.FloatField("Bend Factor", treeDetail.BendFactor); }); if (EditorGUI.EndChangeCheck()) { treeNode.serializedObject.ApplyModifiedProperties(); } }
/// <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++; } } }