三角形光栅化算法

本文介绍三角形光栅化,大多数软光栅都是以绘制三角面片为基础。
这里介绍经典的拆分法:
如下图所示,所有三角形可以被分类成这三种:
1.朝下的两个点y值相同
2.朝上的两个点y值相同
3.其它的任意三角形(但是拆分成1和2类型两个三角形)
1665494158668
从而,我们可以知道,只要会画1和2这两类三角形,我们就可以通过组合,画出任意三角形!
接下来就介绍下如何画出第1类三角形。
1665495793379
第2类和第1类基本一样,就不写了,直接介绍最后的任意三角形绘制:
我们发现要想用画1和2类三角形的方法画任意三角形的时候,还缺了一个点,组成两个三角形。所以我们还需要确定第四个点v4的位置:
IMG_20221011_214705
1665496210988
这里的证明都是初中几何知识,简单但是最好自己画一下。
得到了第4个点的坐标就可以用前面画1和2类三角形的函数画出整个三角形了!

void DrawTopFlatTriangle(const Vec& v1, const Vec& v2, const Vec& v3, const Color& color)
{
   double XL = v1.x, XR = v1.x;
   double dX1 = -(v2.x - v1.x) / (v2.y - v1.y), dX2 = -(v3.x - v1.x) / (v3.y - v1.y);
   double ZL = v1.z, ZR = v1.z;
   double dZ1 =- (v2.z - v1.z) / (v2.y - v1.y), dZ2 =- (v3.z - v1.z) / (v3.y - v1.y);
   if (round(v1.y) - round(v2.y) <= 1) {
   	DrawScanLine(XL, ZL, XR, ZR, round(v1.y), color);
   	return;
   }
   for (int y =round( v1.y); y > v2.y; y--)
   {
   	DrawScanLine(XL, ZL, XR, ZR, y, color);
   	XL += dX1;
   	XR += dX2;
   	ZL += dZ1;
   	ZR += dZ2; 
   }
}

void DrawBottomFlatTriangle(const Vec& v1, const Vec& v2, const Vec& v3, const Color& color)
{


   double XL = v1.x, XR = v1.x;
   double dX1 = (v2.x - v1.x) / (v2.y - v1.y), dX2 = (v3.x - v1.x) / (v3.y - v1.y);
   double ZL = v1.z, ZR = v1.z;
   double dZ1 = (v2.z - v1.z) / (v2.y - v1.y), dZ2 = (v3.z - v1.z) / (v3.y - v1.y);
   if (round(v2.y) - round(v1.y) <= 1) {
   	DrawScanLine(XL, ZL, XR, ZR, round(v1.y), color);
   	return;
   }
   for (int y = round(v1.y); y <v2.y; y++)
   {
   	DrawScanLine(XL, ZL, XR, ZR, y, color);
   	XL += dX1;
   	XR += dX2;
   	ZL += dZ1;
   	ZR += dZ2;
   }
}

void DrawTriangle(const Vec& v1, const Vec& v2, const Vec& v3, const Color& color)
{
   //按y值从小到大排序3个顶点
   Vec V[3] = { v1,v2,v3 };
   int maxIndex=0, minIndex = 0;
   Vec maxV = v1, minV = v1,midV=v1;
   for (int i = 0; i < 3; i++)
   {
   	if (V[i].y < minV.y)
   	{
   		minIndex = i;
   		minV = V[i];
   	}
   	if (V[i].y > maxV.y)
   	{
   		maxIndex = i;
   		maxV = V[i];
   	}
   }
   int midIndex;
   for (int i = 0; i < 3; i++) {
   	if (i == maxIndex || i == minIndex) {
   		continue;
   	}
   	else {
   		midIndex = i;
   		midV = V[i];
   		
   	}
   }
   Vec V1 = minV, V2 = midV, V3 = maxV;
   V1.x = (int)V1.x; V1.y = (int)V1.y;
   V2.x = (int)V2.x; V2.y = (int)V2.y;
   V3.x = (int)V3.x; V3.y = (int)V3.y;

   if (V1.y == V2.y) {
   	 DrawTopFlatTriangle(V3, V1, V2, color);
   }
   else if (V2.y == V3.y) {
   	DrawBottomFlatTriangle(V1, V3, V2, color);
   }
   else {
   	Vec V4;
   	V4.y = V2.y;
   	V4.x = V1.x + (V4.y - V1.y) / (V3.y - V1.y) * (V3.x - V1.x);
   	V4.z = V1.z + (V4.y - V1.y) / (V3.y - V1.y) * (V3.z - V1.z);

   	DrawBottomFlatTriangle(V1, V2, V4, color);
   	DrawScanLine(V2.x, V2.z, V4.x, V4.z, V2.y, color);
   	DrawTopFlatTriangle(V3, V2, V4, color);

   }

}

下面附上用这个三角形光栅化算法画的兔子!
20221011215425

展示评论