public static void Show(GrassNodeEditor grassNode) { EditorGUI.BeginChangeCheck(); GrassDetailNode grassDetail = grassNode.GrassDetailNode; grassDetail.RenderMode = (DetailRenderMode)EditorGUILayout.EnumPopup("Render Mode", grassDetail.RenderMode); if (grassDetail.RenderMode == DetailRenderMode.VertexLit) { grassDetail.Prefab = (GameObject) EditorGUILayout.ObjectField(new GUIContent("Prefab"), grassDetail.Prefab, typeof(GameObject), false); } else { grassDetail.Texture = (Texture2D) EditorGUILayout.ObjectField(new GUIContent("Texture"), grassDetail.Texture, typeof(Texture2D), false); } Show(grassDetail, () => { if (grassDetail.RenderMode != DetailRenderMode.VertexLit) { grassDetail.HealthyColor = EditorGUILayout.ColorField("Healthy Color", grassDetail.HealthyColor); grassDetail.DryColor = EditorGUILayout.ColorField("Dry Color", grassDetail.DryColor); } }); if (EditorGUI.EndChangeCheck()) { grassNode.serializedObject.ApplyModifiedProperties(); } }
/// <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++; } } }