《计算机图形学》课内实验报告实验二.docx
《《计算机图形学》课内实验报告实验二.docx》由会员分享,可在线阅读,更多相关《《计算机图形学》课内实验报告实验二.docx(31页珍藏版)》请在冰豆网上搜索。
![《计算机图形学》课内实验报告实验二.docx](https://file1.bdocx.com/fileroot1/2022-11/22/b85e7d8a-e0e2-49cd-be03-bd8b9ba303d2/b85e7d8a-e0e2-49cd-be03-bd8b9ba303d21.gif)
《计算机图形学》课内实验报告实验二
《计算机图形学》
课内实验报告
学生姓名:
及学号:
学院:
理学院
班级:
课程名称:
计算机图形学
实验题目:
基本图形的生成算法
指导教师
姓名及职称:
讲师
讲师
2014年4月1日
目录
一、实验题目1
二、实验目的1
三、实验内容1
四、实验结果2
五、实验体会或遇到问题23
一、实验题目
基本图形的生成算法
二、实验目的
1.通过实验,进一步理解直线段扫描转换的DDA算法、中点bresenham算法及bresenham算法的基本原理;
2.掌握以上算法生成直线段的基本过程;
3.通过编程,会在C/C++环境下完成用DDA算法、中点bresenham算法及bresenham算法对任意直线段的扫描转换。
三、实验内容
1.点的显示与属性
对VC中画点的函数PutPixel与获取点函数GetPixel分别用于在指定位置画指定大小颜色的点或获取指定位置的点的颜色,而在OpenGL中可以用属性选择来控制画点还是画线或多边形等。
在VC中PutPixel的前两个参数为点的坐标位置,后面的参数为颜色属性来实现画点,在OpenGL中位于glbegin和glend之间的是数据点,通过选取glbegin的属性为GL_POINTS则数据点显示为点。
2.常用画线算法与实现
1)DDA算法,按四舍五入法取点的简单算法,编程容易,但计算量大。
2)中点算法,是通过递推确定取点的方法,由于计算加与减,没有乘法运算所以计算量少,是常用的算法,此算法是判断实际点位于相邻两个像素点的中点的上方,如果是则取上边的像点,否则取下边的像素点(当斜率绝对值大于1时按左右取)。
3)实现,可VC中实现以上算法,OpenGL中已有相应函数画线。
3.面的生成与填充
1)用VC实现区域填充中的扫描转换,用图像填充区域以及字符输出等,可用扫描线算法等实现,用OpenGL则可用填充函数及材质设置函数实现优质显示。
2)由面生成空间图形可以用VC的图形变换实现不同角度效果,并用裁剪算法及隐藏面消除算法实现真实感效果,但OpenGL实现则要简单些。
四、实验结果
1.DDA算法画线
图1DDA算法画线
源程序:
#include
#include
#include
#defineROUND(a)((int)(a+0.5))
#defineOX320
#defineOY240
voidlineDDA(intxa,intya,intxb,intyb,intcolor);
voidsetpixel(intx,inty,intcolor);
main(){
intgdrive=DETECT,gmode=0;
initgraph(&gdrive,&gmode,"d:
\\tc");
setbkcolor(BLACK);
line(0,OY,2*OX,OY);
line(OX,0,OX,2*OY);
lineDDA(300,300,0,0,WHITE);
getch();
closegraph();
return0;
}
voidlineDDA(intxa,intya,intxb,intyb,intcolor){
intdx=xb-xa;
intdy=yb-ya;
intsteps,i;
floatxIncrement,yIncrement;
floatx=xa;
floaty=ya;
if(abs(dx)>abs(dy))
steps=abs(dx);
else
steps=abs(dy);
xIncrement=dx/(float)steps;
yIncrement=dy/(float)steps;
putpixel(ROUND(x),ROUND(y),color);
for(i=0;ix+=xIncrement;
y+=yIncrement;
setpixel(ROUND(x),ROUND(y),color);
}
return;
}
voidsetpixel(intx,inty,intcolor){
putpixel(OX+x,OY-y,color);
return;
}
2.中点bresenham算法画线
图2中点算法输入
图3中点算法画线
源程序:
#include
#include
#include
/**********生成直线段的中点算法**********/
voidMidPointLine(intx1,inty1,intx2,inty2,intcolor)
{
floatx,y,dx,dy;
floatk,d;
floatIncrE,IncrNE;
dx=x2-x1;
dy=y2-y1;
k=dy/dx;
if(k>=-1&&k<=1)
{
d=dx-2*dy;
IncrE=-2*dy;
IncrNE=2*(dx-dy);
x=x1;y=y1;
putpixel(x,y,color);
while(x{
if(d>0)
d+=IncrE;
else
{
d+=IncrNE;
y++;
}
x++;
putpixel((int)x,(int)y,color);
}
}
else
{
d=dy-2*dx;
IncrE=-2*dx;
IncrNE=2*(dy-dx);
x=x1;y=y1;
putpixel(x,y,color);
while(y{
if(d>0)
d+=IncrE;
else
{
d+=IncrNE;
x++;
}
y++;
putpixel((int)x,(int)y,color);
}
}
}
/**********主函数**********/
voidmain()
{
intgraphdriver=DETECT,graphmode;
intx1,y1,x2,y2,color;
printf("PleaseInputTwoPixels(x1,y1),(x2,y2):
");
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
printf("InputColorlike'RED'or'WHITE':
");
scanf("%d",&color);
initgraph(&graphdriver,&graphmode,"\\tc");
MidPointLine(x1,y1,x2,y2,color);
outtextxy(x1,y1,"StartPoint");
outtextxy(x2,y2,"EndPoint");
getch();
closegraph();
}
3.bresenham算法画线
图4bresenham算法画线
源程序:
#include
#include
#include
voiddraw_pixel(intix,intiy)
{
glBegin(GL_POINTS);
glVertex2i(ix,iy);
glEnd();
}
voidBresenham(intx1,inty1,intxEnd,intyEnd)
{
intdx=abs(xEnd-x1),dy=abs(yEnd-y1);
intp=2*dy-dx;
inttwoDy=2*dy,twoDyMinusDx=2*dy-2*dx;
intx,y;
if(x1>xEnd)
{
x=xEnd;y=yEnd;
xEnd=x1;
}
else
{
x=x1;
y=y1;
}
draw_pixel(x,y);
while(x{
x++;
if(p<0)
p+=twoDy;
else
{
y++;
p+=twoDyMinusDx;
draw_pixel(x,y);
}
}
}
voiddisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
Bresenham(0,0,400,400);
glFlush();
}
voidmyinit()
{
glClearColor(0.8,1.0,1.0,1.0);
glColor3f(0.0,0.0,1.0);
glPointSize(1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,500.0,0.0,500.0);
}
voidmain(intargc,char**argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(500,500);
glutInitWindowPosition(200.0,200.0);
glutCreateWindow("CG_test_Bresenham_Lineexample");
glutDisplayFunc(display);
myinit();
glutMainLoop();
}
4.扫描线算法填充
图5扫描线算法填充
源程序:
#include
#include
#include
#defineNULL0//C++中没有NULL这个符号常量,这里用宏定义
#defineWINDOW_HEIGHT400//定义窗口高为400
#defineWINDOW_WIDTH400//定义窗口宽为400
structdcPt{//dcPt实际上是一个点的结构体
intx;
inty;
};
voidsetPixel(GLintx,GLinty)//用OpenGL函数改写setPixel
{
glBegin(GL_POINTS);
glVertex2i(x,y);
glEnd();
}
typedefstructtEdge{
intyUpper;
floatxIntersect,dxPerScan;
structtEdge*next;
}Edge;
/*InsertsedgeintolistinorderofincreasingxIntersectfield.*/
voidinsertEdge(Edge*list,Edge*edge)
{
Edge*p,*q=list;
p=q->next;
while(p!
=NULL){
if(edge->xIntersectxIntersect)
p=NULL;
else{
q=p;
p=p->next;
}
}
edge->next=q->next;
q->next=edge;
}
/*Foranindex,returny-coordinateofnextnonhorizontalline*/
intyNext(intk,intcnt,dcPt*pts)
{
intj;
if((k+1)>(cnt-1))
j=0;
else
j=k+1;
while(pts[k].y==pts[j].y)
if((j+1)>(cnt-1))
j=0;
else
j++;
return(pts[j].y);
}
/*Storelower-ycoordinateandinverseslopeforeachedge.Adjustandstoreupper-ycoordinateforedgesthatarethelowermemberofamonoticallyincreasingordecreasingpairofedges*/
voidmakeEdgeRec
(dcPtlower,dcPtupper,intyComp,Edge*edge,Edge*edges[])
{
edge->dxPerScan=
(float)(upper.x-lower.x)/(upper.y-lower.y);
edge->xIntersect=lower.x;
if(upper.yedge->yUpper=upper.y-1;
else
edge->yUpper=upper.y;
insertEdge(edges[lower.y],edge);
}
voidbuildEdgeList(intcnt,dcPt*pts,Edge*edges[])
{
Edge*edge;
dcPtv1,v2;
inti,yPrev=pts[cnt-2].y;
v1.x=pts[cnt-1].x;v1.y=pts[cnt-1].y;
for(i=0;iv2=pts[i];
if(v1.y!
=v2.y){/*nonhorizontalline*/
edge=(Edge*)malloc(sizeof(Edge));
if(v1.ymakeEdgeRec(v1,v2,yNext(i,cnt,pts),edge,edges);
else/*down-goingedge*/
makeEdgeRec(v2,v1,yPrev,edge,edges);
}
yPrev=v1.y;
v1=v2;
}
}
voidbuildActiveList(intscan,Edge*active,Edge*edges[])
{
Edge*p,*q;
p=edges[scan]->next;
while(p){
q=p->next;
insertEdge(active,p);
p=q;
}
}
voidfillScan(intscan,Edge*active)
{
Edge*p1,*p2;
inti;
p1=active->next;
while(p1){
p2=p1->next;
for(i=p1->xIntersect;ixIntersect;i++)
setPixel((int)i,scan);
p1=p2->next;
}
}
voiddeleteAfter(Edge*q)
{
Edge*p=q->next;
q->next=p->next;
free(p);
}
/*Deletecompletededges.Update'xIntersect'fieldforothers*/
voidupdateActiveList(intscan,Edge*active)
{
Edge*q=active,*p=active->next;
while(p)
if(scan>=p->yUpper){
p=p->next;
deleteAfter(q);
}
else{
p->xIntersect=p->xIntersect+p->dxPerScan;
q=p;
p=p->next;
}
}
voidresortActiveList(Edge*active)
{
Edge*q,*p=active->next;
active->next=NULL;
while(p){
q=p->next;
insertEdge(active,p);
p=q;
}
}
voidscanFill(intcnt,dcPt*pts)
{
Edge*edges[WINDOW_HEIGHT],*active;
inti,scan;
for(i=0;iedges[i]=(Edge*)malloc(sizeof(Edge));
edges[i]->next=NULL;
}
buildEdgeList(cnt,pts,edges);
active=(Edge*)malloc(sizeof(Edge));
active->next=NULL;
for(scan=0;scanbuildActiveList(scan,active,edges);
if(active->next){
fillScan(scan,active);
updateActiveList(scan,active);
resortActiveList(active);
Sleep(20);//为了放慢填充速度,便于观看填充过程,每填充一行停顿10毫秒,Sleep函数包含在头文件windows.h里面
}
}
/*Freeedgerecordsthathavebeenmalloc'ed...*/
}
voidinit(void)
{
glClearColor(1.0,1.0,1.0,0.0);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0,WINDOW_WIDTH,0.0,WINDOW_HEIGHT);
}
voidmyDraw(void)
{
dcPtpts[]={//pts是表示填充图元的顶点数组,这里定义了一个六边形
50,50,
300,20,
300,300,
200,100,
150,350,
20,120
};
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,0.0,0.0);
scanFill(6,pts);//第一个参数为填充图元的顶点数,第二个参数为顶点坐标数组
glFlush();
}
voidmain(intargc,char**argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowPosition(50,100);
glutInitWindowSize(WINDOW_WIDTH,WINDOW_HEIGHT);
glutCreateWindow("通用扫描线填充");
init();
glutDisplayFunc(myDraw);
glutMainLoop();
}
5.隐藏面消除算法
图6隐藏面消除算法输入
图7隐藏面消除算法绘图
源程序:
#include
#include
#include
#include
#include
#defineSCAN_NUM500
typedefstructEdge//边Y桶中的边结构
{
intyUpper;//边的最大y值
floatxInt,dx;//边的最低点的x值,之所以是最低点,是因为本程序是从下往上扫描的
intE_mark;
floatz,dzx,dzy;
structEdge*next;//指向下一条边节点的指针
}Edge;
typedefstructpoint//定义一个点的结构体
{
intx;
inty;
floatz;
}point;
externpoint**points=NULL;//存放多个多边形的顶点信息
externfloat**as=NULL;//存放多边形所在平面的方程的四个系数
externint*counts=NULL;//存放各个多边形的顶点个数
externintnum=0;//记录多边形个数
voidDrawPoint(intx,inty)//画点函数
{
:
:
glBegin(GL_POINTS);
:
:
glVertex2d(x,y);
:
:
glEnd();
}
intnexty(intk,intcount,point*pts)//当前测试点的下一个点的纵坐标,其方向为顺时针
{
intj;
if((k+1)>(count-1))
j=0;
elsej=k+1;
while(pts[k].y==pts[j].y)
{
if((j+1)>(count-1))
j=0;
else
j++;
}
returnpts[j].y;
}
voidinsertE