图形学基础 | 三角形光栅化

从零实现3D图像引擎:(15)三角形的光栅化

1 为什么需要光栅化三角形

  • 不能总让我们的引擎显示线框,要支持实心颜色、光照还有纹理贴图,这些都需要光栅化一个三角形作为支持

2 三角形的类型

在这里插入图片描述

3 平底三角形光栅化

在这里插入图片描述
光栅化平底三角形的原理很简单,就是从上往下画横线。
在图里我们取任意的一条光栅化直线,
这条直线左边的端点x值为XL,右边的为XR。
y值就不用考虑了,因为这些线是从上往下画的,所以y就是从y0一直++,直到y1或者y2。

4. 光栅化平顶三角形

  • 与平底三角形类似

5 光栅化任意三角形

在这里插入图片描述

方法: 将三角形划分为两个三角形. 1) 平底 2) 平顶

每个三角形需要记录的信息:

  1. top
  2. bottom
  3. left直线
  4. right直线

6 具体代码

6.1 拆分三角形

// 将三角形拆成 平三角形
// https://blog.csdn.net/cppyin/article/details/6232453
int trapezoid_init_triangle(trapezoid_t *trap, const vertex_t *p1,
	const vertex_t *p2, const vertex_t *p3) {

	const vertex_t *p;
	float k, x;

	// 排序一下 p1.y<p2.y<p3.y
	if (p1->pos.y > p2->pos.y) p = p1, p1 = p2, p2 = p;
	if (p1->pos.y > p3->pos.y) p = p1, p1 = p3, p3 = p;
	if (p2->pos.y > p3->pos.y) p = p2, p2 = p3, p3 = p;

	// 构不成三角形,返回0
	if (p1->pos.y == p2->pos.y && p1->pos.y == p3->pos.y) return 0;
	if (p1->pos.x == p2->pos.x && p1->pos.x == p3->pos.x) return 0;

	// 平顶,向下的三角形
	if (p1->pos.y == p2->pos.y) {
		// 保证 p1.pos.x<p2.pos.x
		if (p1->pos.x > p2->pos.x) p = p1, p1 = p2, p2 = p;
		trap[0].top = p1->pos.y; // 上面
		trap[0].bottom = p3->pos.y; // 底部
		// 三角形的左边 p1->p3
		trap[0].left.v1 = *p1;
		trap[0].left.v2 = *p3;
		// 三角形的右边 p2->p3
		trap[0].right.v1 = *p2;
		trap[0].right.v2 = *p3;
		return (trap[0].top < trap[0].bottom) ? 1 : 0;
	}

	// 平底三角,向上的三角形
	if (p2->pos.y == p3->pos.y) {
		// 保证 p2.pos.x<p3.pos.x
		if (p2->pos.x > p3->pos.x) p = p2, p2 = p3, p3 = p;
		trap[0].top = p1->pos.y;
		trap[0].bottom = p2->pos.y;
		// 三角形的左边 p1->p2
		trap[0].left.v1 = *p1;
		trap[0].left.v2 = *p2;
		// 三角形的右边 p1->p3
		trap[0].right.v1 = *p1;
		trap[0].right.v2 = *p3;
		return (trap[0].top < trap[0].bottom) ? 1 : 0;
	}

	// 需要对三角形进行划分,0:平底,1:平顶
	trap[0].top = p1->pos.y;
	trap[0].bottom = p2->pos.y;
	trap[1].top = p2->pos.y;
	trap[1].bottom = p3->pos.y;

	k = (p3->pos.y - p1->pos.y) / (p2->pos.y - p1->pos.y);
	x = p1->pos.x + (p2->pos.x - p1->pos.x) * k;

	// 三角形分为右边为主和左边为主
	if (x <= p3->pos.x) {		// 右边为主
		trap[0].left.v1 = *p1;
		trap[0].left.v2 = *p2;
		trap[0].right.v1 = *p1;
		trap[0].right.v2 = *p3;

		trap[1].left.v1 = *p2;
		trap[1].left.v2 = *p3;
		trap[1].right.v1 = *p1;
		trap[1].right.v2 = *p3;
	}
	else {					// 左边为主
		trap[0].left.v1 = *p1;
		trap[0].left.v2 = *p3;
		trap[0].right.v1 = *p1;
		trap[0].right.v2 = *p2;

		trap[1].left.v1 = *p1;
		trap[1].left.v2 = *p3;
		trap[1].right.v1 = *p2;
		trap[1].right.v2 = *p3;
	}
	return 2;
}

6.2 插值三角形

通过扫描线进行插值
从 top 遍历到 bottom j :

  1. 计算出j行上 left 和 right 线上的 两个顶点. 对这个两个顶点进行插值.
  2. 根据左右两边的端点,初始化计算出扫描线的起点和步长
  3. 绘制扫描线.

仅是个人理解的光栅化三角形的一种做法. 具体做法会有很大不同.

// 主渲染函数
	void device_render_trap(trapezoid_t *trap) {
		// 扫描线插值
		scanline_t scanline;
		int j, top, bottom;
		top = (int)(trap->top + 0.5f);
		bottom = (int)(trap->bottom + 0.5f);

		for (j = top; j < bottom; ++j) {
			// 合法
			if (j >= 0 && j < height) {
				// 1 根据 j坐标计算出left和right线上的两个顶点
				trapezoid_edge_interp(trap, (float)j + 0.5f);
				// 2. 根据左右两边的端点,初始化计算出扫描线的起点和步长
				trapezoid_init_scan_line(trap, &scanline, j);
				// 3. 绘制扫描线
				device_draw_scanline(&scanline);
			}
			if (j >= height) break;
		}
	}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
计算机图形学中,光栅化是将几何图形转换为像素的过程,其中三角形光栅化是最常见的操作之一。下面是一个简单的C语言算法来实现三角形光栅化: 1. 首先,我们需要定义一个表示像素的数据结构,可以使用一个二维数组来表示屏幕或画布。 ```c typedef struct { int r, g, b; // 像素的红、绿、蓝分量 } Pixel; // 定义屏幕大小 #define SCREEN_WIDTH 800 #define SCREEN_HEIGHT 600 // 定义屏幕像素数组 Pixel screen[SCREEN_HEIGHT][SCREEN_WIDTH]; ``` 2. 接下来,我们需要定义一个函数来绘制一个三角形。这个函数接受三个顶点的坐标作为参数,并使用扫描线算法来填充三角形内部的像素。 ```c void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3) { // 扫描线算法 // ... } ``` 3. 在`drawTriangle`函数中,我们需要实现扫描线算法来填充三角形内部的像素。具体步骤如下: a. 首先,找到三角形的最小和最大y坐标,确定需要遍历的扫描线范围。 b. 对于每一条扫描线,计算与三角形的交点。 c. 根据交点的x坐标,确定需要填充的像素范围。 d. 在像素范围内,根据插值计算每个像素的颜色,并将其设置为对应的屏幕像素。 ```c void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3) { // 找到最小和最大y坐标 int minY = min(y1, min(y2, y3)); int maxY = max(y1, max(y2, y3)); // 遍历每一条扫描线 for (int y = minY; y <= maxY; y++) { // 计算与三角形的交点 // ... // 确定需要填充的像素范围 int startX = min(x1, min(x2, x3)); int endX = max(x1, max(x2, x3)); // 在像素范围内填充颜色 for (int x = startX; x <= endX; x++) { // 根据插值计算每个像素的颜色 // ... // 设置屏幕像素颜色 screen[y][x].r = red; screen[y][x].g = green; screen[y][x].b = blue; } } } ``` 这是一个简单的三角形光栅化算法的C语言实现。你可以根据需要进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值