运行结果:


源码:
#include "tgaimage.h"
#include "model.h"
#include "geometry.h"
#include <iostream>
#include <map>
using namespace std;
const int width = 500;
const int height = 500;
// 上一节[画线]的函数
void line_rough(int x0, int y0, int x1, int y1, TGAImage& image, TGAColor& color)
{
int d_x = x1 - x0;// x的公差
int d_y = y1 - y0;// y的公差
float X, Y;
for (float q = 0.; q < 1; q += 0.01)
{
X = x0 + q * d_x;
Y = y0 + q * d_y;
image.set(X, Y, color);
}
}
#pragma region LESSON 2
// 声明直线方程的两个变量k,b。
// 比如k_p0p2是指直线p0p2的斜率
float k_p0p2, b_p0p2, k_p0p1, b_p0p1, k_p1p2, b_p1p2;
// 声明循环控制变量i,j
int i, j;
// 扫描线算法优化版
// 优化点:将绘制算法从bresenham算法改成了line_rough(),运行速度提升1000%
// 优化点:去除了上一版的繁琐计算,引入两个数组保存计算结果。
void saomiaoxiansuanfa_160802192023(Vec2i p0, Vec2i p1, Vec2i p2, TGAImage& image, TGAColor color)
{
// 保证p0是最高的点
if (p1.y > p0.y) swap(p1, p0);
if (p2.y > p0.y) swap(p2, p0);
// 保证p1在中间
if (p2.y > p1.y) swap(p2, p1);
// 求直线P0P2方程式
k_p0p2 = 1.0 * (p0.y - p2.y) / (p0.x - p2.x);
b_p0p2 = p2.y - k_p0p2 * p2.x;
// 求直线P0P1方程式
k_p0p1 = 1.0 * (p0.y - p1.y) / (p0.x - p1.x);
b_p0p1 = p0.y - k_p0p1 * p0.x;
// 求直线P1P2方程式
k_p1p2 = 1.0 * (p1.y - p2.y) / (p1.x - p2.x);
b_p1p2 = p1.y - k_p1p2 * p1.x;
// 保存两点的坐标的集合
vector<vector<float>> memo1, memo2;
// 计算直线Y与上半块三角形的交点
for (int Y = p0.y; Y >= p1.y; --Y)
{
memo1.push_back({ (Y - b_p0p1) / k_p0p1 , (Y - b_p0p2) / k_p0p2 });
}
// 使用两点绘制算法去绘制三角形
i = 0;
for (int Y = p0.y; Y >= p1.y; --Y)
{
line_rough(memo1[i][0], Y, memo1[i][1], Y, image, color);
i++;
}
// 计算直线Y与下半块三角形的交点
for (int Y = p1.y; Y >= p2.y; --Y)
{
memo2.push_back({ (Y - b_p1p2) / k_p1p2 , (Y - b_p0p2) / k_p0p2 });
}
// 使用两点绘制算法去绘制三角形
j = 0;
for (int Y = p1.y; Y >= p2.y; --Y)
{
line_rough(memo2[j][0], Y, memo2[j][1], Y, image, color);
j++;
}
}
int main()
{
TGAImage image(width, height, TGAImage::RGB);
Model* model = NULL;
model = new Model("african_head.obj");
for (int i = 0; i < model->nfaces(); i++) {
vector<int> face = model->face(i);
Vec2i screen_coords[3];
for (int j = 0; j < 3; j++) {
Vec3f world_coords = model->vert(face[j]);
screen_coords[j] = Vec2i((world_coords.x + 1.) * width / 2., (world_coords.y + 1.) * height / 2.);
}
saomiaoxiansuanfa_160802192023(screen_coords[0], screen_coords[1], screen_coords[2], image, TGAColor(rand() % 255, rand() % 255, rand() % 255, 255));
}
image.write_tga_file("african_head_saomiaoxian.tga");
}
#pragma endregion
这段代码实现了一个扫描线算法,用于在给定的三角形内绘制水平线段。首先将三角形的三个点按照y值的大小排序,然后分别求出三条直线的方程式,将每个y坐标对应的两个x坐标保存在memo1和memo2两个二维数组中,最后依次使用line_rough函数绘制每条水平线段。该算法进行了两次优化:一是将绘制算法从bresenham算法改为了line_rough,二是引入了memo1和memo2两个数组,避免了重复的计算。
源模型:
运行结果图片: