2013年11月13日星期三(DEMO8_9,三角形光栅化)

首先,介绍了一种算法,就是

1, 凸边形顶点按照顺时针或者逆时针顺序排列,

2, 先提取3个点,组成一个三角形,并分离这个三角形,

3, 再把剩下n-1个点递归计算,

 

然后提出了矢量光栅化,这个属于流水线部分的光栅化算法之一

流程如下:

1, 从上到下,从左到右,进行顺时针排列顶点顺序

2, 从最高顶点开始,光栅化从该顶点发出的左右两条边,

3, 当其中一条边到达终点,也就是到达了位于左边或右边的第二个顶点时,需要重新计算光栅化插值。

4, 继续直至所有点结束。

 

算法看起来简单,实际上很繁琐。直接给出代码。

 

void Draw_Filled_Polygon2D(POLYGON2D_PTR poly, UCHAR *vbuffer, int mempitch)

{

// this function draws a general n sided polygon

 

int ydiff1, ydiff2,         // difference between starting x and ending x

    xdiff1, xdiff2,         // difference between starting y and ending y

    start,                  // starting offset of line between edges

    length,                 // distance from edge 1 to edge 2

    errorterm1, errorterm2, // error terms for edges 1 & 2

    offset1, offset2,       // offset of current pixel in edges 1 & 2

    count1, count2,         // increment count for edges 1 & 2

    xunit1, xunit2;         // unit to advance x offset for edges 1 & 2

 

// initialize count of number of edges drawn:

int edgecount = poly->num_verts-1;

 

// determine which vertex is at top of polygon:

 

int firstvert=0;         // start by assuming vertex 0 is at top

 

int min_y=poly->vlist[0].y; // find y coordinate of vertex 0

 

for (int index=1; index < poly->num_verts; index++)

    { 

    // Search thru vertices

    if ((poly->vlist[index].y) < min_y)

        { 

        // is another vertex higher?

         firstvert=index;                  

         min_y=poly->vlist[index].y;

         } // end if

 

    } // end for index

 

// finding starting and ending vertices of first two edges:

int startvert1=firstvert;      // get starting vertex of edge 1

int startvert2=firstvert;      // get starting vertex of edge 2

int xstart1=poly->vlist[startvert1].x+poly->x0;

int ystart1=poly->vlist[startvert1].y+poly->y0;

int xstart2=poly->vlist[startvert2].x+poly->x0;

int ystart2=poly->vlist[startvert2].y+poly->y0;

int endvert1=startvert1-1;           // get ending vertex of edge 1

 

if (endvert1 < 0)

   endvert1=poly->num_verts-1;    // check for wrap

 

int xend1=poly->vlist[endvert1].x+poly->x0;      // get x & y coordinates

int yend1=poly->vlist[endvert1].y+poly->y0;      // of ending vertices

int endvert2=startvert2+1;           // get ending vertex of edge 2

 

if (endvert2==(poly->num_verts))

    endvert2=0;  // Check for wrap

 

int xend2=poly->vlist[endvert2].x+poly->x0;      // get x & y coordinates

int yend2=poly->vlist[endvert2].y+poly->y0;      // of ending vertices

 

// draw the polygon:

 

while (edgecount>0)

      {   

      // continue drawing until all edges drawn

      offset1=mempitch*ystart1+xstart1;  // offset of edge 1

      offset2=mempitch*ystart2+xstart2;  // offset of edge 2

     

      // initialize error terms

      // for edges 1 & 2

      errorterm1=0;       

      errorterm2=0;          

 

      // get absolute value of

     if ((ydiff1=yend1-ystart1) < 0)

         ydiff1=-ydiff1;

 

      // x & y lengths of edges

      if ((ydiff2=yend2-ystart2) < 0)

         ydiff2=-ydiff2;

 

      if ((xdiff1=xend1-xstart1) < 0)

         {              

         // get value of length

          xunit1=-1;                    // calculate X increment

          xdiff1=-xdiff1;

          } // end if

      else

         {

          xunit1=1;

          } // end else

 

     if ((xdiff2=xend2-xstart2) < 0)

         {

         // Get value of length

          xunit2=-1;                   // calculate X increment

          xdiff2=-xdiff2;

          } // end else

      else

         {

          xunit2=1;

          } // end else

 

      // choose which of four routines to use

      if (xdiff1 > ydiff1)

         {   

         // if x length of edge 1 is greater than y length

          if (xdiff2 > ydiff2)

            { 

            // if X length of edge 2 is greater than y length

 

             // increment edge 1 on X and edge 2 on X:

             count1=xdiff1;    // count for x increment on edge 1

             count2=xdiff2;    // count for x increment on edge 2

 

             while (count1 && count2)

                  { 

                  // continue drawing until one edge is done

               // calculate edge 1:

                    while ((errorterm1 < xdiff1) && (count1 > 0))

                        {

                        // finished w/edge 1?

                          if (count1--)

                           {    

                           // count down on edge 1

                             offset1+=xunit1;  // increment pixel offset

                             xstart1+=xunit1;

                             } // end if

 

                          errorterm1+=ydiff1; // increment error term

 

                          if (errorterm1 < xdiff1)

                           {  // if not more than XDIFF

                             vbuffer[offset1]=(UCHAR)poly->color; // ...plot a pixel

                             } // end if

 

                           } // end while

                     

                  errorterm1-=xdiff1; // if time to increment X, restore error term

 

                   // calculate edge 2:

 

                    while ((errorterm2 < xdiff2) && (count2 > 0))

                        { 

                        // finished w/edge 2?

                          if (count2--)

                           {    

                           // count down on edge 2

                             offset2+=xunit2;  // increment pixel offset

                             xstart2+=xunit2;

                             } // end if

 

                            errorterm2+=ydiff2; // increment error term

 

                            if (errorterm2 < xdiff2)

                             {  // if not more than XDIFF

                                vbuffer[offset2]=(UCHAR)poly->color;  // ...plot a pixel

                               } // end if

 

                             } // end while

 

                      errorterm2-=xdiff2; // if time to increment X, restore error term

 

                     // draw line from edge 1 to edge 2:

 

                      length=offset2-offset1; // determine length of horizontal line

 

                      if (length < 0)

                       { // if negative...

                         length=-length;       // make it positive

                         start=offset2;        // and set START to edge 2

                         } // end if

                      else

                       start=offset1;     // else set START to edge 1

              

              for (int index=start; index < start+length+1; index++)

                  {  // From edge to edge...

               vbuffer[index]=(UCHAR)poly->color;         // ...draw the line

                  } // end for index

 

                  offset1+=mempitch;           // advance edge 1 offset to next line

                 ystart1++;

                  offset2+=mempitch;           // advance edge 2 offset to next line

                  ystart2++;

 

               } // end if

 

             } // end if

             else

            {

            // increment edge 1 on X and edge 2 on Y:

             count1=xdiff1;    // count for X increment on edge 1

             count2=ydiff2;    // count for Y increment on edge 2

            

            while (count1 && count2)

                  {  // continue drawing until one edge is done

                      // calculate edge 1:

                    while ((errorterm1 < xdiff1) && (count1 > 0))

                        { // finished w/edge 1?

                         if (count1--)

                           {

                           // count down on edge 1

                             offset1+=xunit1;  // increment pixel offset

                             xstart1+=xunit1;

                             } // end if

 

                          errorterm1+=ydiff1; // increment error term

 

                          if (errorterm1 < xdiff1)

                           {  // If not more than XDIFF

                             vbuffer[offset1]=(UCHAR)poly->color; // ...plot a pixel

                             } // end if

 

                          } // end while

 

                      errorterm1-=xdiff1; // If time to increment X, restore error term

 

                     // calculate edge 2:

                      errorterm2+=xdiff2; // increment error term

                     

                    if (errorterm2 >= ydiff2) 

                       { // if time to increment Y...

                         errorterm2-=ydiff2;        // ...restore error term

                         offset2+=xunit2;           // ...and advance offset to next pixel

                         xstart2+=xunit2;

                         } // end if

 

                     count2--;

 

                     // draw line from edge 1 to edge 2:

 

                      length=offset2-offset1; // determine length of horizontal line

 

                      if (length < 0) 

                       { // if negative...

                         length=-length;       // ...make it positive

                         start=offset2;        // and set START to edge 2

                         } // end if

                      else

                       start=offset1;        // else set START to edge 1

 

                     for (int index=start; index < start+length+1; index++)  // from edge to edge

                          {

                        vbuffer[index]=(UCHAR)poly->color;         // ...draw the line

                        } // end for index

 

                  offset1+=mempitch;           // advance edge 1 offset to next line

                      ystart1++;

                      offset2+=mempitch;           // advance edge 2 offset to next line

                      ystart2++;

 

                  } // end while

             } // end if

         } // end if

         else

            {

             if (xdiff2 > ydiff2)

               {

                // increment edge 1 on Y and edge 2 on X:

 

                count1=ydiff1;  // count for Y increment on edge 1

                count2=xdiff2;  // count for X increment on edge 2

 

                while(count1 && count2)

                    {  // continue drawing until one edge is done

                       // calculate edge 1:

 

                      errorterm1+=xdiff1; // Increment error term

 

                      if (errorterm1 >= ydiff1) 

                       {  // if time to increment Y...

                         errorterm1-=ydiff1;         // ...restore error term

                         offset1+=xunit1;            // ...and advance offset to next pixel

                         xstart1+=xunit1;

                         } // end if

 

                      count1--;

 

                 // Calculate edge 2:

 

                      while ((errorterm2 < xdiff2) && (count2 > 0))

                          { // finished w/edge 1?

                            if (count2--)

                             { // count down on edge 2

                                offset2+=xunit2;  // increment pixel offset

                                xstart2+=xunit2;

                               } // end if

 

                            errorterm2+=ydiff2; // increment error term

 

                            if (errorterm2 < xdiff2)

                             {  // if not more than XDIFF

                                vbuffer[offset2]=(UCHAR)poly->color; // ...plot a pixel

                               } // end if

                             } // end while

 

                      errorterm2-=xdiff2;  // if time to increment X, restore error term

 

                    // draw line from edge 1 to edge 2:

 

                      length=offset2-offset1; // determine length of horizontal line

 

                      if (length < 0)

                       {    // if negative...

                         length=-length;  // ...make it positive

                         start=offset2;   // and set START to edge 2

                         } // end if

                      else

                       start=offset1;  // else set START to edge 1

 

                     for (int index=start; index < start+length+1; index++) // from edge to edge...

                          {

                        vbuffer[index]=(UCHAR)poly->color;      // ...draw the line

                        } // end for index

 

                      offset1+=mempitch;         // advance edge 1 offset to next line

                      ystart1++;

                      offset2+=mempitch;         // advance edge 2 offset to next line

                      ystart2++;

 

               } // end if

             } // end if

             else

               {

                // increment edge 1 on Y and edge 2 on Y:

                count1=ydiff1;  // count for Y increment on edge 1

                count2=ydiff2;  // count for Y increment on edge 2

 

                while(count1 && count2)

                    { 

                    // continue drawing until one edge is done

                      // calculate edge 1:

                      errorterm1+=xdiff1;  // increment error term

 

                      if (errorterm1 >= ydiff1) 

                       {                           // if time to increment Y

                         errorterm1-=ydiff1;         // ...restore error term

                         offset1+=xunit1;            // ...and advance offset to next pixel

                         xstart1+=xunit1;

                         } // end if

              

                    count1--;

 

                     // calculate edge 2:

                      errorterm2+=xdiff2;            // increment error term

 

                      if (errorterm2 >= ydiff2) 

                       {                           // if time to increment Y

                         errorterm2-=ydiff2;         // ...restore error term

                         offset2+=xunit2;            // ...and advance offset to next pixel

                         xstart2+=xunit2;

                         } // end if

 

                      --count2;

 

                     // draw line from edge 1 to edge 2:

 

                      length=offset2-offset1;  // determine length of horizontal line

 

                      if (length < 0)

                       {         

                       // if negative...

                         length=-length;        // ...make it positive

                         start=offset2;         // and set START to edge 2

                         } // end if

                      else

                       start=offset1;         // else set START to edge 1

 

                     for (int index=start; index < start+length+1; index++)  

                        { // from edge to edge

                          vbuffer[index]=(UCHAR)poly->color;   // ...draw the linee

                        } // end for index

 

                      offset1+=mempitch;            // advance edge 1 offset to next line

                      ystart1++;

                      offset2+=mempitch;            // advance edge 2 offset to next line

                      ystart2++;

 

                  } // end while

 

             } // end else

 

         } // end if

 

        // another edge (at least) is complete. Start next edge, if any.

         if (!count1)

           {                      // if edge 1 is complete...

            --edgecount;           // decrement the edge count

            startvert1=endvert1;   // make ending vertex into start vertex

            --endvert1;            // and get new ending vertex

        

           if (endvert1 < 0)

              endvert1=poly->num_verts-1; // check for wrap

 

             xend1=poly->vlist[endvert1].x+poly->x0;  // get x & y of new end vertex

             yend1=poly->vlist[endvert1].y+poly->y0;

             } // end if

 

         if (!count2)

           {                     // if edge 2 is complete...

            --edgecount;          // decrement the edge count

            startvert2=endvert2;  // make ending vertex into start vertex

            endvert2++;           // and get new ending vertex

        

           if (endvert2==(poly->num_verts))

              endvert2=0;                // check for wrap

 

             xend2=poly->vlist[endvert2].x+poly->x0;  // get x & y of new end vertex

             yend2=poly->vlist[endvert2].y+poly->y0;

 

            } // end if

 

    } // end while

 

} // end Draw_Filled_Polygon2D

 

在每帧里面,是光栅化多边形,并旋转,然后为了好看点,弄了个调色板颜色变化。

即game_main()

{

……

if (FAILED(lpddsback->Lock(NULL,&ddsd,

                           DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,

                           NULL)))

return(0);

 

// do the graphics

Draw_Filled_Polygon2D(&object, (UCHAR *)ddsd.lpSurface, ddsd.lPitch);

 

// rotate the polygon by 5 degrees

Rotate_Polygon2D(&object, 5);

 

// unlock primary buffer

if (FAILED(lpddsback->Unlock(NULL)))

   return(0);

 

// perform palette animation

Set_Palette_Entry(1, &palette[1]);

 

// animate green

palette[1].peGreen+=green_inc;

 

// check if ready to change animation in other direction

if (palette[1].peGreen > 255 || palette[1].peGreen < 16)

   {

   // invert increment

   green_inc=-green_inc;

   palette[1].peGreen+=green_inc;   

   } // end if

 

// draw the text

Draw_Text_GDI("Press <ESC> to exit.", 8,8,255, lpddsback);

 

// perform the flip

while (FAILED(lpddsprimary->Flip(NULL, DDFLIP_WAIT)));

 

// wait a sec

Sleep(33);

…….

}

 

在初始化里面,弄了个四边形

Game_init()

{

 

// define points of object (must be convex)

VERTEX2DF object_vertices[4] = {-100,-100, 100,-100, 100,100, -100, 100};

 

// initialize polygon object

object.state       = 1;   // turn it on

object.num_verts   = 4; 

object.x0          = SCREEN_WIDTH/2; // position it

object.y0          = SCREEN_HEIGHT/2;

object.xv          = 0;

object.yv          = 0;

object.color       = 1; // animated green

object.vlist       = new VERTEX2DF [object.num_verts];

 

for (int index = 0; index < object.num_verts; index++)

    object.vlist[index] = object_vertices[index];

 

  

// create sin/cos lookup table

 

// generate the tables

for (int ang = 0; ang < 360; ang++)

    {

    // convert ang to radians

    float theta = (float)ang*PI/(float)180;

 

    // insert next entry into table

    cos_look[ang] = cos(theta);

    sin_look[ang] = sin(theta);

 

} // end for ang

.

}

在初始化中,GAME_INIT()已经引入了T3DLIB中的函数,这样很好,不会看错了,

{

.

 

// define points of object (must be convex)

VERTEX2DF object_vertices[4] = {-100,-100, 100,-100, 100,100, -100, 100};

 

// initialize polygon object

object.state       = 1;   // turn it on

object.num_verts   = 4; 

object.x0          = SCREEN_WIDTH/2; // position it

object.y0          = SCREEN_HEIGHT/2;

object.xv          = 0;

object.yv          = 0;

object.color       = 1; // animated green

object.vlist       = new VERTEX2DF [object.num_verts];

 

for (int index = 0; index < object.num_verts; index++)

    object.vlist[index] = object_vertices[index];

 

  

// create sin/cos lookup table

 

// generate the tables

for (int ang = 0; ang < 360; ang++)

    {

    // convert ang to radians

    float theta = (float)ang*PI/(float)180;

 

    // insert next entry into table

    cos_look[ang] = cos(theta);

    sin_look[ang] = sin(theta);

 

} // end for ang

..

}

现在进行封装,简单封装后,改变为成员函数后,为

看看t3dlib中,有一个16位的填充函数

void ddraw_math::Draw_Filled_Polygon2D16(POLYGON2D_PTR poly, UCHAR *vbuffer, int mempitch);

只是添加了

USHORT * vbuffer          = ( USHORT * ) _vbuffer;

mempitch                  = ( mempitch >> 1 );

这两句,进行了转换。

在game_main()中

改为 math.Draw_Filled_Polygon2D16( &object, ddraw->getbackbuffer(), ddraw->getbacklpitch() );

在common,h中,把位数设为16

#define  SCREEN_BPP                             16

OK

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值