Files
2024-11-26 10:51:13 +08:00

389 lines
8.3 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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;i<Width;i++)
{
delete[] zBuffer[i];
zBuffer[i]=NULL;
}
if(zBuffer!=NULL)
{
delete zBuffer;
zBuffer=NULL;
}
ClearMemory();
}
void CZBuffer::SetPoint(CPi3 *p,CVector *n,CT2 *t,int m)
{
P=new CPi3[m];
N=new CVector[m];
T=new CT2[m];
for(int i=0;i<m;i++)
{
P[i]=p[i];
N[i]=n[i];
T[i]=t[i];
}
PNum=m;
}
void CZBuffer::CreateBucket()//创建桶表
{
int yMin,yMax;
yMin=yMax=P[0].y;
for(int i=1;i<PNum;i++)//查找多边形所覆盖的最小和最大扫描线
{
if(P[i].y<yMin)
yMin=P[i].y;//扫描线的最小值
if(P[i].y>yMax)
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;i<PNum;i++)
{
pCurrentB=pHeadB;
int j=(i+1)%PNum;//边的第二个顶点,P[i]和P[j]构成边
if(P[i].y<P[j].y)//边的终点比起点高
{
pEdge=new CAET;
pEdge->x=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].y<P[i].y)//边的终点比起点低
{
pEdge=new CAET;
pEdge->x=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;x<xe;x++)//左闭右开
{
nf=Interpolation(x,xb,xe,na,nb);
tf=Interpolation(x,xb,xe,ta,tb);
COLORREF clr=Image[Round(tf.v)][Round(tf.u)];
CRGB Textureclr=CRGB(GetRValue(clr)/255.0,GetGValue(clr)/255.0,GetBValue(clr)/255.0);
// pMaterial->SetDiffuse(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;i<Count-1;i++)//冒泡排序
{
CAET **pPre=&pHeadE;
pT1=pHeadE;
for(int j=0;j<Count-1-i;j++)
{
pT2=pT1->pNext;
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;i<Width;i++)
zBuffer[i]=new double[Height];
for(i=0;i<Width;i++)//初始化深度缓冲
for(int j=0;j<Height;j++)
zBuffer[i][j]=Depth;
}
void CZBuffer::ClearMemory()
{
DeleteAETChain(pHeadE);
CBucket *pBucket=pHeadB;
while (pBucket !=NULL)//针对每一个桶
{
CBucket * pBucketTemp = pBucket->pNext;
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;
}
}