贝塞尔曲线 维基+ 转 XNA绘制三次贝塞尔曲线

维基百科,自由的百科全书

 

 

三次方贝济埃曲线

数学数值分析领域中,贝济埃曲线Bézier curve)是电脑图形学中相当重要的参数曲线。更高维度的广泛化贝济埃曲线就称作贝济埃曲面,其中贝济埃三角是一种特殊的实例。

贝济埃曲线于1962年,由法国工程师皮埃尔·贝济埃Pierre Bézier)所广泛发表,他运用贝济埃曲线来为汽车的主体进行设计。贝济埃曲线最初由Paul de Casteljau1959年运用de Casteljau算法开发,以稳定数值的方法求出贝济埃曲线。

目录

  [隐藏]

[编辑]实例说明

[编辑]线性贝济埃曲线

给定点P0P1,线性贝济埃曲线只是一条两点之间的直线。这条线由下式给出:

/mathbf{B}(t)=/mathbf{P}_0 + (/mathbf{P}_1-/mathbf{P}_0)t=(1-t)/mathbf{P}_0 + t/mathbf{P}_1 /mbox{ , } t /in [0,1]

且其等同于线性插值

[编辑]二次方贝济埃曲线

二次方贝济埃曲线的路径由给定点P0P1P2的函数Bt)追踪:

/mathbf{B}(t) = (1 - t)^{2}/mathbf{P}_0 + 2t(1 - t)/mathbf{P}_1 + t^{2}/mathbf{P}_2 /mbox{ , } t /in [0,1]

TrueType字型就运用了以贝济埃样条组成的二次贝济埃曲线。

[编辑]三次方贝济埃曲线

P0P1P2P3四个点在平面或在三维空间中定义了三次方贝济埃曲线。曲线起始于P0走向P1,并从P2的方向来到P3。一般不会经过P1P2;这两个点只是在那里提供方向资讯。P0P1之间的间距,决定了曲线在转而趋进P3之前,走向P2方向的“长度有多长”。

曲线的参数形式为:

/mathbf{B}(t)=/mathbf{P}_0(1-t)^3+3/mathbf{P}_1t(1-t)^2+3/mathbf{P}_2t^2(1-t)+/mathbf{P}_3t^3 /mbox{ , } t /in [0,1]

现代的成象系统,如PostScriptAsymptoteMetafont,运用了以贝济埃样条组成的三次贝济埃曲线,用来描绘曲线轮廓。

[编辑]一般化

n阶贝济埃曲线可如下推断。给定点P0P1、…、Pn,其贝济埃曲线即

/mathbf{B}(t)=/sum_{i=0}^n {n/choose i}/mathbf{P}_i(1-t)^{n-i}t^i =/mathbf{P}_0(1-t)^n+{n/choose 1}/mathbf{P}_1(1-t)^{n-1}t+/cdots+/mathbf{P}_nt^n /mbox{ , } t /in [0,1]

例如n = 5

/mathbf{B}(t)=/mathbf{P}_0(1-t)^5+5/mathbf{P}_1t(1-t)^4+10/mathbf{P}_2t^2(1-t)^3+10/mathbf{P}_3t^3(1-t)^2+5/mathbf{P}_4t^4(1-t)+/mathbf{P}_5t^5 /mbox{ , } t /in [0,1]

如上公式可如下递归表达: 用/mathbf{B}_{/mathbf{P}_0/mathbf{P}_1/ldots/mathbf{P}_n}表示由点P0P1、…、Pn所决定的贝济埃曲线。则

/mathbf{B}(t) = /mathbf{B}_{/mathbf{P}_0/mathbf{P}_1/ldots/mathbf{P}_n}(t) = (1-t)/mathbf{B}_{/mathbf{P}_0/mathbf{P}_1/ldots/mathbf{P}_{n-1}}(t) + t/mathbf{B}_{/mathbf{P}_1/mathbf{P}_2/ldots/mathbf{P}_n}(t)

用平常话来说,n阶的贝济埃曲线,即双n - 1阶贝济埃曲线之间的插值。

[编辑]术语

一些关于参数曲线的术语,有

/mathbf{B}(t) = /sum_{i=0}^n /mathbf{P}_i/mathbf{b}_{i,n}(t),/quad t/in[0,1]

即多项式

/mathbf{b}_{i,n}(t) = {n/choose i} t^i (1-t)^{n-i},/quad i=0,/ldots n

又称作n阶的伯恩斯坦基底多项式,定义00 = 1。

Pi称作贝济埃曲线的控制点多边形以带有线的贝济埃点连接而成,起始于P0并以Pn终止,称作贝济埃多边形(或控制多边形)。贝济埃多边形的凸包(convex hull)包含有贝济埃曲线。

[编辑]注解

  • 开始于P0并结束于Pn的曲线,即所谓的端点插值法属性。
  • 曲线是直线的充分必要条件是所有的控制点都位在曲线上。同样的,贝济埃曲线是直线的充分必要条件是控制点共线
  • 曲线的起始点(结束点)相切于贝济埃多边形的第一节(最后一节)。
  • 一条曲线可在任意点切割成两条或任意多条子曲线,每一条子曲线仍是贝济埃曲线。
  • 一些看似简单的曲线(如)无法以贝济埃曲线精确的描述,或分段成贝济埃曲线(虽然当每个内部控制点对单位圆上的外部控制点水平或垂直的的距离为4/left(/sqrt{2} -1/right)/3时,分成四段的贝济埃曲线,可以小于千分之一的最大半径误差近似于圆)。
  • 位于固定偏移量的曲线(来自给定的贝济埃曲线),又称作偏移曲线(假平行于原来的曲线,如两条铁轨之间的偏移)无法以贝济埃曲线精确的形成(某些琐屑实例除外)。无论如何,现存的启发法通常可为实际用途中给出近似值。

[编辑]建构贝济埃曲线

[编辑]线性曲线

线性贝济埃曲线演示动画,t in [0,1]
线性贝济埃曲线演示动画,t in [0,1]

线性贝济埃曲线函数中的t会经过由P0P1Bt)所描述的曲线。例如当t=0.25时,Bt)即一条由点P0P1路径的四分之一处。就像由0至1的连续tBt)描述一条由P0P1的直线。

[编辑]二次曲线

为建构二次贝济埃曲线,可以中介点Q0Q1作为由0至1的t

  • P0P1的连续点Q0,描述一条线性贝济埃曲线。
  • P1P2的连续点Q1,描述一条线性贝济埃曲线。
  • Q0Q1的连续点Bt),描述一条二次贝济埃曲线。
二次贝济埃曲线的结构 二次贝济埃曲线演示动画,t in [0,1]
二次贝济埃曲线的结构 二次贝济埃曲线演示动画,t in [0,1]

[编辑]高阶曲线

为建构高阶曲线,便需要相应更多的中介点。对于三次曲线,可由线性贝济埃曲线描述的中介点Q0Q1Q2,和由二次曲线描述的点R0R1所建构:

三次贝济埃曲线的结构 三次贝济埃曲线演示动画,t in [0,1]
三次贝济埃曲线的结构 三次贝济埃曲线演示动画,t in [0,1]

对于四次曲线,可由线性贝济埃曲线描述的中介点Q0Q1Q2Q3,由二次贝济埃曲线描述的点R0R1R2,和由三次贝济埃曲线描述的点S0S1所建构:

四次贝济埃曲线的结构 四次贝济埃曲线演示动画,t in [0,1]
四次贝济埃曲线的结构 四次贝济埃曲线演示动画,t in [0,1]

(还可参阅五阶贝济埃曲线的构成。)

[编辑]应用

[编辑]电脑绘图

贝济埃曲线被广泛地在计算机图形中用来为平滑曲线建立模型。

二次和三次贝济埃曲线最为常见

[编辑]程式范例

下列程式码为一简单的实际运用范例,展示如何使用C标出三次方贝济埃曲线。注意,此处仅简单的计算多项式系数,并读尽一系列由0至1的t值;实践中一般不会这么做,递归求解通常会更快速——以更多的内存为代价,花费较少的处理器时间。不过直接的方法较易于理解并产生相同结果。以下程式码已使运算更为清晰。实践中的最佳化会先计算系数一次,并在实际计算曲线点的循环中反复使用。此处每次都会重新计算,损失了效率,但程式码更清楚易读。

曲线的计算可在曲线阵列上将相连点画上直线——点越多,曲线越平滑。

在部分架构中,下以程式码也可由动态程式设计进行最佳化。举例来说,dt是一个常数,cx * t则等同于每次反复就修改一次常数。经反复应用这种最佳化后,循环可被重写为没有任何乘法(虽然这个过程不是稳定数值的)。

/*
 產生三次方貝茲曲線的程式碼
*/
 
typedef struct
{
    float x;
    float y;
}
Point2D;
 
/*
 cp在此是四個元素的陣列:
 cp[0]為起始點,或上圖中的P0
 cp[1]為第一個控制點,或上圖中的P1
 cp[2]為第二個控制點,或上圖中的P2
 cp[3]為結束點,或上圖中的P3
 t為參數值,0 <= t <= 1
*/
 
Point2D PointOnCubicBezier( Point2D* cp, float t )
{
    float   ax, bx, cx;
    float   ay, by, cy;
    float   tSquared, tCubed;
    Point2D result;
 
    /*計算多項式係數*/
 
    cx = 3.0 * (cp[1].x - cp[0].x);
    bx = 3.0 * (cp[2].x - cp[1].x) - cx;
    ax = cp[3].x - cp[0].x - cx - bx;
 
    cy = 3.0 * (cp[1].y - cp[0].y);
    by = 3.0 * (cp[2].y - cp[1].y) - cy;
    ay = cp[3].y - cp[0].y - cy - by;
 
    /*計算位於參數值t的曲線點*/
 
    tSquared = t * t;
    tCubed = tSquared * t;
 
    result.x = (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x;
    result.y = (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y;
 
    return result;
}
 
/*
 ComputeBezier以控制點cp所產生的曲線點,填入Point2D結構的陣列。
 呼叫者必須分配足夠的記憶體以供輸出結果,其為<sizeof(Point2D) numberOfPoints>
*/
 
void ComputeBezier( Point2D* cp, int numberOfPoints, Point2D* curve )
{
    float   dt;
    int	    i;
 
    dt = 1.0 / ( numberOfPoints - 1 );
 
    for( i = 0; i < numberOfPoints; i++)
        curve[i] = PointOnCubicBezier( cp, i*dt );
}

另一种贝济埃曲线的应用是在动画中,描述物件的运动路径等等。此处,曲线的x、y位置不用来标示曲线,但用来表示图形位置。当用在这种形式时,连续点之间的距离会变的更为重要,且大多不是平均比例。点将会串的更紧密,控制点更接近每一个点,而更为稀疏的控制点会散的更开。如果需要线性运动速度,进一步处理时就需要循所需路径将点平均分散。

[编辑]有理贝济埃曲线

有理贝济埃增加可调节的权重,以提供更近似于随意的形状。分子是加权的伯恩斯坦形式贝济埃曲线,而分母是加权的伯恩斯坦多项式的总和。

给定n + 1控制点Pi,有理贝济埃曲线可如下描述:

/mathbf{B}(t) =
/frac{
/sum_{i=0}^n b_{i,n}(t) /mathbf{P}_{i}w_i
}
{
/sum_{i=0}^n b_{i,n}(t) w_i
}

或简单的

/mathbf{B}(t) =
/frac{
/sum_{i=0}^n {n /choose i} t^i (1-t)^{n-i}/mathbf{P}_{i}w_i
}
{
/sum_{i=0}^n {n /choose i} t^i (1-t)^{n-i}w_i
}

[编辑]参阅

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

 以前有人发表过类似的文章,是用Texture2D模拟贝赛尔曲线 ,而本文是基于顶点绘制的。
  在XNA中,使用DrawUserPrimitives方法可以绘制直线,但是没有直接绘制贝塞尔曲线的方法。其实绘制贝塞尔曲线就是绘制一组与贝赛尔曲线近似的折线段。

  面向对象编程,首先定义贝赛尔曲线类。三次贝赛尔曲线由两端的锚点和中间两个控制点组成,没什么好说的,上代码:

Bezier.cs
using  System.Collections.Generic;
using  Microsoft.Xna.Framework;

namespace  DrawBezier
{
     ///   <summary>
     ///      定义一段三次贝塞尔曲线。
     ///   </summary>
     public   class  Bezier
    {
         ///   <summary>
         ///      储存构成该贝赛尔曲线的点的对应顶点结构。
         ///   </summary>
        List < Vector2 >  points;

         ///   <summary>
         ///      获取或设置贝赛尔曲线的第一个锚点。
         ///   </summary>
         public  Vector2 Anchor1
        {
             get
            {
                 return  anchor1;
            }
             set
            {
                anchor1  =  value;
                needUpdate  =   true ;
            }
        }
        Vector2 anchor1;

         ///   <summary>
         ///      获取或设置贝赛尔曲线的第二个锚点。
         ///   </summary>
         public  Vector2 Anchor2
        {
             get
            {
                 return  anchor2;
            }
             set
            {
                anchor2  =  value;
                needUpdate  =   true ;
            }
        }
        Vector2 anchor2;

         ///   <summary>
         ///      获取或设置贝赛尔曲线的第一个控制点。
         ///   </summary>
         public  Vector2 Control1
        {
             get
            {
                 return  control1;
            }
             set
            {
                control1  =  value;
                needUpdate  =   true ;
            }
        }
        Vector2 control1;

         ///   <summary>
         ///      获取或设置贝赛尔曲线的第二个控制点。
         ///   </summary>
         public  Vector2 Control2
        {
             get
            {
                 return  control2;
            }
             set
            {
                control2  =  value;
                needUpdate  =   true ;
            }
        }
        Vector2 control2;

         ///   <summary>
         ///      用于判断曲线的作用点是否改变。
         ///   </summary>
         bool  needUpdate  =   false ;

         ///   <summary>
         ///      用指定参数创建贝赛尔曲线的新实例。
         ///   </summary>
         ///   <param name="anchor1"> 指定贝赛尔曲线的第一个锚点。 </param>
         ///   <param name="control1"> 指定贝赛尔曲线的第一个控制点。 </param>
         ///   <param name="control2"> 指定贝赛尔曲线的第二个控制点。 </param>
         ///   <param name="anchor2"> 指定贝赛尔曲线的第二个锚点。 </param>
         public  Bezier(Vector2 anchor1, Vector2 control1, Vector2 control2, Vector2 anchor2)
        {
             this .Anchor1  =  anchor1;
             this .Anchor2  =  anchor2;
             this .Control1  =  control1;
             this .Control2  =  control2;
        }
    }
}

  设贝塞尔曲线的作用点分别为P1(第一个锚点)、P2(第一个控制点)、P3(第二个控制点)、P4(第二个锚点)。首先确定P1和P2、P2和P3、P3和P4的中心点,分别设为P12、P23、P34;然后找到P12和P23、P23和P34的中心点,设为P123、P234;这两个点的中心点P为该贝塞尔曲线上的一点(这是贝塞尔曲线的一个重要性质,其原理网上到处都是)。此点将原贝塞尔曲线一分为二,生成两段新的贝塞尔曲线。

  根据这个原理,可以递归拆分贝赛尔曲线直到生成的曲线与直线近似。判断是否近似的标准就是:新生成贝塞尔曲线的两个控制点到经过两锚点的直线的距离小于指定容限(注:容限一般设为0.1414)。

  代码如下: 

Bezier.cs方法
         ///   <summary>
         ///      用指定参数创建贝赛尔曲线的新实例。
         ///   </summary>
         ///   <param name="anchor1"> 指定贝赛尔曲线的第一个锚点。 </param>
         ///   <param name="control1"> 指定贝赛尔曲线的第一个控制点。 </param>
         ///   <param name="control2"> 指定贝赛尔曲线的第二个控制点。 </param>
         ///   <param name="anchor2"> 指定贝赛尔曲线的第二个锚点。 </param>
         public  Bezier(Vector2 anchor1, Vector2 control1, Vector2 control2, Vector2 anchor2)
        {
             this .Anchor1  =  anchor1;
             this .Anchor2  =  anchor2;
             this .Control1  =  control1;
             this .Control2  =  control2;
        }

         ///   <summary>
         ///      获取该贝赛尔曲线的近似折线的点集。
         ///   </summary>
         ///   <returns> 该贝赛尔曲线的近似折线的点集。 </returns>
         public  List < Vector2 >  GetPoints()
        {
             if  (needUpdate)
            {
                points  =   new  List < Vector2 > ();
                points.Add( this .Anchor1);
                CubicBezierToPoints( this .Anchor1,  this .Control1,  this .Control2,  this .Anchor2, points);
                needUpdate  =   false ;
            }
             return  points;
        }

         ///   <summary>
         ///      将指定参数的贝赛尔曲线转换为近似折线的点集。
         ///   </summary>
         ///   <param name="p0"> 指定贝赛尔曲线的第一个锚点。 </param>
         ///   <param name="p1"> 指定贝赛尔曲线的第二个控制点。 </param>
         ///   <param name="p2"> 指定贝赛尔曲线的第一个控制点。 </param>
         ///   <param name="p3"> 指定贝赛尔曲线的第二个锚点。 </param>
         ///   <param name="points"> 转换后的近似折线的点集。 </param>
         void  CubicBezierToPoints(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, List < Vector2 >  points)
        {
             if  (Distance(p1, p0, p3)  <   0.02   &&  Distance(p2, p0, p3)  <   0.02 )
            {
                points.Add(p3);
            }
             else
            {
                Vector2 p01  =   new  Vector2((p0.X  +  p1.X)  /   2 , (p0.Y  +  p1.Y)  /   2 );
                Vector2 p12  =   new  Vector2((p1.X  +  p2.X)  /   2 , (p1.Y  +  p2.Y)  /   2 );
                Vector2 p23  =   new  Vector2((p2.X  +  p3.X)  /   2 , (p2.Y  +  p3.Y)  /   2 );

                Vector2 p012  =   new  Vector2((p01.X  +  p12.X)  /   2 , (p01.Y  +  p12.Y)  /   2 );
                Vector2 p123  =   new  Vector2((p12.X  +  p23.X)  /   2 , (p12.Y  +  p23.Y)  /   2 );

                Vector2 p  =   new  Vector2((p012.X  +  p123.X)  /   2 , (p012.Y  +  p123.Y)  /   2 );

                CubicBezierToPoints(p0, p01, p012, p, points);
                CubicBezierToPoints(p, p123, p23, p3, points);
            }
        }

         ///   <summary>
         ///      计算指定点 p 到指定直线 ab 的距离的平方。
         ///   </summary>
         ///   <param name="p"> 指定点 p。 </param>
         ///   <param name="a"> 指定直线的第一个点 a。 </param>
         ///   <param name="b"> 指定直线的第二个点 b。 </param>
         ///   <returns> 点 p 到直线 ab 的距离的平方。 </returns>
         float  Distance(Vector2 p, Vector2 a, Vector2 b)
        {
             float  paX  =  p.X  -  a.X;
             float  paY  =  p.Y  -  a.Y;

             float  baX  =  b.X  -  a.X;
             float  baY  =  b.Y  -  a.Y;

             float  pa2  =  paX  *  paX  +  paY  *  paY;
             float  ba2  =  baX  *  baX  +  baY  *  baY;

             float  apab  =  paX  *  baX  +  paY  *  baY;
             float  apab2  =  apab  *  apab;

             return  pa2  -  apab2  /  ba2;
        }

   得到这组点集后可以做很多事,这里提供我自己的绘制方法,以供参考。

  定义简单的顶点结构:VertexPosition2D 

 

VertexPosition2D.cs
using  Microsoft.Xna.Framework;
using  Microsoft.Xna.Framework.Graphics;

namespace  DrawBezier
{
     public   struct  VertexPosition2D
    {
         public  Vector2 Position;
         public   static   readonly   int  SizeInBytes  =   sizeof ( float )  *   2 ;

         public   static   readonly  VertexElement[] VertexElements  =  
        {
             new  VertexElement( 0 ,  0 , VertexElementFormat.Vector2, VertexElementMethod.Default, VertexElementUsage.Position,  0 ),
        };

         public  VertexPosition2D(Vector2 position)
        {
            Position  =  position;
        }
    }
}

    编写简单的绘制直线的Shader:

 

Line.fx
float4 Color;

float4 VS_Main(float2 Position : POSITION0) : POSITION0
{
     return  float4(Position.xy, 0.5 , 1 );
}

float4 PS_Main(float2 Position : POSITION0) : COLOR0
{
     return  Color;
}

technique Technique1
{
    pass Pass1
    {
        VertexShader  =  compile vs_1_1 VS_Main();
        PixelShader  =  compile ps_1_1 PS_Main();
    }
}

    在游戏主程序中运用:

 

Game1.cs
using  System;
using  System.Collections.Generic;
using  Microsoft.Xna.Framework;
using  Microsoft.Xna.Framework.Graphics;

namespace  DrawBezier
{
     ///   <summary>
     ///      测试贝塞尔曲线。
     ///   </summary>
     public   class  Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;

        Effect lineEffect;
        VertexDeclaration declaration;
        Bezier bezier;
        VertexPosition2D[] vertices;

         public  Game1()
        {
            graphics  =   new  GraphicsDeviceManager( this );
            Content.RootDirectory  =   " Content " ;

            graphics.PreferredBackBufferWidth  =   400 ;
            graphics.PreferredBackBufferHeight  =   300 ;
            graphics.PreferMultiSampling  =   true ;
            graphics.PreparingDeviceSettings  +=   new  EventHandler < PreparingDeviceSettingsEventArgs > (graphics_PreparingDeviceSettings);
        }

         void  graphics_PreparingDeviceSettings( object  sender, PreparingDeviceSettingsEventArgs e)
        {
             //  Xbox 360 and most PCs support FourSamples/0   
             //  (4x) and TwoSamples/0 (2x) antialiasing.  
            PresentationParameters pp  =  e.GraphicsDeviceInformation.PresentationParameters;
             int  quality  =   0 ;
            GraphicsAdapter adapter  =  e.GraphicsDeviceInformation.Adapter;
            SurfaceFormat format  =  adapter.CurrentDisplayMode.Format;
             //  Check for 4xAA  
             if  (adapter.CheckDeviceMultiSampleType(DeviceType.Hardware, format,
                 false , MultiSampleType.FourSamples,  out  quality))
            {
                 //  even if a greater quality is returned, we only want quality 0  
                pp.MultiSampleQuality  =   0 ;
                pp.MultiSampleType  =
                    MultiSampleType.FourSamples;
            }
             //  Check for 2xAA  
             else   if  (adapter.CheckDeviceMultiSampleType(DeviceType.Hardware,
                format,  false , MultiSampleType.TwoSamples,  out  quality))
            {
                 //  even if a greater quality is returned, we only want quality 0  
                pp.MultiSampleQuality  =   0 ;
                pp.MultiSampleType  =
                    MultiSampleType.TwoSamples;
            }
             return ;
        } 

         ///   <summary>
         ///      初始化。
         ///   </summary>
         protected   override   void  Initialize()
        {
            declaration  =   new  VertexDeclaration(GraphicsDevice, VertexPosition2D.VertexElements);

            bezier  =   new  Bezier( new  Vector2( - 100 ,  - 50 ),  new  Vector2( - 200 ,  150 ),  new  Vector2( 250 ,  200 ),  new  Vector2( 100 ,  - 100 ));
            List < Vector2 >  positions  =  bezier.GetPoints();
            vertices  =   new  VertexPosition2D[positions.Count];
             int  i  =   0 ;
             foreach  (Vector2 position  in  positions)
            {
                Vector2 pos  =   new  Vector2(position.X  /  GraphicsDevice.Viewport.Width  *   2 , position.Y  /  GraphicsDevice.Viewport.Height  *   2 );
                vertices[i]  =   new  VertexPosition2D(pos);
                i ++ ;
            }

             base .Initialize();
        }

         ///   <summary>
         ///      加载资源。
         ///   </summary>
         protected   override   void  LoadContent()
        {
            lineEffect  =  Content.Load < Effect > ( " Effects/Line " );
        }

         ///   <summary>
         ///      绘制。
         ///   </summary>
         ///   <param name="gameTime"> Provides a snapshot of timing values. </param>
         protected   override   void  Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            lineEffect.Parameters[ " Color " ].SetValue(Color.White.ToVector4());
            lineEffect.Begin();
             foreach  (EffectPass pass  in  lineEffect.CurrentTechnique.Passes)
            {
                pass.Begin();
                GraphicsDevice.VertexDeclaration  =  declaration;
                GraphicsDevice.DrawUserPrimitives < VertexPosition2D > (PrimitiveType.LineStrip, vertices,  0 , vertices.Length  -   1 );
                pass.End();
            }
            lineEffect.End(); 

             base .Draw(gameTime);
        }
    }
}
得到的效果图如下:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值