Unity引擎绘制多边形属性图

news2024/9/20 22:13:52

  大家好,我是阿赵
  在制作游戏的时候,经常会遇到需要绘制多边形属性图的需求,比如这种效果:
可以根据需要的属性的数量变化多边形的边数,然后每一个顶点从中心点开始到多边形的顶点的长度代表了该属性的强度,然后多个属性的顶点连接起来形成一个多边形图形。
在这里插入图片描述

  这里介绍一下我自己的做法。

一、 需求拆分:

  需要做到上图的效果,可以拆分成几个部分

1、底板

在这里插入图片描述

  这一个图片,当然也可以用程序计算生成出来,但我个人觉得,这个底图除了会出现边数不一样以外,其他的样式差不多是固定的,而程序生成的图片可能没有美术做的底图好看,所以我是比较建议直接出图使用。如果需要换边数,可以直接换图

2、属性多边形

在这里插入图片描述

  这个形状是会根据属性的变化而变化的,所以是不能直接用美术出图的,必现要动态生成。既然是动态的绘制多边形,所以用到的知识点肯定是动态计算顶点和索引,构成Mesh网格来显示了。由于这个形状基本上都是用于UI的,所以不能直接用Mesh和MeshRenderer来渲染,我这里选择的是MaskableGraphic。
  MaskableGraphic可以直接在UI上通过顶点和索引绘制多边形。所以我们只需要固定一个中心点坐标,然后通过设置一些参数,比如:

  1. 边数
  2. 最大半径
  3. 颜色
  4. 属性的最大最小值
  5. 每一个边的当前值
  6. 等等
      然后根据参数计算几个顶点的坐标,再通过(中心点、当前顶点、下一个顶点)作为一个三角形的索引,就可以逐个三角形绘制出来了。最后指定颜色,半透明也是在颜色里面指定。

3、多边形描边

在这里插入图片描述

  这个的原理和上一步一样,都是使用MaskableGraphic来自定义顶点和索引绘制。
  可以设置的参数和上面绘制多边形基本一致,只需要加多:
1、 描边的厚度
2、 描边的颜色
  绘制描边的算法比绘制多边形本身复杂一些,我一开始想得简单,直接把多边形的半径扩大,然后往回减去描边厚度,来得到描边的一个角上的两个顶点。不过那样做是不行的,将会导致描边的线段不是均匀的厚度,到了尖角的地方会变得很厚。
  后来我还是老老实实的对多边形的每条边进行往内平移,并且求出每条平移后的线和下一条线的延伸线的交点,作为描边的第二层的顶点。然后如果有描边的情况下,多边形的顶点也是使用了描边的第二层的顶点,两者就完全接得上了。
  由于这个原因,所以需要求线段平移和交点的方法。

4、在编辑器调整效果

在这里插入图片描述

  最后,综合以上所述,在编辑器里面可以暴露这些参数,可以在做UI的时候就看到效果,并且用代码去设置。这里还有一个angle角度的变量,是用于旋转多边形的,因为有时候我们的需求多边形不一定是正上方有个顶点,可以是旋转一定角度。
  有一个isChange的变量,下面的代码里面会说到,只有在修改的情况下才会重新计算顶点。所以如果在编辑器的非运行状态下,可以手点一下激活,这样在调整参数的时候,画面就会立刻刷新变化。

二、 代码实现

1、 MaskableGraphic的基础代码

  使用MaskableGraphic之前介绍过,基础用法很简单,类继承MaskableGraphic,然后重写OnPopulateMesh方法,在里面输入顶点和索引列表。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
    [RequireComponent(typeof(CanvasRenderer))]
    [RequireComponent(typeof(RectTransform))]
public class UIPolyOutlineEx : MaskableGraphic
{
        private List<UIVertex> vertexList;
    private List<int> indexList;
        protected override void OnPopulateMesh(VertexHelper vh)
        {
            vh.Clear();           
            if (vertexList != null && vertexList.Count > 0&&indexList!= null && indexList.Count > 0)
            {
                vh.AddUIVertexStream(vertexList, indexList);
            }
      }
}

2、 设置变量

  根据刚才的分析,设置了变量

public int sideCount = 0;
public float radius = 100;
public float minVal = 0.1f;
public float maxVal = 1;
public float edgeLen = 10;
public float[] sideValueArr;
public float angle = 0;
public Color insideColor = Color.green;
public Color edgeColor = Color.black;

public bool isChange = false;
private List<UIVertex> outlinePoints;
private List<UIVertex> insidePoints;
private List<UIVertex> vertexList;
private List<int> indexList;

3、 计算顶点

  需要根据参数,求出内部多边形和外部描边的顶点,中间还有一个平移线段的顶点信息,所以需要三个数组来计算。计算完之后,就把他们保存起来。这里我是直接保存成UIVertex的,由于描边和内部颜色不一样,所以UIVertex里面也记录了颜色,所以描边的顶点列表和内部的顶点列表是完全分开的,就算看着是同一个点,其实也是两边都保存。

    private void CreatePoints()
    {
        List<Vector2> outsidePoints = new List<Vector2>();
        List<Vector2> outsidePoints2 = new List<Vector2>();
        List<Vector2> moveLinePoints = new List<Vector2>();
        outlinePoints = new List<UIVertex>();
        insidePoints = new List<UIVertex>();
        if (sideCount < 3)
        {
            return;
        }

        float offsetRate = edgeLen / radius;
        Rect rect = gameObject.GetComponent<RectTransform>().rect;
        UIVertex vex0 = UIVertex.simpleVert;
        vex0.position = new Vector3(rect.center.x, rect.center.y, 0);
        Vector3 uv0 = new Vector2(0.5f, 0.5f);
        vex0.uv0 = uv0;
        vex0.color = insideColor;
        insidePoints.Add(vex0);
        for (int i = 0; i < sideCount; i++)
        {
            float val = 0;
            if (sideValueArr != null && i < sideValueArr.Length)
            {
                val = sideValueArr[i];
            }
            else
            {
                val = 0;
            }
            float ang = 360f / sideCount * i + angle;
            ang = ang * Mathf.Deg2Rad;
            val = Mathf.Clamp(val, minVal, maxVal);
            float x = val * Mathf.Sin(ang);
            float y = val * Mathf.Cos(ang);
            outsidePoints.Add(new Vector2(x, y));
        }
        if (edgeLen <= 0)
        {
            for (int i = 0; i < outsidePoints.Count; i++)
            {
                UIVertex vex = UIVertex.simpleVert;
                vex.position = new Vector3(rect.center.x + outsidePoints[i].x * radius, rect.center.y + outsidePoints[i].y * radius, 0);
                Vector2 uv = new Vector2(outsidePoints[i].x, outsidePoints[i].y);
                uv *= 0.5f;
                uv += new Vector2(0.5f, 0.5f);
                vex.uv0 = uv;
                vex.color = insideColor;
                insidePoints.Add(vex);
            }
        }
        else
        {
            for (int i = 0; i < outsidePoints.Count; i++)
            {
                Vector2 p0 = Vector2.zero;
                Vector2 p1 = outsidePoints[i];
                Vector2 p2;

                if (i < outsidePoints.Count - 1)
                {
                    p2 = outsidePoints[i + 1];
                }
                else
                {
                    p2 = outsidePoints[0];
                }

                Vector2 foot = GetPointToLine(p0, p1, p2);
                Vector2 dir = p0 - foot;
                dir.Normalize();
                Vector2 p3 = p1 + dir * offsetRate;
                Vector2 p4 = p2 + dir * offsetRate;
                moveLinePoints.Add(p3);
                moveLinePoints.Add(p4);
            }

            for (int i = 0; i < outsidePoints.Count; i++)
            {
                int ind1 = i * 2;
                int ind2 = i * 2 + 1;
                int ind3 = i * 2 - 2;
                int ind4 = i * 2 - 1;
                if (i == 0)
                {
                    ind3 = moveLinePoints.Count - 2;
                    ind4 = moveLinePoints.Count - 1;
                }
                Vector2 crossPoint = GetLineCrossPoint(moveLinePoints[ind1], moveLinePoints[ind2], moveLinePoints[ind3], moveLinePoints[ind4]);
                print(moveLinePoints[ind1] * radius + "," + moveLinePoints[ind2] * radius + "|" + moveLinePoints[ind3] * radius + "," + moveLinePoints[ind4] * radius + "||" + crossPoint * radius);
                outsidePoints2.Add(crossPoint);
            }

            for (int i = 0; i < outsidePoints.Count; i++)
            {

                UIVertex vex = UIVertex.simpleVert;
                vex.position = new Vector3(rect.center.x + outsidePoints2[i].x * radius, rect.center.y + outsidePoints2[i].y * radius, 0);
                Vector2 uv = new Vector2(outsidePoints2[i].x, outsidePoints2[i].y);
                uv *= 0.5f;
                uv += new Vector2(0.5f, 0.5f);
                vex.uv0 = uv;
                vex.color = insideColor;
                insidePoints.Add(vex);

                vex = UIVertex.simpleVert;
                vex.position = new Vector3(rect.center.x + outsidePoints[i].x * radius, rect.center.y + outsidePoints[i].y * radius, 0);
                uv = new Vector2(outsidePoints[i].x, outsidePoints[i].y);
                uv *= 0.5f;
                uv += new Vector2(0.5f, 0.5f);
                vex.uv0 = uv;
                vex.color = edgeColor;
                outlinePoints.Add(vex);

                vex = UIVertex.simpleVert;
                vex.position = new Vector3(rect.center.x + outsidePoints2[i].x * radius, rect.center.y + outsidePoints2[i].y * radius, 0);
                uv = new Vector2(outsidePoints2[i].x, outsidePoints2[i].y);
                uv *= 0.5f;
                uv += new Vector2(0.5f, 0.5f);
                vex.uv0 = uv;
                vex.color = edgeColor;
                outlinePoints.Add(vex);
            }

        }
    }

    private Vector2 GetPointToLine(Vector2 p0, Vector2 p1, Vector2 p2)
    {
        Vector2 lineDir = p1 - p2;
        lineDir.Normalize();
        float x0 = p0.x;
        float y0 = p0.y;
        float x1 = p1.x;// -lineDir.x*10;
        float y1 = p1.y;// - lineDir.y * 10;
        float x2 = p2.x;// + lineDir.x * 10;
        float y2 = p2.y;// + lineDir.x * 10;
        if ((x1 == x0 && y1 == y0) || (x2 == x0 && y2 == y0))
        {
            return new Vector2(x0, y0);//点和线段一边重合
        }

        float k = 1;
        if (x1 != x2)
        {
            k = (y2 - y1) / (x2 - x1);
        }
        float a = k;
        float b = -1;
        float c = y1 - k * x1;
        float d = Mathf.Abs(a * x0 + b * y0 + c) / Mathf.Sqrt(a * a + b * b);
        float px = (b * b * x0 - a * b * y0 - a * c) / (a * a + b * b);
        float py = (a * a * y0 - a * b * x0 - b * c) / (a * a + b * b);
        return new Vector2(px, py);
    }

    private Vector2 GetLineCrossPoint(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4)
    {
        Vector2 dir1 = (p1 - p2).normalized;
        p1 += dir1;
        p2 -= dir1;
        Vector2 dir2 = (p3 - p4).normalized;
        p3 += dir2;
        p4 -= dir2;
        Vector2 bx = p4 - p3;
        float d1 = Mathf.Abs(CrossMulVec(bx, p1 - p3));
        float d2 = Mathf.Abs(CrossMulVec(bx, p2 - p3));
        float dx = d1 + d2;
        if (dx == 0)
        {
            return p1;
        }
        float t = d1 / dx;
        Vector2 temp = (p2 - p1) * t;
        return p1 + temp;
    }

    private float CrossMulVec(Vector2 p1, Vector2 p2)
    {
        return p1.x * p2.y - p2.x * p1.y;
}

4、 求构成多边形的点和索引

  由于绘制的时候,需要把描边和内部的所有顶点和索引合并在一起,所以这里需要再计算一次,把两个列表合并。

        private void CreateMeshParam()
        {
            vertexList = new List<UIVertex>();
            indexList = new List<int>();
            int insidePointCount = 0;
            if (insidePoints != null && insidePoints.Count > 0)
            {
                insidePointCount = insidePoints.Count;
                for (int i = 0; i < insidePoints.Count; i++)
                {
                    vertexList.Add(insidePoints[i]);
                }
                List<int> tempList = new List<int>();
                if (sideCount > 2)
                {
                    int ind3 = 0;
                    for (int i = 0; i < sideCount; i++)
                    {
                        tempList.Add(0);
                        tempList.Add(i + 1);
                        ind3 = i + 2;
                        if (ind3 > sideCount)
                        {
                            ind3 = 1;
                        }
                        tempList.Add(ind3);
                    }
                }
                indexList = tempList;
            }
            if (outlinePoints != null && outlinePoints.Count > 0)
            {
                for (int i = 0; i < outlinePoints.Count; i++)
                {
                    vertexList.Add(outlinePoints[i]);
                }
                for (int i = 0; i < sideCount; i++)
                {
                    int ind1 = i * 2;
                    int ind2 = i * 2 + 2;
                    int ind3 = i * 2 + 1;
                    int ind4 = i * 2 + 3;
                    if (i == sideCount - 1)
                    {
                        ind2 = 0;
                        ind4 = 1;
                    }
                    indexList.Add(ind1 + insidePointCount);
                    indexList.Add(ind2 + insidePointCount);
                    indexList.Add(ind3 + insidePointCount);
                    indexList.Add(ind3 + insidePointCount);
                    indexList.Add(ind2 + insidePointCount);
                    indexList.Add(ind4 + insidePointCount);
                }
            }
  }

5、 各种属性的GetSet

  在运行的时候,我们不会希望每一帧都需要重复去计算多边形的顶点和索引,希望只有参数变化的时候才重新计算。所以那些可以改变的参数,应该都做成GetSet方法,然后在Set方法的时候,把一个isChange的标记设置为true。那么当isChange为true的时候,才重新计算。

public void InitData(int sideCount,float r,float edge)
{
    SetSideCount(sideCount);
    radius = r;
    edgeLen = edge;
    isChange = true;
}
public void SetIsChange()
{
    isChange = true;
}
public void SetSideCount(int val)
{
    sideCount = val;
    float[] newArr = new float[val];
    if(sideValueArr!=null&&sideValueArr.Length>0)
    {
        for(int i = 0;i<val;i++)
        {
            if(sideValueArr.Length>val)
            {
                newArr[i] = sideValueArr[i];
            }
        }
    }
    sideValueArr = newArr;
    isChange = true;
}

public void SetValArr(float[] vals)
{
    if (sideValueArr == null)
    {
        return;
    }
    for (int i = 0; i < sideValueArr.Length; i++)
    {
        if (i < vals.Length)
        {
            sideValueArr[i] = vals[i];
        }
    }
    isChange = true;
}


public void SetOneVal(int index,float val)
{
    if(index<0)
    {
        return;
    }
    if(sideValueArr != null&&sideValueArr.Length> index)
    {
        sideValueArr[index] = val;
    }
    isChange = true;
}

public void SetOneValByLua(double index, double val)
{
    int ind = Mathf.FloorToInt((float)index);
    float value = (float)val;
    SetOneVal(ind - 1, value);
}

public void SetAngle(float ang)
{
    angle = ang;
    isChange = true;
}

public void SetRange(float min,float max)
{
    minVal = min;
    maxVal = max;
    isChange = true;
}

public void SetInsideColor(Color col)
{
    insideColor = col;
    isChange = true;
}

public void SetOutlineColor(Color col)
{
    edgeColor = col;
    isChange = true;
}


public void SetRadius(float val)
{
    radius = val;
    isChange = true;
}

  这是一个重新计算顶点和索引的方法,只有在isChange为true的时候,才会调用。

private void UpdatePoly()
{
    if (sideCount == 0)
    {
        vertexList = null;
        return;
    }
    CreatePoints();
    CreateMeshParam();
}

6、 修改OnPopulateMesh方法

  在OnPopulateMesh里面判断isChange,然后调用UpdatePoly方法。

   protected override void OnPopulateMesh(VertexHelper vh)
    {
        //base.OnPopulateMesh(vh);
        vh.Clear();
        if(isChange)
        {
            UpdatePoly();
            if(Application.isPlaying)
                isChange = false;
        }
        
        if (vertexList != null && vertexList.Count > 0)
        {
            vh.AddUIVertexStream(vertexList, indexList);
        }
    }

三、完整代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace azhao
{
    [RequireComponent(typeof(CanvasRenderer))]
    [RequireComponent(typeof(RectTransform))]
    public class UIPolyOutlineEx : MaskableGraphic
    {


        public int sideCount = 0;
        public float radius = 100;
        public float minVal = 0.1f;
        public float maxVal = 1;
        public float edgeLen = 10;
        public float[] sideValueArr;
        public float angle = 0;
        public Color insideColor = Color.green;
        public Color edgeColor = Color.black;

        public bool isChange = false;
        private List<UIVertex> outlinePoints;
        private List<UIVertex> insidePoints;
        private List<UIVertex> vertexList;
        private List<int> indexList;
        // Start is called before the first frame update
        private new IEnumerator Start()
        {
            UpdatePoly();
            yield return null;
        }

        public void InitData(int sideCount,float r,float edge)
        {
            SetSideCount(sideCount);
            radius = r;
            edgeLen = edge;
            isChange = true;
        }
        public void SetIsChange()
        {
            isChange = true;
        }
        public void SetSideCount(int val)
        {
            sideCount = val;
            float[] newArr = new float[val];
            if(sideValueArr!=null&&sideValueArr.Length>0)
            {
                for(int i = 0;i<val;i++)
                {
                    if(sideValueArr.Length>val)
                    {
                        newArr[i] = sideValueArr[i];
                    }
                }
            }
            sideValueArr = newArr;
            isChange = true;
        }

        public void SetValArr(float[] vals)
        {
            if (sideValueArr == null)
            {
                return;
            }
            for (int i = 0; i < sideValueArr.Length; i++)
            {
                if (i < vals.Length)
                {
                    sideValueArr[i] = vals[i];
                }
            }
            isChange = true;
        }


        public void SetOneVal(int index,float val)
        {
            if(index<0)
            {
                return;
            }
            if(sideValueArr != null&&sideValueArr.Length> index)
            {
                sideValueArr[index] = val;
            }
            isChange = true;
        }

        public void SetOneValByLua(double index, double val)
        {
            int ind = Mathf.FloorToInt((float)index);
            float value = (float)val;
            SetOneVal(ind - 1, value);
        }

        public void SetAngle(float ang)
        {
            angle = ang;
            isChange = true;
        }

        public void SetRange(float min,float max)
        {
            minVal = min;
            maxVal = max;
            isChange = true;
        }

        public void SetInsideColor(Color col)
        {
            insideColor = col;
            isChange = true;
        }

        public void SetOutlineColor(Color col)
        {
            edgeColor = col;
            isChange = true;
        }


        public void SetRadius(float val)
        {
            radius = val;
            isChange = true;
        }

        private void UpdatePoly()
        {
            if (sideCount == 0)
            {
                vertexList = null;
                return;
            }
            CreatePoints();
            CreateMeshParam();
        }



        private void CreatePoints()
        {
            List<Vector2> outsidePoints = new List<Vector2>();
            List<Vector2> outsidePoints2 = new List<Vector2>();
            List<Vector2> moveLinePoints = new List<Vector2>();
            outlinePoints = new List<UIVertex>();
            insidePoints = new List<UIVertex>();
            if (sideCount < 3)
            {
                return;
            }

            float offsetRate = edgeLen / radius;
            Rect rect = gameObject.GetComponent<RectTransform>().rect;
            UIVertex vex0 = UIVertex.simpleVert;
            vex0.position = new Vector3(rect.center.x, rect.center.y, 0);
            Vector3 uv0 = new Vector2(0.5f, 0.5f);
            vex0.uv0 = uv0;
            vex0.color = insideColor;
            insidePoints.Add(vex0);
            for (int i = 0; i < sideCount; i++)
            {
                float val = 0;
                if (sideValueArr != null && i < sideValueArr.Length)
                {
                    val = sideValueArr[i];
                }
                else
                {
                    val = 0;
                }
                float ang = 360f / sideCount * i + angle;
                ang = ang * Mathf.Deg2Rad;
                val = Mathf.Clamp(val, minVal, maxVal);
                float x = val * Mathf.Sin(ang);
                float y = val * Mathf.Cos(ang);
                outsidePoints.Add(new Vector2(x, y));
            }
            if (edgeLen <= 0)
            {
                for (int i = 0; i < outsidePoints.Count; i++)
                {
                    UIVertex vex = UIVertex.simpleVert;
                    vex.position = new Vector3(rect.center.x + outsidePoints[i].x * radius, rect.center.y + outsidePoints[i].y * radius, 0);
                    Vector2 uv = new Vector2(outsidePoints[i].x, outsidePoints[i].y);
                    uv *= 0.5f;
                    uv += new Vector2(0.5f, 0.5f);
                    vex.uv0 = uv;
                    vex.color = insideColor;
                    insidePoints.Add(vex);
                }
            }
            else
            {
                for (int i = 0; i < outsidePoints.Count; i++)
                {
                    Vector2 p0 = Vector2.zero;
                    Vector2 p1 = outsidePoints[i];
                    Vector2 p2;

                    if (i < outsidePoints.Count - 1)
                    {
                        p2 = outsidePoints[i + 1];
                    }
                    else
                    {
                        p2 = outsidePoints[0];
                    }

                    Vector2 foot = GetPointToLine(p0, p1, p2);
                    Vector2 dir = p0 - foot;
                    dir.Normalize();
                    Vector2 p3 = p1 + dir * offsetRate;
                    Vector2 p4 = p2 + dir * offsetRate;
                    moveLinePoints.Add(p3);
                    moveLinePoints.Add(p4);
                }

                for (int i = 0; i < outsidePoints.Count; i++)
                {
                    int ind1 = i * 2;
                    int ind2 = i * 2 + 1;
                    int ind3 = i * 2 - 2;
                    int ind4 = i * 2 - 1;
                    if (i == 0)
                    {
                        ind3 = moveLinePoints.Count - 2;
                        ind4 = moveLinePoints.Count - 1;
                    }
                    Vector2 crossPoint = GetLineCrossPoint(moveLinePoints[ind1], moveLinePoints[ind2], moveLinePoints[ind3], moveLinePoints[ind4]);
                    print(moveLinePoints[ind1] * radius + "," + moveLinePoints[ind2] * radius + "|" + moveLinePoints[ind3] * radius + "," + moveLinePoints[ind4] * radius + "||" + crossPoint * radius);
                    outsidePoints2.Add(crossPoint);
                }

                for (int i = 0; i < outsidePoints.Count; i++)
                {

                    UIVertex vex = UIVertex.simpleVert;
                    vex.position = new Vector3(rect.center.x + outsidePoints2[i].x * radius, rect.center.y + outsidePoints2[i].y * radius, 0);
                    Vector2 uv = new Vector2(outsidePoints2[i].x, outsidePoints2[i].y);
                    uv *= 0.5f;
                    uv += new Vector2(0.5f, 0.5f);
                    vex.uv0 = uv;
                    vex.color = insideColor;
                    insidePoints.Add(vex);

                    vex = UIVertex.simpleVert;
                    vex.position = new Vector3(rect.center.x + outsidePoints[i].x * radius, rect.center.y + outsidePoints[i].y * radius, 0);
                    uv = new Vector2(outsidePoints[i].x, outsidePoints[i].y);
                    uv *= 0.5f;
                    uv += new Vector2(0.5f, 0.5f);
                    vex.uv0 = uv;
                    vex.color = edgeColor;
                    outlinePoints.Add(vex);

                    vex = UIVertex.simpleVert;
                    vex.position = new Vector3(rect.center.x + outsidePoints2[i].x * radius, rect.center.y + outsidePoints2[i].y * radius, 0);
                    uv = new Vector2(outsidePoints2[i].x, outsidePoints2[i].y);
                    uv *= 0.5f;
                    uv += new Vector2(0.5f, 0.5f);
                    vex.uv0 = uv;
                    vex.color = edgeColor;
                    outlinePoints.Add(vex);
                }

            }
        }

        private Vector2 GetPointToLine(Vector2 p0, Vector2 p1, Vector2 p2)
        {
            Vector2 lineDir = p1 - p2;
            lineDir.Normalize();
            float x0 = p0.x;
            float y0 = p0.y;
            float x1 = p1.x;// -lineDir.x*10;
            float y1 = p1.y;// - lineDir.y * 10;
            float x2 = p2.x;// + lineDir.x * 10;
            float y2 = p2.y;// + lineDir.x * 10;
            if ((x1 == x0 && y1 == y0) || (x2 == x0 && y2 == y0))
            {
                return new Vector2(x0, y0);//点和线段一边重合
            }

            float k = 1;
            if (x1 != x2)
            {
                k = (y2 - y1) / (x2 - x1);
            }
            float a = k;
            float b = -1;
            float c = y1 - k * x1;
            float d = Mathf.Abs(a * x0 + b * y0 + c) / Mathf.Sqrt(a * a + b * b);
            float px = (b * b * x0 - a * b * y0 - a * c) / (a * a + b * b);
            float py = (a * a * y0 - a * b * x0 - b * c) / (a * a + b * b);
            return new Vector2(px, py);
        }

        private Vector2 GetLineCrossPoint(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4)
        {
            Vector2 dir1 = (p1 - p2).normalized;
            p1 += dir1;
            p2 -= dir1;
            Vector2 dir2 = (p3 - p4).normalized;
            p3 += dir2;
            p4 -= dir2;
            Vector2 bx = p4 - p3;
            float d1 = Mathf.Abs(CrossMulVec(bx, p1 - p3));
            float d2 = Mathf.Abs(CrossMulVec(bx, p2 - p3));
            float dx = d1 + d2;
            if (dx == 0)
            {
                return p1;
            }
            float t = d1 / dx;
            Vector2 temp = (p2 - p1) * t;
            return p1 + temp;
        }

        private float CrossMulVec(Vector2 p1, Vector2 p2)
        {
            return p1.x * p2.y - p2.x * p1.y;
        }

        private void CreateMeshParam()
        {
            vertexList = new List<UIVertex>();
            indexList = new List<int>();
            int insidePointCount = 0;
            if (insidePoints != null && insidePoints.Count > 0)
            {
                insidePointCount = insidePoints.Count;
                for (int i = 0; i < insidePoints.Count; i++)
                {
                    vertexList.Add(insidePoints[i]);
                }
                List<int> tempList = new List<int>();
                if (sideCount > 2)
                {
                    int ind3 = 0;
                    for (int i = 0; i < sideCount; i++)
                    {
                        tempList.Add(0);
                        tempList.Add(i + 1);
                        ind3 = i + 2;
                        if (ind3 > sideCount)
                        {
                            ind3 = 1;
                        }
                        tempList.Add(ind3);
                    }
                }
                indexList = tempList;
            }
            if (outlinePoints != null && outlinePoints.Count > 0)
            {
                for (int i = 0; i < outlinePoints.Count; i++)
                {
                    vertexList.Add(outlinePoints[i]);
                }
                for (int i = 0; i < sideCount; i++)
                {
                    int ind1 = i * 2;
                    int ind2 = i * 2 + 2;
                    int ind3 = i * 2 + 1;
                    int ind4 = i * 2 + 3;
                    if (i == sideCount - 1)
                    {
                        ind2 = 0;
                        ind4 = 1;
                    }
                    indexList.Add(ind1 + insidePointCount);
                    indexList.Add(ind2 + insidePointCount);
                    indexList.Add(ind3 + insidePointCount);
                    indexList.Add(ind3 + insidePointCount);
                    indexList.Add(ind2 + insidePointCount);
                    indexList.Add(ind4 + insidePointCount);
                }
            }
        }

        // Update is called once per frame
        void Update()
        {

        }


        protected override void OnPopulateMesh(VertexHelper vh)
        {
            //base.OnPopulateMesh(vh);
            vh.Clear();
            if(isChange)
            {
                UpdatePoly();
                if(Application.isPlaying)
                    isChange = false;
            }
            
            if (vertexList != null && vertexList.Count > 0)
            {
                vh.AddUIVertexStream(vertexList, indexList);
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2150255.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

超声波清洗机哪个品牌更值得推荐一些?四款良心眼镜清洗机值得信赖!

作为一名拥有20年戴镜经历的眼镜一族&#xff0c;我深深体会到清洁眼镜的种种挑战&#xff1a;微小缝隙里的污垢难以清除&#xff0c;频繁积累的脏污往往让我无暇应对&#xff0c;而用力擦拭又恐伤及镜片&#xff0c;这确实让人苦恼不已&#xff0c;渴求一种有效的清洁解决方案…

C++11(5)

目录 12。function包装器 用法 function的应用 13。bind绑定 bind的应用——计算利息 万众瞩目的C11它又来了&#xff0c;本章将继续讲解C11更新的内容&#xff0c;欢迎观看&#xff01;&#xff01;&#xff01; 12。function包装器 function包装器 也叫作适配器。C中的…

大数据新视界 --大数据大厂之算法在大数据中的核心作用:提升效率与智能决策

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

情感类智能体——你的微信女神

智能体名称&#xff1a;你的微信女神 链接&#xff1a;文心智能体平台AgentBuilder | 想象即现实 (baidu.com)https://agents.baidu.com/agent/preview/RulbsUjIGj4wsinydlBH7AR3NQKFungt 简介 “你的微信女神”是一个直率的智能体&#xff0c;她用犀利而真实的言辞帮助用户…

kubernetes调度2

1、各种缩写的应用 [rootk8s-master test]# kubectl get rsNAME DESIRED CURRENT READY AGEtest001-64c7957b5c 2 2 2 8m59stest001-698b98bb8f 0 0 0 12m[rootk8s-master test]# kubectl get replicas…

医疗领域患者监控中的手势识别:一种深度卷积神经网络方法

这篇论文的标题是《Hand Gesture Recognition for Patient Monitoring in the Medical Field: A Deep Convolution Neural Networks Approach》&#xff0c;作者们来自印度的Chaitanya Bharathi Institute of Technology电子与通信工程系。论文主要探讨了在医疗领域&#xff0c…

【Redis入门到精通二】Redis核心数据类型(String,Hash)详解

目录 Redis数据类型 1.String类型 &#xff08;1&#xff09;常见命令 &#xff08;2&#xff09;内部编码 2.Hash类型 &#xff08;1&#xff09;常见命令 &#xff08;2&#xff09;内部编码 Redis数据类型 查阅Redis官方文档可知&#xff0c;Redis提供给用户的核心数据…

先导小型五轴数控加工中心助力职业教育

职业本科高校规模不断扩大&#xff0c;职校学生升学渠道打通&#xff0c;产教融合更加紧密&#xff0c;科教融汇成果不断出现&#xff0c;教学改革持续深化……种种迹象表明&#xff0c;职业教育大变革已经开启。 推进新型工业化、发展新质生产力等时代命题与职业教育发展方向和…

深刻理解OS管理与进程

OS是什么 OS&#xff1a;operator system OS的本质是进行软硬件资源管理的软件 内存是cpu与外部间的巨大缓存 OS的意义 对下&#xff1a;操作系统对下软硬件资源的管理&#xff0c;保证系统稳定的&#xff0c;高效的安全的能进行良好的工作&#xff08;手段&#xff09;对上&am…

Linux--禁止root用户通过ssh直接登录

原文网址&#xff1a;Linux--禁止root用户通过ssh直接登录_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Linux服务器怎样禁止root用户通过ssh直接登录。 为什么要禁止&#xff1f; 因为root用户是每个Linux系统都有的&#xff0c;黑客可以使用root用户名尝试不同的密码来暴力破…

电机控制系统PCB设计 222

6 还能只用网络标号?没用网络端口比较电流 通过SD引脚来控制电机驱动右边是电机四个MOS管是连在一起的不懂为啥加左边这个好像说只要用芯片的 就加个滤波电容?DRV87里也有这个 难道都要有这个?? 缓冲? 数字逻辑?加了左上这个 吸收的防止电源超过7.2V这放旁边就行??? 取…

C++ OpenCV Canny边缘检测,使用Trackbar滑动条选择最佳参数

目录 一、代码二、检测效果 一、代码 下面代码可以通过Trackbar滑动条拖动查看最佳阈值&#xff0c;使用只需要修改导入图像路径。本教程提供的边缘检测方法为Canny&#xff0c;学者可以在此框架基础上替换为其它检测方法。 具体代码见下&#xff1a; #include <iostream…

重磅发布:OpenAI o1全新推理模型系列

2024年9月12日&#xff0c;OpenAI正式推出全新的推理模型系列——OpenAI o1。这款全新AI模型系列专为解决复杂问题而设计&#xff0c;能够在响应前花费更多时间进行思考&#xff0c;并通过深入推理应对比以往模型更具挑战性的科学、编程和数学问题。 1. 开发背景与首发版本 今…

【记录】C++学习路线

一、记录心得&#xff1a; 目前自己的状况是刚上大三&#xff0c;学校是双非一本&#xff0c;教的主流方向是 J A V A JAVA JAVA开发方向&#xff0c;还有就是嵌入式方向&#xff0c;这两个方向自己都不是很感兴趣&#xff0c;所以从大一开始就自学 C C C&#xff0c;加入 A…

2024.9.20 作业

写一个shell脚本&#xff0c;将以下内容放到脚本中&#xff1a; a.在家目录下创建目录文件&#xff0c;dir b.dir下创建dir1和dir2 c.把当前目录下的所有文件拷贝到dir1中&#xff0c; d.把当前目录下的所有脚本文件拷贝到dir2中 e.把dir2打包并压缩为dir2.tar.xz f.再把…

Cypress初次安装启动常见问题

安装成功后会出现如图所示目录和文件 Cypress启动问题 进入node_modules下的.bin 目录,执行命令: cypress open 启动cypress&#xff0c;此时会有一个报错&#xff0c;如图 需要进入项目目录&#xff0c;编辑package.json文件中scripts配置 此时再次启动CMD&#xff0c;进入根…

CSP-J2024全真模拟题 阅读程序题3+程序填空题

由于明天考试&#xff0c;今天晚上给大家提供详细的答案和解析&#xff0c;求关注点赞和评论 28.将第 1 行改为 &#xff03;include<iostream>&#xff0c;程序的运行结果不变。&#xff08;&#xff09; A.对B.错 29.本程序用到了队列而不是栈的思想。&#xff08;&a…

pdb文件查看工具pdbripper.exe

下载地址:https://www.bing.com/ck/a?!&&p249322afbfbc575bJmltdHM9MTcyMTM0NzIwMCZpZ3VpZD0yMjBkODE2MC1hYjNhLTZkYTMtMGVlYi05NWQ5YWE3OTZjOGEmaW5zaWQ9NTE4Mg&ptn3&ver2&hsh3&fclid220d8160-ab3a-6da3-0eeb-95d9aa796c8a&psqpdbripper.exe&…

交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面

一、介绍 交通标志识别系统。本系统使用Python作为主要编程语言&#xff0c;在交通标志图像识别功能实现中&#xff0c;基于TensorFlow搭建卷积神经网络算法模型&#xff0c;通过对收集到的58种常见的交通标志图像作为数据集&#xff0c;进行迭代训练最后得到一个识别精度较高…

多态的使用和原理(c++详解)

一、多态的概念 多态顾名思义就是多种形态&#xff0c;它分为编译时的多态&#xff08;静态多态&#xff09;和运行时的多态&#xff08;动态多态&#xff09;&#xff0c;编译时多态&#xff08;静态多态&#xff09;就是函数重载&#xff0c;模板等&#xff0c;通过不同的参数…