您的位置:首页 > 其它

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

2013-12-27 18:11 239 查看

首先,介绍了一种算法,就是
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: