计算机图形学学习(一)——线的绘制、三角形填充绘制

以下摘抄自本人的计算机图形学上机报告

实验内容及要求:

  1. 理解并掌握中点画线法、Bresenham算法、扫描线法和重心坐标法的基本原理和算法步骤。
  2. 使用编程语言C++实现上述算法,并编写相应的代码。
  3. 对于直线绘制算法,要求能够绘制水平、垂直、斜向等不同方向的直线,并观察绘制结果是否符合预期。
  4. 对于三角形填充绘制算法,要求能够填充任意位置和大小的三角形,并观察填充结果是否完整且没有漏填或重填的情况。
  5. 编写实验报告,包括实验目的、实验原理、实验步骤、实验结果和实验总结等部分,对实验过程和结果进行详细的描述和分析。

算法思想

本次直线的绘制采用的是中点画线法

中点画线法的算法原理:

设为\mathrm{M}=\left(x_{i}+1, y_{i}+0.5\right) P1与P2之中点,Q为理想直线与 x=x_{​{i}}+1 垂线的交点。将Q与M的y坐标进行比较。当M在Q的下方,则P2应为下一个像素点;当M在Q的上方,则P1应为下一个像素点

三角形的绘制采用的是扫描线法重心坐标法

扫描线法的算法原理:

  1. 顶点排序首先,根据 y 坐标对三角形的三个顶点进行排序。确保 ta 是最下面的顶点,tc 是最上面的顶点,而 tb 则位于中间。
  2. 计算总高度:计算三角形在 y 轴上的总高度,即 tc.y - ta.y。
  3. 绘制底部条带:从 ta 到 tb 的 y 坐标范围内,循环遍历每一行(y 值)。对于每一行,计算 A 和 B 两个点的 x 坐标。这两个点位于当前行的扫描线上,并且与三角形的两边相交。然后,从 A 点到 B 点填充像素。如果 A 的 x 坐标大于 B 的 x 坐标,则交换 A 和 B,以确保填充的顺序是正确的。
  4. 绘制顶部条带:从 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);
            }
        }
    }
}
  • 28
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值