// ZBuffer.cpp: implementation of the CZBuffer class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "Test.h" #include "ZBuffer.h" #include "math.h" #define Round(d) int(floor(d+0.5)) #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CZBuffer::CZBuffer() { P=NULL; N=NULL; T=NULL; pHeadE=NULL; pCurrentB=NULL; pEdge=NULL; pCurrentE=NULL; pHeadB=NULL; zBuffer=NULL; } CZBuffer::~CZBuffer() { for(int i=0;iyMax) yMax=P[i].y;//扫描线的最大值 } for(int y=yMin;y<=yMax;y++) { if(yMin==y)//建立桶头结点 { pHeadB=new CBucket;//建立桶的头结点 pCurrentB=pHeadB;//pCurrentB为CBucket当前结点指针 pCurrentB->ScanLine=yMin; pCurrentB->pET=NULL;//没有链接边表 pCurrentB->pNext=NULL; } else//其他扫描线 { pCurrentB->pNext=new CBucket;//建立桶的其他结点 pCurrentB=pCurrentB->pNext; pCurrentB->ScanLine=y; pCurrentB->pET=NULL; pCurrentB->pNext=NULL; } } } void CZBuffer::CreateEdge()//创建边表 { for(int i=0;ix=P[i].x;//计算ET表的值 pEdge->yMax=P[j].y; pEdge->k=(P[j].x-P[i].x)/(P[j].y-P[i].y);//代表1/k pEdge->ps=P[i];//绑定顶点和颜色 pEdge->pe=P[j]; pEdge->ns=N[i];//绑定法矢量 pEdge->ne=N[j]; pEdge->ts=T[i];//绑定纹理 pEdge->te=T[j]; pEdge->pNext=NULL; while(pCurrentB->ScanLine!=P[i].y)//在桶内寻找该边的yMin { pCurrentB=pCurrentB->pNext;//移到yMin所在的桶结点 } } if(P[j].yx=P[j].x; pEdge->yMax=P[i].y; pEdge->k=(P[i].x-P[j].x)/(P[i].y-P[j].y); pEdge->ps=P[i]; pEdge->pe=P[j]; pEdge->ns=N[i]; pEdge->ne=N[j]; pEdge->ts=T[i]; pEdge->te=T[j]; pEdge->pNext=NULL; while(pCurrentB->ScanLine!=P[j].y) { pCurrentB=pCurrentB->pNext; } } if(int(P[j].y)!=P[i].y) { pCurrentE=pCurrentB->pET; if(pCurrentE==NULL) { pCurrentE=pEdge; pCurrentB->pET=pCurrentE; } else { while(pCurrentE->pNext!=NULL) { pCurrentE=pCurrentE->pNext; } pCurrentE->pNext=pEdge; } } } } void CZBuffer::Phong(CDC *pDC,CP3 ViewPoint,CLighting *pLight,CMaterial *pMaterial,COLORREF **Image)//填充多边形 { double z=0.0;//当前扫描线的z double zStep=0.0;//当前扫描线随着x增长的z步长 double A,B,C,D;//平面方程Ax+By+Cz+D=0的系数 CVector V01(P[0],P[1]),V02(P[0],P[2]); CVector VN=Cross(V01,V02); A=VN.x;B=VN.y;C=VN.z; D=-A*P[0].x-B*P[0].y-C*P[0].z; zStep=-A/C;//计算直线z增量 CAET *pT1,*pT2; pHeadE=NULL; for(pCurrentB=pHeadB;pCurrentB!=NULL;pCurrentB=pCurrentB->pNext) { for(pCurrentE=pCurrentB->pET;pCurrentE!=NULL;pCurrentE=pCurrentE->pNext) { pEdge=new CAET; pEdge->x=pCurrentE->x; pEdge->yMax=pCurrentE->yMax; pEdge->k=pCurrentE->k; pEdge->ps=pCurrentE->ps; pEdge->pe=pCurrentE->pe; pEdge->ns=pCurrentE->ns; pEdge->ne=pCurrentE->ne; pEdge->ts=pCurrentE->ts; pEdge->te=pCurrentE->te; pEdge->pNext=NULL; AddEt(pEdge); } ETOrder(); pT1=pHeadE; if(pT1==NULL) return; while(pCurrentB->ScanLine>=pT1->yMax)//下闭上开 { CAET * pAETTEmp=pT1; pT1=pT1->pNext; delete pAETTEmp; pHeadE=pT1; if(pHeadE==NULL) return; } if(pT1->pNext!=NULL) { pT2=pT1; pT1=pT2->pNext; } while(pT1!=NULL) { if(pCurrentB->ScanLine>=pT1->yMax)//下闭上开 { CAET* pAETTemp =pT1; pT2->pNext=pT1->pNext; pT1=pT2->pNext; delete pAETTemp; } else { pT2=pT1; pT1=pT2->pNext; } } CVector na,nb,nf;//na、nb代表边上任意点的法矢量,nf代表面上任意点的法矢量 na=Interpolation(pCurrentB->ScanLine,pHeadE->ps.y,pHeadE->pe.y,pHeadE->ns,pHeadE->ne); nb=Interpolation(pCurrentB->ScanLine,pHeadE->pNext->ps.y,pHeadE->pNext->pe.y,pHeadE->pNext->ns,pHeadE->pNext->ne); CT2 ta,tb,tf;//ta和tb代表边上任意点的纹理,tf代表面上任意点的纹理 ta=Interpolation(pCurrentB->ScanLine,pHeadE->ps.y,pHeadE->pe.y,pHeadE->ts,pHeadE->te); tb=Interpolation(pCurrentB->ScanLine,pHeadE->pNext->ps.y,pHeadE->pNext->pe.y,pHeadE->pNext->ts,pHeadE->pNext->te); BOOL bInFlag=FALSE;//区间内外测试标志,初始值为假表示区间外部 double xb,xe;//扫描线和有效边相交区间的起点和终点坐标 for(pT1=pHeadE;pT1!=NULL;pT1=pT1->pNext) { if(FALSE==bInFlag) { xb=pT1->x; z=-(xb*A+pCurrentB->ScanLine*B+D)/C;//z=-(Ax+By+D)/C bInFlag=TRUE; } else { xe=pT1->x; for(double x=xb;xSetDiffuse(Textureclr);//用纹理颜色作为材质的漫反射光反射率 //pMaterial->SetAmbient(Textureclr);//用纹理颜色作为材质的环境光反射率 CRGB c=Textureclr;//pLight->Lighting(ViewPoint,CP3(Round(x),pCurrentB->ScanLine,z),nf,pMaterial); if(z<=zBuffer[Round(x)+Width/2][pCurrentB->ScanLine+Height/2])//如果新采样点的深度小于原采样点的深度 { zBuffer[Round(x)+Width/2][pCurrentB->ScanLine+Height/2]=z;//xy坐标与数组下标保持一致 pDC->SetPixelV(Round(x),pCurrentB->ScanLine,RGB(c.red*255,c.green*255,c.blue*255)); } z+=zStep; } bInFlag=FALSE; } } for(pT1=pHeadE;pT1!=NULL;pT1=pT1->pNext)//边的连续性 pT1->x=pT1->x+pT1->k; } } void CZBuffer::AddEt(CAET *pNewEdge)//合并ET表 { CAET *pCE; pCE=pHeadE; if(pCE==NULL) { pHeadE=pNewEdge; pCE=pHeadE; } else { while(pCE->pNext!=NULL) { pCE=pCE->pNext; } pCE->pNext=pNewEdge; } } void CZBuffer::ETOrder()//边表的冒泡排序算法 { CAET *pT1,*pT2; int Count=1; pT1=pHeadE; if(pT1==NULL) return; if(pT1->pNext==NULL)//如果该ET表没有再连ET表 return;//桶结点只有一条边,不需要排序 while(pT1->pNext!=NULL)//统计边结点的个数 { Count++; pT1=pT1->pNext; } for(int i=0;ipNext; if ((pT1->x>pT2->x)||((pT1->x==pT2->x)&&(pT1->k>pT2->k))) { pT1->pNext=pT2->pNext; pT2->pNext=pT1; *pPre=pT2; pPre=&(pT2->pNext);//调整位置为下次遍历准备 } else { pPre=&(pT1->pNext); pT1=pT1->pNext; } } } } CRGB CZBuffer::Interpolation(double t,double t1,double t2,CRGB clr1,CRGB clr2)//颜色线性插值 { CRGB color; color=(t-t2)/(t1-t2)*clr1+(t-t1)/(t2-t1)*clr2; return color; } CVector CZBuffer::Interpolation(double t,double t1,double t2,CVector vec1,CVector vec2)//矢量线性插值 { CVector vector; vector=(t-t2)/(t1-t2)*vec1+(t-t1)/(t2-t1)*vec2; return vector; } CT2 CZBuffer::Interpolation(double t,double t1,double t2,CT2 tex1,CT2 tex2)//纹理线性插值 { CT2 texture; texture=(t-t2)/(t1-t2)*tex1+(t-t1)/(t2-t1)*tex2; return texture; } void CZBuffer::InitDeepBuffer(int Width,int Height,double Depth)//初始化深度缓冲 { int i; this->Width=Width,this->Height=Height; zBuffer=new double *[Width]; for(int i=0;ipNext; DeleteAETChain(pBucket->pET); delete pBucket; pBucket=pBucketTemp; } pHeadB=NULL; pHeadE=NULL; if(P!=NULL) { delete []P; P=NULL; } if(N!=NULL) { delete []N; N=NULL; } if (T!=NULL) { delete []T; T=NULL; } } void CZBuffer::DeleteAETChain(CAET* pAET) { while (pAET!=NULL) { CAET* pAETTemp=pAET->pNext; delete pAET; pAET=pAETTemp; } }