【问题标题】:Fill polygon in unity 3d在统一 3d 中填充多边形
【发布时间】:2014-09-16 02:52:17
【问题描述】:

我在统一 2d 中绘制手册时遇到了一些问题。 我使用列表向量来绘制多边形,但我无法填充它。 我还阅读了本教程:http://forum.unity3d.com/threads/draw-polygon.54092/ 但似乎我需要将多边形转换为三角形。(因为我的多边形很复杂,所以转换为三角形很难。我需要使用一些算法,比如剪耳......)。

请帮我一个简单的方法来填充它。 (我认为统一是游戏引擎的顶级,然后有一些方法可以做到最简单)。

非常感谢。

【问题讨论】:

    标签: unity3d unityscript


    【解决方案1】:

    您被困在转换为网格以使填充工作... GPU(着色器)只能填充三角形的内部空间...如果您使用封闭的凸多边形,这相当容易。具有凹面部分的多边形将需要更复杂的算法才能转换为网格,但您似乎已经对该主题进行了一些研究(您提到了剪耳)。

    祝你好运将你的多边形列表实现为三角形算法:)

    【讨论】:

    • 谢谢。在 java 核心或 C# 核心中,我可以轻松填充多边形:|。你知道为什么unity不支持这个功能吗?
    • 它不是统一的——它是一个 3D 显卡,GPU 唯一一次扫描显示区域的像素是在处理三角形时......顶点着色器使用世界/从对象坐标转换为屏幕坐标的视图/投影矩阵数据,如果生成的坐标通过视口的剪切测试,则为三角形内的每个像素调用像素着色器...颜色、UV 和法线通过顶点数据在传递给像素着色器之前被混合/插值。
    【解决方案2】:

    我可以提供Poisson-Disc algorithm remodel UniformPoissonDiskSampler.cs 之类的:

    using System;
    using System.Collections.Generic;
    using UnityEngine;
    
    namespace AwesomeNamespace
    {
        public static class UniformPoissonDiskSampler
        {
            public const int DefaultPointsPerIteration = 30;
    
            static readonly float SquareRootTwo = (float)Math.Sqrt(2);
    
            struct Settings
            {
                public UnityEngine.Vector2 TopLeft, LowerRight, Center;
                public UnityEngine.Vector2 Dimensions;
                public float? RejectionSqDistance;
                public float MinimumDistance;
                public float CellSize;
                public int GridWidth, GridHeight;
            }
    
            struct State
            {
                public UnityEngine.Vector2?[,] Grid;
                public List<UnityEngine.Vector2> ActivePoints, Points;
            }
    
            public static List<UnityEngine.Vector2> SampleCircle(UnityEngine.Vector2 center, float radius, float minimumDistance)
            {
                return SampleCircle(center, radius, minimumDistance, DefaultPointsPerIteration);
            }
            public static List<UnityEngine.Vector2> SampleCircle(UnityEngine.Vector2 center, float radius, float minimumDistance, int pointsPerIteration)
            {
                return Sample(center - new UnityEngine.Vector2(radius, radius), center + new UnityEngine.Vector2(radius, radius), radius, minimumDistance, pointsPerIteration, null);
            }
    
            public static List<UnityEngine.Vector2> SampleRectangle(UnityEngine.Vector2 topLeft, UnityEngine.Vector2 lowerRight, float minimumDistance)
            {
                return SampleRectangle(topLeft, lowerRight, minimumDistance, DefaultPointsPerIteration);
            }
            public static List<UnityEngine.Vector2> SampleRectangle(UnityEngine.Vector2 topLeft, UnityEngine.Vector2 lowerRight, float minimumDistance, int pointsPerIteration)
            {
                return Sample(topLeft, lowerRight, null, minimumDistance, pointsPerIteration, null);
            }
    
            public static List<UnityEngine.Vector2> SamplePolygon(UnityEditor.Experimental.TerrainAPI.Processing.InMetric metric, float minimumDistance)
            {
                return Sample(null, null, null, minimumDistance, DefaultPointsPerIteration, metric);
            }
    
            static List<UnityEngine.Vector2> Sample(UnityEngine.Vector2? topLeft, UnityEngine.Vector2? lowerRight, float? rejectionDistance, float minimumDistance, int pointsPerIteration, UnityEditor.Experimental.TerrainAPI.Processing.InMetric metric = null)
            {
                if (!topLeft.HasValue && !lowerRight.HasValue && metric != null)
                {
                    topLeft = new Vector2(metric.minpointx, metric.minpointz);
                    lowerRight = new Vector2(metric.maxpointx, metric.maxpointz);
                }
                var settings = new Settings
                {
                    TopLeft = (Vector2)topLeft,
                    LowerRight = (Vector2)lowerRight,
                    Dimensions = (Vector2)lowerRight - (Vector2)topLeft,
                    Center = ((Vector2)topLeft + (Vector2)lowerRight) / 2,
                    CellSize = minimumDistance / SquareRootTwo,
                    MinimumDistance = minimumDistance,
                    RejectionSqDistance = rejectionDistance == null ? null : rejectionDistance * rejectionDistance
                };
                settings.GridWidth = (int)(settings.Dimensions.x / settings.CellSize) + 1;
                settings.GridHeight = (int)(settings.Dimensions.y / settings.CellSize) + 1;
                // Debug.Log("settings.GridWidth"+settings.GridWidth+"settings.GridHeight"+settings.GridHeight);
                var state = new State
                {
                    Grid = new UnityEngine.Vector2?[settings.GridWidth, settings.GridHeight],
                    ActivePoints = new List<UnityEngine.Vector2>(),
                    Points = new List<UnityEngine.Vector2>()
                };
    
                AddFirstPoint(ref settings, ref state, (metric == null) ? null : metric);
    
                while (state.ActivePoints.Count != 0)
                {
                    var listIndex = RandomHelper.Random.Next(state.ActivePoints.Count);
    
                    var point = state.ActivePoints[listIndex];
                    var found = false;
    
                    for (var k = 0; k < pointsPerIteration; k++)
                        found |= AddNextPoint(point, ref settings, ref state, (metric == null) ? null : metric);
    
                    if (!found)
                        state.ActivePoints.RemoveAt(listIndex);
                }
    
                return state.Points;
            }
    
            static void AddFirstPoint(ref Settings settings,
                                        ref State state,
                                        UnityEditor.Experimental.TerrainAPI.Processing.InMetric metric = null)
            {
                var added = false;
                while (!added)
                {
                    var d = RandomHelper.Random.NextDouble();
                    var xr = settings.TopLeft.x + settings.Dimensions.x * d;
    
                    d = RandomHelper.Random.NextDouble();
                    var yr = settings.TopLeft.y + settings.Dimensions.y * d;
    
                    var p = new UnityEngine.Vector2((float)xr, (float)yr);
                    if (settings.RejectionSqDistance != null && DistanceSquared(settings.Center, p) > settings.RejectionSqDistance)
                        continue;
                    added = true;
    
                    if (UnityEditor.Experimental.TerrainAPI.Processing.figures_Included(p.x, p.y, metric.metricIn, metric.count) == true)
                    {
                        var index = Denormalize(p, settings.TopLeft, settings.CellSize);
    
                        state.Grid[(int)index.x, (int)index.y] = p;
    
                        state.ActivePoints.Add(p);
                        state.Points.Add(p);
                    }
                    else
                    {
                        AddFirstPoint(ref settings, ref state, metric);
                    }
                }
            }
            static float DistanceSquared(Vector2 A, Vector2 B)
            {
                return (float)Math.Pow(Math.Sqrt(Math.Pow((A.x - B.x), 2) + Math.Pow((A.y - B.y), 2)), 2);
            }
    
            static bool AddNextPoint(UnityEngine.Vector2 point,
                                    ref Settings settings,
                                    ref State state,
                                    UnityEditor.Experimental.TerrainAPI.Processing.InMetric metric = null)
            {
                var found = false;
                var q = GenerateRandomAround(point, settings.MinimumDistance);
                if (metric != null)
                {
                    if (UnityEditor.Experimental.TerrainAPI.Processing.figures_Included(q.x, q.y, metric.metricIn, metric.count) == true &&
                        q.x >= settings.TopLeft.x && q.x < settings.LowerRight.x &&
                        q.y > settings.TopLeft.y && q.y < settings.LowerRight.y &&
                        (settings.RejectionSqDistance == null || DistanceSquared(settings.Center, q) <= settings.RejectionSqDistance))
                    {
                        var qIndex = Denormalize(q, settings.TopLeft, settings.CellSize);
                        var tooClose = false;
    
                        for (var i = (int)Math.Max(0, qIndex.x - 2); i < Math.Min(settings.GridWidth, qIndex.x + 3) && !tooClose; i++)
                            for (var j = (int)Math.Max(0, qIndex.y - 2); j < Math.Min(settings.GridHeight, qIndex.y + 3) && !tooClose; j++)
                                if (state.Grid[i, j].HasValue && Vector2.Distance(state.Grid[i, j].Value, q) < settings.MinimumDistance)
                                    tooClose = true;
    
                        if (!tooClose)
                        {
                            found = true;
                            state.ActivePoints.Add(q);
                            state.Points.Add(q);
                            state.Grid[(int)qIndex.x, (int)qIndex.y] = q;
                        }
                    }
                }
                else
                {
                    if (q.x >= settings.TopLeft.x && q.x < settings.LowerRight.x &&
                        q.y > settings.TopLeft.y && q.y < settings.LowerRight.y &&
                        (settings.RejectionSqDistance == null || DistanceSquared(settings.Center, q) <= settings.RejectionSqDistance))
                    {
                        var qIndex = Denormalize(q, settings.TopLeft, settings.CellSize);
                        var tooClose = false;
    
                        for (var i = (int)Math.Max(0, qIndex.x - 2); i < Math.Min(settings.GridWidth, qIndex.x + 3) && !tooClose; i++)
                            for (var j = (int)Math.Max(0, qIndex.y - 2); j < Math.Min(settings.GridHeight, qIndex.y + 3) && !tooClose; j++)
                                if (state.Grid[i, j].HasValue && Vector2.Distance(state.Grid[i, j].Value, q) < settings.MinimumDistance)
                                    tooClose = true;
    
                        if (!tooClose)
                        {
                            found = true;
                            state.ActivePoints.Add(q);
                            state.Points.Add(q);
                            state.Grid[(int)qIndex.x, (int)qIndex.y] = q;
                        }
                    }
                }
                return found;
            }
    
            static Vector2 GenerateRandomAround(Vector2 center, float minimumDistance)
            {
                var d = RandomHelper.Random.NextDouble();
                var radius = minimumDistance + minimumDistance * d;
    
                d = RandomHelper.Random.NextDouble();
                var angle = MathHelper.TwoPi * d;
    
                var newX = radius * Math.Sin(angle);
                var newY = radius * Math.Cos(angle);
    
                return new Vector2((float)(center.x + newX), (float)(center.y + newY));
            }
    
            static Vector2 Denormalize(Vector2 point, Vector2 origin, double cellSize)
            {
                return new Vector2((int)((point.x - origin.x) / cellSize), (int)((point.y - origin.y) / cellSize));
            }
        }
    
        public static class RandomHelper
        {
            public static readonly System.Random Random = new System.Random();
        }
    
        public static class MathHelper
        {
            public const float Pi = (float)Math.PI;
            public const float HalfPi = (float)(Math.PI / 2);
            public const float TwoPi = (float)(Math.PI * 2);
        }
    }
    

    数字_包括:

    public static bool figures_Included(float xPoint, float yPoint, float[] metricIn, int n)
    {
        float X = xPoint;
        float Y = yPoint;
        int npol = n;
        int i, j;
        bool res = false;
        float[] XYpol = metricIn;
        for (i = 0, j = npol - 1; i < npol; j = i++)
        {
            if ((((XYpol[i * 2 + 1] <= Y) && (Y < XYpol[j * 2 + 1])) ||
                    ((XYpol[j * 2 + 1] <= Y) && (Y < XYpol[i * 2 + 1]))) &&
                (X < (XYpol[j * 2] - XYpol[i * 2]) * (Y - XYpol[i * 2 + 1]) /
                    (XYpol[j * 2 + 1] - XYpol[i * 2 + 1]) + XYpol[i * 2]))
            {
                res = !res;
            }
        }
        return res;
    }
    

    和 InMetric :

        static public InMetric getmetricIn(List<Vector3> drawcoord, bool editingmode = true)
        {
            float mapoffsetx = 0;
            float mapoffsety = 0;
            if (editingmode == true)
            {
                mapoffsetx = Main.mainSatting.mapoffsetx;
                mapoffsety = Main.mainSatting.mapoffsetz;
            }
            else
            {
                mapoffsetx = 0;
                mapoffsety = 0;
            }
    
            if (drawcoord[0].x != drawcoord[drawcoord.Count - 1].x && drawcoord[0].z != drawcoord[drawcoord.Count - 1].z) //если линия, ограничивающая полигон не замкнута
                drawcoord.Add(drawcoord[0]); //добавляем замыкающую вершину
    
            float[] metricIn = new float[drawcoord.Count * 2]; //дополнительный массив вершин, пересчитанный для проверки нахождения точки внутри полигона            
            drawcoord[0] = new Vector3(drawcoord[0].x - mapoffsetx, 0, drawcoord[0].z - mapoffsety); //расчет 0-ой вершины в единицах Unity (метры)
            metricIn[0] = drawcoord[0].x;
            metricIn[1] = drawcoord[0].z; //запись 0-ой вершины в дополнительный массив. x-координаты под четными индексами, Z-координаты под нечетными индексами
            float minpointx = drawcoord[0].x; //минимальная x-координата
            float maxpointx = drawcoord[0].x; //максимальная х-координата
            float minpointz = drawcoord[0].z; //минимальная y-координата
            float maxpointz = drawcoord[0].z; //максимальная у-координата
    
            /*Цикл обработки вершин. начинается 1-ой вершины*/
            for (int i = 1; i < drawcoord.Count; i++)
            {
                drawcoord[i] = new Vector3(drawcoord[i].x - mapoffsetx, 0, drawcoord[i].z - mapoffsety); //расчет i-ой вершины в единицах Unity (метры)
                metricIn[i * 2] = drawcoord[i].x; //запись i-ой вершины в дополнительный массив. x-координаты под четными индексами
                metricIn[i * 2 + 1] = drawcoord[i].z; //запись i-ой вершины в дополнительный массив. z-координаты под нечетными индексами
                /*поиск максимальных и минимальных координат по x и максимальных и минимальных координат по z*/
                if (drawcoord[i].x < minpointx)
                    minpointx = drawcoord[i].x;
                if (drawcoord[i].x > maxpointx)
                    maxpointx = drawcoord[i].x;
                if (drawcoord[i].z < minpointz)
                    minpointz = drawcoord[i].z;
                if (drawcoord[i].z > maxpointz)
                    maxpointz = drawcoord[i].z;
            }
            InMetric metric = new InMetric();
            metric.metricIn = metricIn;
            metric.minpointx = minpointx;
            metric.maxpointx = maxpointx;
            metric.minpointz = minpointz;
            metric.maxpointz = maxpointz;
            metric.drawcoord = drawcoord;
            metric.count = drawcoord.Count;
            return metric;
        }
    
        public class InMetric
        {
            public float minpointx { get; set; }
            public float maxpointx { get; set; }
            public float minpointz { get; set; }
            public float maxpointz { get; set; }
            public float[] metricIn { get; set; }
            public List<Vector3> drawcoord { get; set; }
            public int count { get; set; }
        }
    

    【讨论】:

      猜你喜欢
      • 2023-02-17
      • 2016-02-10
      • 1970-01-01
      • 2012-03-02
      • 1970-01-01
      • 2014-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多