unity 网格面片生成抛物线,折线

unity 网格面片生成抛物线,折线

实现效果

工程文件下载地址

一、 网格面片的建立方法

编写一个通用的网格面片线生成方法

线宽的处理

网格面片线建立相对于,管道线建立《unity 线绳管道纯代码创建方法》更为简单,建立方法也类似,可以把面片线理解成,任意个两点线段前后连接组成的多边形,线段的长度就是面片线的线宽。随之会发现,当六个以上点建立线,两端线和中间线的向量不一样时,会出现线宽不一致的情况,如下图。

线段a、b、c的长度是一样的组成的面片线的线宽不一致。

为了解决这个问题,我们需要动态改变所以中间线段的长度。

如上图所示,需要动态改变的是线段b。已知线段a的长度,∠α的度数(三点求夹角)求线段b的长度。
∠ α = 2 ∠ β A C = A B s i n β ∠α=2∠β\\ AC= \displaystyle\frac{AB} {sinβ}\\ α=2βAC=sinβAB

这里存在一个问题,如果∠β的角度足够小,AC线段会无限长,为了解决这个问题,加入了前后断点,当角度小于一个值时,不连接拐点。如下面的代码,∠β不小于30°

实现效果

轴心线的建立

  /// <summary>
        /// 轴心线的建立
        /// </summary>
        /// <param name="createPoint"></param>
        /// <param name="lineWidth"></param>
        /// <returns></returns>
        List<LinePoint2D> SetLinePoint2D(Vector3[] createPoint, float lineWidth)
        {
            List<LinePoint2D> linePoint = new List<LinePoint2D>();
            int length = createPoint.Length;
            for (int i = 0; i < length; i++)
            {
                if (i == 0)
                {
                    Add2DLinePoints(lineWidth, createPoint[i], (createPoint[i + 1] - createPoint[i]).GetPlaneVector().normalized, ref linePoint);
                }
                else if (i == length - 1)
                {
                    Add2DLinePoints(lineWidth, createPoint[i], (createPoint[i] - createPoint[i - 1]).GetPlaneVector().normalized, ref linePoint);
                }
                else
                {
                    Get2DElbowPoint(createPoint[i], createPoint[i - 1], createPoint[i + 1], lineWidth, ref linePoint);
                }
            }
          
            return linePoint;
        }

拐点的建立

/// <summary>
        /// 得到拐点
        /// </summary>
        /// <param name="focusPoint">中间点</param>
        /// <param name="frontPoint">前一点</param>
        /// <param name="backPoint">后一点</param>
        void Get2DElbowPoint(Vector3 focusPoint, Vector3 frontPoint, Vector3 backPoint, float lineWidth, ref List<LinePoint2D> linePoint)
        {
            //焦点前后向量
            Vector3 frontVec = (frontPoint - focusPoint).normalized;
            Vector3 backVec = (backPoint - focusPoint).normalized;
            //平面点
            Vector3 frontPlaneVec = (frontPoint - focusPoint).GetPlaneVector().normalized;
            Vector3 backPlaneVec = (backPoint - focusPoint).GetPlaneVector().normalized;
            Vector3 focusVec = (frontPlaneVec + backPlaneVec).normalized;

            //得到前后断点
            Vector3 tangencyFrontPoint = (lineWidth * frontVec*0.5f) + focusPoint;
            Vector3 tangencyBackPoint = (lineWidth * backVec * 0.5f) + focusPoint;

            //得到两个焦点向量的法线
            Vector3 normalVec = Vector3.Cross(frontVec, backVec).normalized ;
            Vector3 directionVec;
            //前后向量相反时,法线向量为零
            if (frontPlaneVec == -backPlaneVec)
            {
                 directionVec = backPlaneVec;
            }
            else
            {
                 directionVec = -Vector3.Cross(focusVec, normalVec).normalized;
            }
            Add2DLinePoints(lineWidth, tangencyFrontPoint, -frontPlaneVec, ref linePoint);
            float angle = Vector3.Angle(frontPlaneVec, backPlaneVec) * 0.5f;
            if (angle>30)
            {
                float newLineWidth = lineWidth / Mathf.Sin(angle * Mathf.Deg2Rad);
                //增加管线点
                Add2DLinePoints(newLineWidth, focusPoint, directionVec, ref linePoint);
            }
            Add2DLinePoints(lineWidth, tangencyBackPoint, backPlaneVec, ref linePoint);
        }

创建网格点

        #region 创建网格点
        Vector3[] Create2DMeshPoint(List<LinePoint2D> linePoint,int type)
        {
            int length = linePoint.Count;
            Vector3[] meshPoint = new Vector3[length * 2];
            for (int i = 0; i < length; i++)
            {
                if (type==0)
                {
                    meshPoint[(i * 2) + 0] = new Vector3(linePoint[i].LineWidth * 0.5f, 0, 0).FromToMoveRotation(linePoint[i].Location, linePoint[i].Direction);
                    meshPoint[(i * 2) + 1] = new Vector3(-linePoint[i].LineWidth * 0.5f, 0, 0).FromToMoveRotation(linePoint[i].Location, linePoint[i].Direction);
                }
                else if (type == 1)
                {
                    meshPoint[(i * 2) + 0] = new Vector3( 0, 0,linePoint[i].LineWidth * 0.5f).FromToMoveRotation(linePoint[i].Location, linePoint[i].Direction);
                    meshPoint[(i * 2) + 1] = new Vector3(0, 0, -linePoint[i].LineWidth * 0.5f).FromToMoveRotation(linePoint[i].Location, linePoint[i].Direction);
                }
                else
                {
                    meshPoint[(i * 2) + 0] = new Vector3(0, linePoint[i].LineWidth * 0.5f, 0).FromToMoveRotation(linePoint[i].Location, linePoint[i].Direction);
                    meshPoint[(i * 2) + 1] = new Vector3(0, -linePoint[i].LineWidth * 0.5f,  0).FromToMoveRotation(linePoint[i].Location, linePoint[i].Direction);
                }
            }
            return meshPoint;
        }
        #endregion

网格创建

  #region 网格创建
        /// <summary>
        /// 网格创建
        /// </summary>
        /// <param name="linePoints">线的轴心线组</param>
        /// <param name="meshPoint">网格点</param>
        /// <param name="count">段数</param>
        /// <param name="uvX">uv宽度</param>
        /// <returns></returns>
        Mesh CreatMesh(List<LinePoint2D> linePoints, Vector3[] meshPoint, int count, int uvX)
        {
            Mesh mesh = new Mesh();
            mesh.vertices = meshPoint;
            mesh.triangles = GetTriangles(linePoints.Count, count);
            mesh.uv = GetUV(linePoints, count, uvX);
            mesh.RecalculateNormals();
            mesh.RecalculateBounds();
            return mesh;
        }

        Vector2[] GetUV(List<LinePoint2D> linePoints,int count,int uvX)
        {
            int length = linePoints.Count;

            Vector2[] uvs = new Vector2[(count * length)];
            float lineDis = 0;
            int k = 0;
            for (int i = 0; i < length; i ++)
            {
                
                if (i != 0)
                {
                    lineDis += Vector3.Distance(linePoints[i].Location, linePoints[i - 1].Location);
                }
                for (int j = 0; j < count; j++)
                {
                    Vector2 vector2;
                    if (j % 2 != 0)
                    {
                        vector2 = new Vector2(uvX, lineDis);
                    }
                    else
                    {
                        vector2 = new Vector2(0, lineDis);
                    }

                    uvs[k] = vector2;
                    k += 1;
                }
            }
            return uvs;
        }
        /// <param name="length">线段段数</param>
        /// <param name="count">横截面段数(也就是圆的段数)</param>
        /// <returns></returns>
        int[] GetTriangles(int length, int count)
        {
            int[] triangles = new int[(count * (length - 1)) * 6];
            int k = 0;
            for (int i = 0; i < length - 1; i++)
            {
                for (int j = 0; j < count; j++)
                {
                        if (j == count - 1)
                        {
                            triangles[k] = (i * count) + j;
                            triangles[k + 1] = (i * count) + 0;
                            triangles[k + 2] = ((i + 1) * count) + 0;
                            triangles[k + 3] = (i * count) + j;
                            triangles[k + 4] = ((i + 1) * count) + 0;
                            triangles[k + 5] = ((i + 1) * count) + j;
                        }
                        else
                        {
                            triangles[k] = (i * count) + j;
                            triangles[k + 1] = (i * count) + j + 1;
                            triangles[k + 2] = ((i + 1) * count) + j + 1;
                            triangles[k + 3] = (i * count) + j;
                            triangles[k + 4] = ((i + 1) * count) + j + 1;
                            triangles[k + 5] = ((i + 1) * count) + j;
                        }
                    k += 6;
                }
            }
            return triangles;
        }
        #endregion

与管道线生成的异同点

unity 线绳管道纯代码创建方法

相同点

与创建管道线方法一致,也是通过得到中心路径的位置和放心,将线段矩阵变换到相应位置,构建网格点数组,从而建立网格。

不同点

管道线的拐点是内切圆分段,片面线的拐点是调整线段长度,保持线宽一致。为了保持uv的一致,也加入了类似管道线内切圆分段的方法,只是只加入前后两个点。

补充的扩展方法

 /// <summary>
        /// 角度旋转
        /// </summary>
        /// <param name="vector3"></param>
        /// <param name="angle">旋转角度</param>
        /// <param name="center">旋转中心点</param>
        /// <param name="direction">旋转轴</param>
        /// <returns></returns>
        public static Vector3 ToAngle(this Vector3 vector3, float angle, Vector3 center, Vector3 direction)
        {
            Vector3 pos = center;
            Quaternion quaternion = Quaternion.AngleAxis(angle, direction);
            Matrix4x4 matrix = new Matrix4x4();
            matrix.SetTRS(pos, quaternion, Vector3.one);
            vector3 = matrix.MultiplyPoint3x4(vector3);
            return vector3;
        }

        /// <summary>
        /// 矩阵变换
        /// </summary>
        /// <param name="vector3"></param>
        /// <param name="location">位置</param>
        /// <param name="direction">旋转向量</param>
        /// <returns></returns>
        public static Vector3 FromToMoveRotation(this Vector3 vector3, Vector3 location, Vector3 direction)
        {
            return vector3.FromToMoveRotation(location, direction,Vector3.one);
        }
        public static Vector3 FromToMoveRotation(this Vector3 vector3, Vector3 location, Vector3 direction,Vector3 scale)
        {
            Matrix4x4 matrix = Matrix4x4.identity;
            Quaternion quaternion = Quaternion.LookRotation(direction, direction);
            matrix.SetTRS(location, quaternion, scale);
            vector3 = matrix.MultiplyPoint3x4(vector3);
            return vector3;
        }

        /// <summary>
        /// 得到平面投影向量
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public static Vector3 GetPlaneVector(this Vector3 vector3)
        {
            return new Vector3(vector3.x, 0, vector3.z);
        }

二、 抛物线创建

抛物线公式
y = a x 2 + b x + c y=ax^2+bx+c y=ax2+bx+c
从公式上看,只知道起点和终点是不能确定一条抛物线的,所以我们要把 a a a定义成变量, a = 1 2 p a=\displaystyle\frac{1}{2p} a=2p1, p p p为焦准距。

把起点设为原点, c = 0 c=0 c=0,带入终点向量坐标,求出 b b b

         Vector3 originPlanePoint = GetPlaneVector(originPoint);
         Vector3 endPlanePoint = GetPlaneVector(endPoint);
            float xzMagnitude = Vector3.Distance(originPlanePoint, endPlanePoint);
            float a;
            if (p == 0)
            {
                a = -2 /  xzMagnitude;
            }
            else
            {
                a = -1 / (2 * p);
            }
            float yMagnitude = (endPoint - originPoint).y;
            float b = (yMagnitude - (xzMagnitude * xzMagnitude * a)) / xzMagnitude;

猜你喜欢

转载自blog.csdn.net/dxs1990/article/details/125185612