📄 btriangle.cpp
字号:
//当前颜色
float fRed = clr1.red + fIncR;
float fGreen = clr1.green + fIncG;
float fBlue = clr1.blue + fIncB;
float fAlpha = clr1.alpha + fIncA;
//填充方向
int nDirection = (x1 < x2) ? 1 : -1;
//当前x坐标
int x = x1 + nDirection;
//当前 z 坐标, z坐标增量,
//注意 我们并没有采用平面系数法计算深度
float z = z1, fIncZ = (z2 - z1) / nFillPixels;
z += fIncZ;
nFillPixels--;
//开始填充
for(int i = 0; i < nFillPixels ; i++)
{
float zInBuffer = pZB->GetDepth(x,nScanLine);
//如果当前点的z坐标小于深度缓冲区中的相同位置z的坐标
if(z < zInBuffer)
{
//在颜色缓冲区中绘制第一个点
pCB->SetPixel(x, nScanLine, fRed, fGreen, fBlue, fAlpha);
//重置深度缓冲区的值
pZB->SetDepth(x, nScanLine, z);
}
//增量计算
x += nDirection;
z += fIncZ;
fRed += fIncR;
fGreen += fIncG;
fBlue += fIncB;
fAlpha += fIncA;
}
}
//扫描转换三角形
//pt1,pt2,pt3------三角形顶点坐标
//z1, z2,z3--------三角形顶点深度
//clr1,clr2,clr3---三角形顶点颜色
//pCB,pZB----------颜色缓冲器和深度缓冲器
void CBTriangle::Draw(POINT pt1, POINT pt2, POINT pt3, float z1, float z2, float z3, FLOATCOLORRGBA clr1, FLOATCOLORRGBA clr2, FLOATCOLORRGBA clr3, CColorBuffer* pCB, CZBuffer* pZB)
{
ASSERT(pCB);
ASSERT(pZB);
//第一部分代码:处理退化情况中的一种情况
//处理退化情况(三点在一条水平直线上)
//尽管 z-buffer算法与绘制顺序一般情况下是无关的,
//但是,当三点在一条扫描线上时,仍然有必要这样处理
if((pt1.y == pt2.y) && (pt2.y == pt3.y))
{
//pt1位于中间(采用矢量点积进行判断)
if((pt2.x - pt1.x) * (pt3.x - pt1.x) <= 0)
{
Scan(pt1.x, pt2.x, pt1.y, z1, z2, clr1, clr2, pCB, pZB);
Scan(pt1.x, pt3.x, pt1.y, z1, z3, clr1, clr3, pCB, pZB);
}
//pt2位于中间
else if((pt1.x - pt2.x) * (pt3.x - pt2.x) <= 0)
{
Scan(pt2.x, pt1.x, pt1.y, z2, z1, clr2, clr1, pCB, pZB);
Scan(pt2.x, pt3.x, pt1.y, z2, z3, clr2, clr3, pCB, pZB);
}
//pt3位于中间
else
{
Scan(pt3.x, pt1.x, pt1.y, z3, z1, clr3, clr1, pCB, pZB);
Scan(pt3.x, pt2.x, pt1.y, z3, z2, clr3, clr2, pCB, pZB);
}
//增加三个端点
float zInBuffer = pZB->GetDepth(pt1.x, pt1.y);
//如果当前点的z坐标小于深度缓冲区中的相同位置z的坐标
if(z1 < zInBuffer)
{
//在颜色缓冲区中绘制第一个点
pCB->SetPixel(pt1.x, pt1.y, clr1.red, clr1.green, clr1.blue, clr1.alpha);
//重置深度缓冲区的值
pZB->SetDepth(pt1.x, pt1.y, z1);
}
//
zInBuffer = pZB->GetDepth(pt2.x, pt2.y);
//如果当前点的z坐标小于深度缓冲区中的相同位置z的坐标
if(z2 < zInBuffer)
{
//在颜色缓冲区中绘制第一个点
pCB->SetPixel(pt2.x, pt2.y, clr2.red, clr2.green, clr2.blue, clr2.alpha);
//重置深度缓冲区的值
pZB->SetDepth(pt2.x, pt2.y, z2);
}
zInBuffer = pZB->GetDepth(pt3.x, pt3.y);
//如果当前点的z坐标小于深度缓冲区中的相同位置z的坐标
if(z3 < zInBuffer)
{
//在颜色缓冲区中绘制第一个点
pCB->SetPixel(pt3.x, pt3.y, clr3.red, clr3.green, clr3.blue, clr3.alpha);
//重置深度缓冲区的值
pZB->SetDepth(pt3.x, pt3.y, z3);
}
return;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
//第二部分代码:处理一般情况
//第一步,排序:
//排序规则:第一个点的y坐标最小,第二个点的y坐标最大,第三个点则位于它们的中间
//顶点和颜色备份
POINT point1 = pt1, point2 = pt2, point3 = pt3;
FLOATCOLORRGBA color1 = clr1, color2 = clr2, color3 = clr3;
float fz1 = z1, fz2 = z2, fz3 = z3;
//point1记录y坐标最小者
if(point1.y > point2.y)
{
point1 = pt2;
point2 = pt1;
color1 = clr2;
color2 = clr1;
fz1 = z2;
fz2 = z1;
}
if(point1.y > point3.y)
{
POINT ptTemp = point1;
FLOATCOLORRGBA clrTemp = color1;
float zTemp = fz1;
point1 = point3;
color1 = color3;
fz1 = fz3;
point3 = ptTemp;
color3 = clrTemp;
fz3 = zTemp;
}
//point2记录y坐标最大者
if(point2.y < point3.y)
{
POINT ptTemp = point2;
FLOATCOLORRGBA clrTemp = color2;
float zTemp = fz2;
point2 = point3;
color2 = color3;
fz2 = fz3;
point3 = ptTemp;
color3 = clrTemp;
fz3 = zTemp;
}
//第二步,获取边界点的 x 坐标,计算边界颜色
//12 --- 1 to 2, 13 ---- 1 to 3, 32 ---- 3 to 2
//y坐标之间的距离
int nDy12 = (point2.y - point1.y) + 1;
int nDy13 = (point3.y - point1.y) + 1;
int nDy32 = (point2.y - point3.y) + 1;
//获取扫描线的 x 坐标
int* pnEdge12 = new int[nDy12];
int* pnEdge13 = new int[nDy13];
int* pnEdge32 = new int[nDy32];
//获取边界颜色
//注意,这里支持透明计算,因而颜色用三个分量
FLOATCOLORRGBA* pClrEdge12 = new FLOATCOLORRGBA[nDy12];
FLOATCOLORRGBA* pClrEdge13 = new FLOATCOLORRGBA[nDy13];
FLOATCOLORRGBA* pClrEdge32 = new FLOATCOLORRGBA[nDy32];
//记录边界深度
float* pfzEdge12 = new float[nDy12];
float* pfzEdge13 = new float[nDy13];
float* pfzEdge32 = new float[nDy32];
//获取边界及其颜色
//计算矢量叉积(只需要计算Z分量),以判断三角形的位置关系
int nDelta = ((point3.x - point1.x) * (point2.y - point3.y)
- (point2.x - point3.x) * (point3.y - point1.y));
if(nDelta > 0)
{
DealEdge(point1.x, point1.y, point2.x, point2.y, fz1, fz2, color1, color2, pCB, pZB, pnEdge12, pClrEdge12, pfzEdge12);
DealEdge(point1.x, point1.y, point3.x, point3.y, fz1, fz3, color1, color3, pCB, pZB, pnEdge13, pClrEdge13, pfzEdge13, G3D_TRIANGLE_ON_LINE_LEFT);
DealEdge(point3.x, point3.y, point2.x, point2.y, fz3, fz2, color3, color2, pCB, pZB, pnEdge32, pClrEdge32, pfzEdge32, G3D_TRIANGLE_ON_LINE_LEFT);
}
else
{
DealEdge(point1.x, point1.y, point2.x, point2.y, fz1, fz2, color1, color2, pCB, pZB, pnEdge12, pClrEdge12, pfzEdge12, G3D_TRIANGLE_ON_LINE_LEFT);
DealEdge(point1.x, point1.y, point3.x, point3.y, fz1, fz3, color1, color3, pCB, pZB, pnEdge13, pClrEdge13, pfzEdge13);
DealEdge(point3.x, point3.y, point2.x, point2.y, fz3, fz2, color3, color2, pCB, pZB, pnEdge32, pClrEdge32, pfzEdge32);
}
//保证最后一个点也能绘制
//这是因为,CPLine基元与Windows绘制直线的方式是一致的,即不绘制最后一个点
float zInBuffer = pZB->GetDepth(point2.x, point2.y);
//如果当前点的z坐标小于深度缓冲区中的相同位置z的坐标
if(fz2 < zInBuffer)
{
//在颜色缓冲区中绘制第一个点
pCB->SetPixel(point2.x, point2.y, color2.red, color2.green, color2.blue, color2.alpha);
//重置深度缓冲区的值
pZB->SetDepth(point2.x, point2.y, fz2);
}
//第三个顶点
if(point3.y == point2.y)
{
zInBuffer = pZB->GetDepth(point3.x, point3.y);
//如果当前点的z坐标小于深度缓冲区中的相同位置z的坐标
if(fz3 < zInBuffer)
{
//在颜色缓冲区中绘制第一个点
pCB->SetPixel(point3.x, point3.y, color3.red, color3.green, color3.blue, color3.alpha);
//重置深度缓冲区的值
pZB->SetDepth(point3.x, point3.y, fz3);
}
}
//第三步,进行扫描填充
//扫描分为两个阶段:
//第一,扫描第一点至第三点之间的区域
//第二,扫描第三点至第二点之间的区域
//当前扫描线的y坐标及扫描计数器
int y, nPlumbScan = 0;
if(point1.y < point3.y)
{
for(y = point1.y; y < point3.y; y++)
{
//一条扫描线的x坐标
int x12 = pnEdge12[nPlumbScan];
int x13 = pnEdge13[nPlumbScan];
//一条扫描线的深度变化
float z12 = pfzEdge12[nPlumbScan];
float z13 = pfzEdge13[nPlumbScan];
//颜色
FLOATCOLORRGBA clrEdge12 = pClrEdge12[nPlumbScan];
FLOATCOLORRGBA clrEdge13 = pClrEdge13[nPlumbScan];
//填充
Scan(x12, x13, y, z12, z13, clrEdge12,clrEdge13, pCB, pZB);
nPlumbScan++;
}//end for y
}//end (point1.y < point3.y)
//第二阶段扫描
//准备数据
//沿边3-2的计数器
int nPlumbScan32 = 0;
for(y = point3.y; y <= point2.y; y++)
{
//一条扫描线的x坐标
int x12 = pnEdge12[nPlumbScan];
int x32 = pnEdge32[nPlumbScan32];
//一条扫描线的深度变化
float z12 = pfzEdge12[nPlumbScan];
float z32 = pfzEdge32[nPlumbScan32];
//颜色
FLOATCOLORRGBA clrEdge12 = pClrEdge12[nPlumbScan];
FLOATCOLORRGBA clrEdge32 = pClrEdge32[nPlumbScan32];
//填充
Scan(x12, x32, y, z12, z32, clrEdge12,clrEdge32, pCB, pZB);
nPlumbScan++;
nPlumbScan32++;
}//end for y
delete[] pnEdge12;
delete[] pnEdge13;
delete[] pnEdge32;
delete[] pClrEdge12;
delete[] pClrEdge13;
delete[] pClrEdge32;
delete[] pfzEdge12;
delete[] pfzEdge13;
delete[] pfzEdge32;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -