流星

流星消逝的时候,光明已在望。黑暗无论多么长,光明迟早总是会来的。

贝塞尔曲线应用 有更新!

    游戏里有些地方会用到贝塞尔曲线,相关的还有B样条线(多个贝塞尔曲线首尾相连)
    我见过的
    有做新手引导的,一些按钮需要用一个曲线引导,在曲线的终点绘制一个高亮的镂空的圆圈,指明当前要拖动到这里
    还有一种就是流星里的飞轮运动轨迹的
    飞轮的运动轨迹应该是一个仿S形状的轨迹

    其实贝塞尔曲线看起来很麻烦,但是只要真的去试试,就会了解
    一些算法会使用递归来计算任意t下的曲线轨迹,这里不用那么复杂,这里使用一种降阶方式
    先用一个极端点的做为例子:
    在平面坐标系里,3个不同点A,B,C形成2条线段AB,BC,求贝塞尔曲线方程
    实际上就是让t作为规格化参数,给一个处于0-1间的t,你求出由A,B,C三个点形成的贝塞尔曲线上的任意t的点
    比如如果求t = 0时的该贝塞尔曲线坐标那么会得到A点,当求t=1时该贝塞尔曲线坐标会得到C点
    而t 处于 0,1之间的任意值时,在AB线段上取得一个点D,令AD/AB = t 处于0-1间,同时在BC上取得一个点E,令BE/BC = t = AD / AB
    然后连接DE,在DE上取得一个点F,令DF/DE = t,这时,点F的坐标,即为最终要求的轨迹上的点,也就是F代表了在t,该贝塞尔曲线的坐标

    每次由一个外围的3个顶点A,B,C求得 D,E然后由D,E求得F,F即为最终点
    如果是N个顶点呢,其实很简单,得到N-1个下一层顶点,再把下一层作为当前层,再求,一直到得到最后一层只有2个顶点,这时,就可以停止,然后用这2个顶点,求得最终值
    所以这里提供一个非递归求贝塞尔曲线的C#类,贝塞尔曲线很早就意识到有了,但是一直没去看,大多数网上的文章都提出de Casteljau算法使用递归的实现。
    下面的代码比较简单,不用递归,也容易理解,核心就是要求外层多个控制点下的某个t对应的曲线值,只要每次求出内一层的控制点,然后把内外层调换
    到最后控制点个数==2时,就退出循环,用最终的2个控制点,算出最后的结果

    public class Spline
    {
        Vector3[] ControlPath;
        int ControlPoint;
        public Spline(int num)
        {
            ControlPoint = num;
            ControlPath = new Vector3[num];
        }
    
        public void SetControlPath(IEnumerable<Vector3> vec)
        {
            List<Vector3> vecL = new List<Vector3>();
            vecL.AddRange(vec);
            ControlPath = vecL.ToArray();
            ControlPoint = ControlPath.Length;
        }
    
        public void SetControlPointsCount(int count)
        {
            ControlPoint = count;
        }
    
        public void SetControlPoint(int i, Vector3 vec)
        {
            ControlPath[i] = vec;
        }
    
    //这部分就是把递归变化为轮换
        public Vector3 Eval(float t)
        {
            if (ControlPoint < 2 || ControlPath.Length < 2)
                return Vector3.zero;
            if (t > 1)
                return ControlPath[ControlPoint - 1];
            if (t < 0)
                return ControlPath[0];
            if (ControlPoint == 2)
                return (t) * (t * (ControlPath[2] - ControlPath[1]) - t * (ControlPath[1] - ControlPath[0]));
    
            int totalPoint = ControlPoint;
            
            List<Vector3> vecNext = new List<Vector3>();
            vecNext.AddRange(ControlPath);
    		//当剩下控制点数量>2时,计算接下来的一层控制点
            while (totalPoint > 2)
            {
                List<Vector3> vec = new List<Vector3>();
                for (int i = 0; i < totalPoint - 1; i++)
                    vec.Add(t * (vecNext[i + 1] - vecNext[i]) + vecNext[i]);
                vecNext.Clear();
    			//让计算出的内层控制点,变为当前外层控制点,进入下一个循环,一步步求出最内层控制点
                vecNext.AddRange(vec);
                totalPoint--;
            }
    		//当最终顶点数量==2时,直接计算最终点坐标
            return t * (vecNext[1] - vecNext[0]) + vecNext[0];
        }
    }
    

    流星里的飞轮估计比这个要复杂一点。这周末试着用这个还原

    validate