计算机图形学实验z-buffer算法

更新时间:2024-05-18 23:28:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

实验六 9-7

一、实验题目

z-buffer算法的代表性案例是绘制三个相互交叉的红绿蓝条,如图9-85所示,请使用MFC编程实现。

二、实验思想

Z-Buffer算法建立两个缓冲器:

深度缓冲器,用以存储图像空间中每一像素相应的深度值,初始化为最大深度值(zs坐标)。

帧缓冲器,用以存储图像空间中的每个像素的颜色,初始化为屏幕的背景色。

① 帧缓冲器初始值置为背景色。

② 确定深度缓冲器的宽度、高度和初始深度。一般将初始深度置为最大深度值。 ③ 对于多边形表面中的每一像素(xs,ys),计算其深度值zs(xs,ys)。

④ 将zs(xs,ys)与存储在z缓冲器中该位置的深度值zBuffer(xs,ys)进行比较。 ⑤ 如果zs(xs,ys)≤zBuffer(xs,ys),则将此像素的颜色写入帧缓冲器,且用z(xs,ys)

重置zbuffer(xs,ys)。

三、实验代码

CZBuffer::~CZBuffer() { }

void CZBuffer::SetPoint(CPi3 p[],int m) {

P=new CPi3[m]; delete []P;

for(int i=0;i

void CZBuffer::CreateBucket()//创建桶表 {

{ } PNum=m;

P[i]=p[i];

}

int yMin,yMax; yMin=yMax=P[0].y;

for(int i=0;i

for(int y=yMin;y<=yMax;y++) { }

if(yMin==y)//建立桶头结点 { }

else//建立桶的其它结点 { }

CurrentB->next=new CBucket; CurrentB=CurrentB->next; CurrentB->ScanLine=y; CurrentB->pET=NULL; CurrentB->next=NULL;

HeadB=new CBucket;//建立桶的头结点

CurrentB=HeadB;//CurrentB为CBucket当前结点指针 CurrentB->ScanLine=yMin;

CurrentB->pET=NULL;//没有连接边链表 CurrentB->next=NULL; if(P[i].y

if(P[i].y>yMax) { }

yMax=P[i].y;//扫描线的最大值 yMin=P[i].y;//扫描线的最小值

void CZBuffer::CreateEdge()//创建边表

{

for(int i=0;i

CurrentB=HeadB;

int j=(i+1)%PNum;//边的第二个顶点,P[i]和P[j]构成边 if(P[i].y

if(P[j].y

if(int(P[j].y)!=P[i].y) {

Edge=new CAET; Edge->x=P[j].x; Edge->yMax=P[i].y;

Edge->k=(P[i].x-P[j].x)/(P[i].y-P[j].y); Edge->pb=P[i]; Edge->pe=P[j]; Edge->next=NULL;

while(CurrentB->ScanLine!=P[j].y) { }

CurrentB=CurrentB->next; Edge=new CAET;

Edge->x=P[i].x;//计算ET表的值 Edge->yMax=P[j].y;

Edge->k=(P[j].x-P[i].x)/(P[j].y-P[i].y);//代表1/k Edge->pb=P[i];//绑定顶点和颜色 Edge->pe=P[j]; Edge->next=NULL;

while(CurrentB->ScanLine!=P[i].y)//在桶内寻找该边的yMin { }

CurrentB=CurrentB->next;//移到yMin所在的桶结点

}

}

}

CurrentE=CurrentB->pET; if(CurrentE==NULL) { } else { }

while(CurrentE->next!=NULL) { }

CurrentE->next=Edge;

CurrentE=CurrentE->next; CurrentE=Edge; CurrentB->pET=CurrentE;

void CZBuffer::Gouraud(CDC *pDC)//填充多边形 {

double CurDeep=0.0;//当前扫描线的深度

double DeepStep=0.0;//当前扫描线随着x增长的深度步长 double A,B,C,D;//平面方程Ax+By+Cz+D=0的系数 CVector V21(P[1],P[2]),V10(P[0],P[1]); CVector VN=V21*V10; A=VN.X();B=VN.Y();C=VN.Z(); D=-A*P[1].x-B*P[1].y-C*P[1].z;

DeepStep=-A/C;//计算直线deep增量步长 CAET *T1,*T2; HeadE=NULL;

for(CurrentB=HeadB;CurrentB!=NULL;CurrentB=CurrentB->next) {

for(CurrentE=CurrentB->pET;CurrentE!=NULL;CurrentE=CurrentE->next) {

Edge=new CAET;

}

Edge->x=CurrentE->x; Edge->yMax=CurrentE->yMax; Edge->k=CurrentE->k; Edge->pb=CurrentE->pb; Edge->pe=CurrentE->pe; Edge->next=NULL; AddEt(Edge);

EtOrder(); T1=HeadE; if(T1==NULL) { }

return;

while(CurrentB->ScanLine>=T1->yMax)//下闭上开 { }

if(T1->next!=NULL) { }

while(T1!=NULL) {

if(CurrentB->ScanLine>=T1->yMax)//下闭上开 { } else {

T2->next=T1->next; T1=T2->next; T2=T1; T1=T2->next; T1=T1->next; HeadE=T1; if(HeadE==NULL)

return;

}

}

T2=T1; T1=T2->next;

CRGB Ca,Cb,Cf;//Ca、Cb代边上任意点的颜色,Cf代表面上任意点的颜色

Ca=Interpolation(CurrentB->ScanLine,HeadE->pb.y,HeadE->pe.y,HeadE->pb.c,HeadE->pe.c);

Cb=Interpolation(CurrentB->ScanLine,HeadE->next->pb.y,HeadE->next->pe.y,HeadE->next->

pb.c,HeadE->next->pe.c);

BOOL Flag=FALSE;

double xb,xe;//扫描线的起点和终点坐标 for(T1=HeadE;T1!=NULL;T1=T1->next) {

if(Flag==FALSE) { } else {

xe=T1->x;

for(double x=xb;x

Cf=Interpolation(x,xb,xe,Ca,Cb);

if(CurDeep>=ZB[ROUND(x)+Width/2][CurrentB->ScanLine+Height/2])//xb=T1->x;

CurDeep=-(xb*A+CurrentB->ScanLine*B+D)/C;//z=-(Ax+By-D)/C Flag=TRUE;

如果新采样点的深度大于原采样点的深度

{

ZB[ROUND(x)+Width/2][CurrentB->ScanLine+Height/2]=CurDeep;//xy坐标与数组下标保持

一致

pDC->SetPixel(ROUND(x),CurrentB->ScanLine,RGB(Cf.red*255,Cf.green*255,Cf.blue*255));

}

}

}

}

}

}

CurDeep+=DeepStep;

Flag=FALSE;

for(T1=HeadE;T1!=NULL;T1=T1->next)//边的连续性 { }

T1->x=T1->x+T1->k;

delete HeadB; delete HeadE; delete CurrentE; delete CurrentB; delete Edge;

void CZBuffer::AddEt(CAET *NewEdge)//合并ET表 { }

CAET *CE; CE=HeadE; if(CE==NULL) { } else { }

while(CE->next!=NULL) { }

CE->next=NewEdge;

CE=CE->next; HeadE=NewEdge; CE=HeadE;

void CZBuffer::EtOrder()//边表的冒泡排序算法 {

CAET *T1,*T2; int Count=1; T1=HeadE; if(T1==NULL) { }

if(T1->next==NULL)//如果该ET表没有再连ET表 { }

while(T1->next!=NULL)//统计结点的个数 { }

for(int i=1;i

T1=HeadE;

if(T1->x>T1->next->x)//按x由小到大排序 { } else {

if(T1->x==T1->next->x) {

if(T1->k>T1->next->k)//按斜率由小到大排序 {

T2=T1->next;

T2=T1->next;

T1->next=T1->next->next; T2->next=T1; HeadE=T2; Count++; T1=T1->next;

return;//桶结点只有一条边,不需要排序 return;

}

}

}

}

}

T1->next=T1->next->next; T2->next=T1; HeadE=T2;

T1=HeadE;

while(T1->next->next!=NULL) { }

T2=T1; T1=T1->next;

if(T1->x>T1->next->x)//按x由小到大排序 { } else { }

if(T1->x==T1->next->x) { }

if(T1->k>T1->next->k)//按斜率由小到大排序 { }

T2->next=T1->next; T1->next=T1->next->next; T2->next->next=T1; T1=T2->next;

T2->next=T1->next; T1->next=T1->next->next; T2->next->next=T1; T1=T2->next;

CRGB CZBuffer::Interpolation(double t,double t1,double t2,CRGB c1,CRGB c2)//线性插值 { }

void CZBuffer::InitDeepBuffer(int width,int height,double depth)//初始化深度缓冲 { }

Width=width,Height=height; ZB=new double *[Width]; for(int i=0;i

ZB[i]=new double[Height]; CRGB c;

c=(t-t2)/(t1-t2)*c1+(t-t1)/(t2-t1)*c2; return c;

for(i=0;i

for(int j=0;j

ZB[i][j]=double(depth);

四、程序结果截图

本文来源:https://www.bwwdw.com/article/qa17.html

Top