Exemple #1
0
        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);
                    }
                }
            }
        }
Exemple #2
0
        public static PaintTreesDetailsContext Create(Terrain terrain, Vector2 uv)
        {
            s_Nbrs[0] = terrain.leftNeighbor;
            s_Nbrs[1] = terrain.leftNeighbor ? terrain.leftNeighbor.topNeighbor : (terrain.topNeighbor ? terrain.topNeighbor.leftNeighbor : null);
            s_Nbrs[2] = terrain.topNeighbor;
            s_Nbrs[3] = terrain.rightNeighbor ? terrain.rightNeighbor.topNeighbor : (terrain.topNeighbor ? terrain.topNeighbor.rightNeighbor : null);
            s_Nbrs[4] = terrain.rightNeighbor;
            s_Nbrs[5] = terrain.rightNeighbor ? terrain.rightNeighbor.bottomNeighbor : (terrain.bottomNeighbor ? terrain.bottomNeighbor.rightNeighbor : null);
            s_Nbrs[6] = terrain.bottomNeighbor;
            s_Nbrs[7] = terrain.leftNeighbor ? terrain.leftNeighbor.bottomNeighbor : (terrain.bottomNeighbor ? terrain.bottomNeighbor.leftNeighbor : null);

            s_Uvs[0] = new Vector2(uv.x + 1.0f, uv.y);
            s_Uvs[1] = new Vector2(uv.x + 1.0f, uv.y - 1.0f);
            s_Uvs[2] = new Vector2(uv.x, uv.y - 1.0f);
            s_Uvs[3] = new Vector2(uv.x - 1.0f, uv.y - 1.0f);
            s_Uvs[4] = new Vector2(uv.x - 1.0f, uv.y);
            s_Uvs[5] = new Vector2(uv.x - 1.0f, uv.y + 1.0f);
            s_Uvs[6] = new Vector2(uv.x, uv.y + 1.0f);
            s_Uvs[7] = new Vector2(uv.x + 1.0f, uv.y + 1.0f);

            PaintTreesDetailsContext ctx = new PaintTreesDetailsContext();

            ctx.terrains[0] = terrain;
            ctx.uvs[0]      = uv;

            bool left   = uv.x < 0.5f;
            bool right  = !left;
            bool bottom = uv.y < 0.5f;
            bool top    = !bottom;

            int t = 0;

            if (right && top)
            {
                t = 2;
            }
            else if (right && bottom)
            {
                t = 4;
            }
            else if (left && bottom)
            {
                t = 6;
            }

            for (int i = 1; i < 4; ++i, t = (t + 1) % 8)
            {
                ctx.terrains[i] = s_Nbrs[t];
                ctx.uvs[i]      = s_Uvs[t];
            }

            return(ctx);
        }
Exemple #3
0
        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;
                            }
                        }
                    }
                }
            }
        }
        public override bool OnPaint(Terrain terrain, IOnPaint editContext)
        {
            if (m_TargetTerrain == null ||
                selectedDetail == kInvalidDetail ||
                selectedDetail >= m_TargetTerrain.terrainData.detailPrototypes.Length)
            {
                return(false);
            }

            Texture2D brush = editContext.brushTexture as Texture2D;

            if (brush == null)
            {
                Debug.LogError("Brush texture is not a Texture2D.");
                return(false);
            }

            if (m_BrushRep == null)
            {
                m_BrushRep = new BrushRep();
            }

            PaintTreesDetailsContext ctx = PaintTreesDetailsContext.Create(terrain, editContext.uv);

            for (int t = 0; t < ctx.terrains.Length; ++t)
            {
                Terrain ctxTerrain = ctx.terrains[t];
                if (ctxTerrain != null)
                {
                    int detailPrototype = PaintDetailsUtils.FindDetailPrototype(ctxTerrain, m_TargetTerrain, selectedDetail);
                    if (detailPrototype == kInvalidDetail)
                    {
                        detailPrototype = PaintDetailsUtils.CopyDetailPrototype(ctxTerrain, m_TargetTerrain, selectedDetail);
                    }

                    TerrainData terrainData = ctxTerrain.terrainData;

                    TerrainPaintUtilityEditor.UpdateTerrainDataUndo(terrainData, "Terrain - Detail Edit");

                    int size = (int)Mathf.Max(1.0f, editContext.brushSize * ((float)terrainData.detailResolution / terrainData.size.x));

                    m_BrushRep.CreateFromBrush(brush, size);

                    Vector2 ctxUV = ctx.uvs[t];

                    int xCenter = Mathf.FloorToInt(ctxUV.x * terrainData.detailWidth);
                    int yCenter = Mathf.FloorToInt(ctxUV.y * terrainData.detailHeight);

                    int intRadius   = Mathf.RoundToInt(size) / 2;
                    int intFraction = Mathf.RoundToInt(size) % 2;

                    int xmin = xCenter - intRadius;
                    int ymin = yCenter - intRadius;

                    int xmax = xCenter + intRadius + intFraction;
                    int ymax = yCenter + intRadius + intFraction;

                    if (xmin >= terrainData.detailWidth || ymin >= terrainData.detailHeight || xmax <= 0 || ymax <= 0)
                    {
                        continue;
                    }

                    xmin = Mathf.Clamp(xmin, 0, terrainData.detailWidth - 1);
                    ymin = Mathf.Clamp(ymin, 0, terrainData.detailHeight - 1);

                    xmax = Mathf.Clamp(xmax, 0, terrainData.detailWidth);
                    ymax = Mathf.Clamp(ymax, 0, terrainData.detailHeight);

                    int width  = xmax - xmin;
                    int height = ymax - ymin;

                    float targetStrength = detailStrength;
                    if (Event.current.shift || Event.current.control)
                    {
                        targetStrength = -targetStrength;
                    }

                    int[] layers = { detailPrototype };
                    if (targetStrength < 0.0F && !Event.current.control)
                    {
                        layers = terrainData.GetSupportedLayers(xmin, ymin, width, height);
                    }

                    for (int i = 0; i < layers.Length; i++)
                    {
                        int[,] alphamap = terrainData.GetDetailLayer(xmin, ymin, width, height, layers[i]);

                        for (int y = 0; y < height; y++)
                        {
                            for (int x = 0; x < width; x++)
                            {
                                int   xBrushOffset = (xmin + x) - (xCenter - intRadius + intFraction);
                                int   yBrushOffset = (ymin + y) - (yCenter - intRadius + intFraction);
                                float opa          = detailOpacity * m_BrushRep.GetStrengthInt(xBrushOffset, yBrushOffset);

                                float targetValue = Mathf.Lerp(alphamap[y, x], targetStrength, opa);
                                alphamap[y, x] = Mathf.RoundToInt(targetValue - .5f + Random.value);
                            }
                        }

                        terrainData.SetDetailLayer(xmin, ymin, layers[i], alphamap);
                    }
                }
            }

            return(false);
        }