private void RemoveTrees(Terrain terrain, IOnPaint editContext, bool clearSelectedOnly) { PaintTreesDetailsContext ctx = PaintTreesDetailsContext.Create(terrain, editContext.uv); for (int i = 0; i < ctx.terrains.Length; ++i) { Terrain ctxTerrain = ctx.terrains[i]; if (ctxTerrain != null) { Vector2 ctxUV = ctx.uvs[i]; float radius = 0.5f * brushSize / ctxTerrain.terrainData.size.x; int treePrototype = kInvalidTree; if (clearSelectedOnly && selectedTree != kInvalidTree) { treePrototype = PaintTreesUtils.FindTreePrototype(ctxTerrain, m_TargetTerrain, selectedTree); } if (!clearSelectedOnly || treePrototype != kInvalidTree) { TerrainPaintUtilityEditor.UpdateTerrainDataUndo(ctxTerrain.terrainData, "Terrain - Remove Trees"); ctxTerrain.RemoveTrees(ctxUV, radius, treePrototype); } } } }
private void PlaceTrees(Terrain terrain, IOnPaint editContext) { if (m_TargetTerrain == null || selectedTree == kInvalidTree || selectedTree >= m_TargetTerrain.terrainData.treePrototypes.Length) { return; } PaintTreesDetailsContext ctx = PaintTreesDetailsContext.Create(terrain, editContext.uv); int placedTreeCount = 0; int treePrototype = PaintTreesUtils.FindTreePrototype(terrain, m_TargetTerrain, selectedTree); if (treePrototype == kInvalidTree) { treePrototype = PaintTreesUtils.CopyTreePrototype(terrain, m_TargetTerrain, selectedTree); } if (PaintTreesUtils.ValidateTreePrototype(terrain, treePrototype)) { // When painting single tree // And just clicking we always place it, so you can do overlapping trees Vector3 position = new Vector3(editContext.uv.x, 0, editContext.uv.y); bool checkTreeDistance = Event.current.type == EventType.MouseDrag || brushSize > 1; if (!checkTreeDistance || TerrainInspectorUtil.CheckTreeDistance(terrain.terrainData, position, treePrototype, spacing)) { TerrainPaintUtilityEditor.UpdateTerrainDataUndo(terrain.terrainData, "Terrain - Place Trees"); PaintTreesUtils.PlaceTree(terrain, treePrototype, position, GetTreeColor(), GetTreeHeight(), lockWidthToHeight ? GetTreeHeight() : GetTreeWidth(), GetTreeRotation()); ++placedTreeCount; } } for (int i = 0; i < ctx.terrains.Length; ++i) { Terrain ctxTerrain = ctx.terrains[i]; if (ctxTerrain != null) { Vector2 ctxUV = ctx.uvs[i]; treePrototype = PaintTreesUtils.FindTreePrototype(ctxTerrain, m_TargetTerrain, selectedTree); if (treePrototype == kInvalidTree) { treePrototype = PaintTreesUtils.CopyTreePrototype(ctxTerrain, m_TargetTerrain, selectedTree); } if (PaintTreesUtils.ValidateTreePrototype(ctxTerrain, treePrototype)) { Vector3 size = TerrainInspectorUtil.GetPrototypeExtent(ctxTerrain.terrainData, treePrototype); size.y = 0; float treeCountOneAxis = brushSize / (size.magnitude * spacing * .5f); int treeCount = (int)((treeCountOneAxis * treeCountOneAxis) * .5f); treeCount = Mathf.Clamp(treeCount, 0, 100); // Plant a bunch of trees for (int j = ctxTerrain == terrain ? 1 : 0; j < treeCount && placedTreeCount < treeCount; ++j) { Vector2 randomOffset = 0.5f * Random.insideUnitCircle; randomOffset.x *= brushSize / ctxTerrain.terrainData.size.x; randomOffset.y *= brushSize / ctxTerrain.terrainData.size.z; Vector3 position = new Vector3(ctxUV.x + randomOffset.x, 0, ctxUV.y + randomOffset.y); if (position.x >= 0 && position.x <= 1 && position.z >= 0 && position.z <= 1 && TerrainInspectorUtil.CheckTreeDistance(ctxTerrain.terrainData, position, treePrototype, spacing * .5f)) { TerrainPaintUtilityEditor.UpdateTerrainDataUndo(ctxTerrain.terrainData, "Terrain - Place Trees"); PaintTreesUtils.PlaceTree(ctxTerrain, treePrototype, position, GetTreeColor(), GetTreeHeight(), lockWidthToHeight ? GetTreeHeight() : GetTreeWidth(), GetTreeRotation()); ++placedTreeCount; } } } } } }