以下摘抄自本人的计算机图形学上机报告
实验内容及要求:
- 理解并掌握中点画线法、Bresenham算法、扫描线法和重心坐标法的基本原理和算法步骤。
- 使用编程语言C++实现上述算法,并编写相应的代码。
- 对于直线绘制算法,要求能够绘制水平、垂直、斜向等不同方向的直线,并观察绘制结果是否符合预期。
- 对于三角形填充绘制算法,要求能够填充任意位置和大小的三角形,并观察填充结果是否完整且没有漏填或重填的情况。
- 编写实验报告,包括实验目的、实验原理、实验步骤、实验结果和实验总结等部分,对实验过程和结果进行详细的描述和分析。
算法思想
本次直线的绘制采用的是中点画线法。
中点画线法的算法原理:
设为 P1与P2之中点,Q为理想直线与 垂线的交点。将Q与M的y坐标进行比较。当M在Q的下方,则P2应为下一个像素点;当M在Q的上方,则P1应为下一个像素点
三角形的绘制采用的是扫描线法和重心坐标法。
扫描线法的算法原理:
- 顶点排序:首先,根据 y 坐标对三角形的三个顶点进行排序。确保 ta 是最下面的顶点,tc 是最上面的顶点,而 tb 则位于中间。
- 计算总高度:计算三角形在 y 轴上的总高度,即 tc.y - ta.y。
- 绘制底部条带:从 ta 到 tb 的 y 坐标范围内,循环遍历每一行(y 值)。对于每一行,计算 A 和 B 两个点的 x 坐标。这两个点位于当前行的扫描线上,并且与三角形的两边相交。然后,从 A 点到 B 点填充像素。如果 A 的 x 坐标大于 B 的 x 坐标,则交换 A 和 B,以确保填充的顺序是正确的。
- 绘制顶部条带:从 tb 到 tc 的 y 坐标范围内,重复与底部条带相同的步骤。
中心坐标法的算法原理:
1.确定边界:
x_max 和 x_min 是三角形在x轴上的最大和最小坐标。
y_max 和 y_min 是三角形在y轴上的最大和最小坐标。
这些边界坐标用来确定需要遍历的像素范围。
2.遍历像素:
使用两个嵌套的 for 循环遍历从 y_min 到 y_max 的每一行,以及从 x_min 到 x_max 的每一列。
3.计算重心坐标:
对于每一个像素点 (x, y),计算其相对于三角形三个顶点的重心坐标 alpha 和 beta。
4.判断像素点是否在三角形内部:
如果 alpha, beta 和 1 - alpha - beta 都大于0,则说明像素点 (x, y) 位于三角形内部
5.绘制像素:
如果像素点 (x, y) 在三角形内部,则调用 draw_pixel 函数将其绘制为给定的颜色 color。
代码说明及实验结果
中点画线算法:
void draw_line(int x1, int y1, int x2, int y2, const TGAColor& color)
{int a, b, delta1, delta2, d, x, y;a = y1 - y2;b = x2 - x1;d = 2 * a + b;delta1 = 2 * a;delta2 = 2 * (a + b);x = x1;y = y1;draw_pixel(x, y, color);while (x < x2){if (d < 0){x++;y++;d += delta2;}else {x++;d += delta1;}draw_pixel(x, y, color);}}
扫描线算法:
void draw_triange2(vec2i ta, vec2i tb, vec2i tc, const TGAColor& color)
{if (ta.y > tb.y) std::swap(ta, tb);if (ta.y > tc.y) std::swap(ta, tc);if (tb.y > tc.y) std::swap(tb, tc);int total_height = tc.y - ta.y;for (int y = ta.y; y < tb.y; ++y) {int segment_height = tb.y - ta.y;float alpha = (float)(y - ta.y) / total_height;float beta = (float)(y - ta.y) / segment_height;vec2i A = ta + (tc - ta) * alpha;vec2i B = ta + (tb - ta) * beta;if (A.x > B.x) std::swap(A, B);for (int j = A.x; j <= B.x; ++j) {draw_pixel(j, y, color);}}for (int y = tb.y; y <= tc.y; ++y) {int segment_height = tc.y - tb.y;float alpha = (float)(y - ta.y) / total_height;float beta = (float)(y - tb.y) / segment_height;vec2i A = ta + (tc - ta) * alpha;vec2i B = tb + (tc - tb) * beta;if (A.x > B.x) std::swap(A, B);for (int j = A.x; j <= B.x; ++j) {draw_pixel(j, y, color);}}
}
重心坐标算法:
void draw_triange1(vec2i ta, vec2i tb, vec2i tc, const TGAColor& color)
{float x,y,alpha, beta;int x_max = max(ta.x, max(tb.x, tc.x));int x_min = min(ta.x, min(tb.x, tc.x));int y_max = max(ta.y, max(tb.y, tc.y));int y_min = min(ta.y, min(tb.y, tc.y));for (y = y_min; y <= y_max; y++) {for (x = x_min; x <= x_max; x++){alpha = (-(x - tb.x) * (tc.y - tb.y) + (y - tb.y) * (tc.x - tb.x)) / (-(ta.x - tb.x) * (tc.y - tb.y) + (ta.y - tb.y) * (tc.x - tb.x));beta = (-(x - tc.x) * (ta.y - tc.y) + (y - tc.y) * (ta.x - tc.x)) / (-(tb.x - tc.x) * (ta.y - tc.y) + (tb.y - tc. y) * (ta.x - tc.x));if (alpha > 0 && beta >0 && 1 - alpha - beta >0){draw_pixel(x, y, color);}}}
}