手写光栅化渲染器之三角形和插值

手写光栅化渲染器之三角形和插值

环境:20200520版EasyX,vs2019

项目地址:https://github.com/zsybh1/EasyX-Based-Renderer

目标:使用EasyX编写一个光栅化渲染器,实现三角形的显示和插值

基本没有参考什么资料,可能一些解决方案和一般方法不太一样,仅供参考

主要思路:建立数据结构 -> 建立视角模型 -> 投影三角形顶点 -> 映射到实际窗口 -> 插值绘制

建立数据结构

vec3向量类,pos坐标类,实现简单的向量和点的运算

color颜色类,实现颜色的加法、乘法,方便插值

tricolor_triangle带色三角形类,用三个pos和对应的三个color描述一个三角形

建立视角模型

一个视点COP和一个视图窗口,物体和COP连线在视窗上的交集即为投影。为了简单起见,取平面为z=0

手写光栅化渲染器之三角形和插值_第1张图片

投影三角形顶点

令视点COP在点e,COP到三角形某一顶点的向量为d,向量和视窗的交点为p,有方程
e + t d = p e+td=p e+td=p
其中pz=0,可得 t = − z z ′ t=-\frac{z}{z'} t=zz,代入方程求得p

映射到实际窗口

在视窗上选取一块区域,投影到程序窗口上进行显示

有多种选取方式,我选择的是将上面计算出来的坐标p放大500倍显示在窗口上

插值绘制

需要对于窗口上的指定像素,判断是否存在于三角形内部,并给出三个顶点对这个像素的贡献系数

令投影在窗口上的三个顶点分别为ABC,要计算的像素为P

A P ⃗ = u A B ⃗ + v A C ⃗ \vec{AP}=u\vec{AB}+v\vec{AC} AP =uAB +vAC

当满足 u ≥ 0 , v ≥ 0 , u + v ≤ 1 u\ge0,v\ge 0,u+v\le1 u0,v0,u+v1时,P在三角形ABC内

该方程可以从x和y两个维度展开成二元一次方程组,运用克莱姆法则可得到解

此时 1 − u − v , u , v 1-u-v,u,v 1uv,u,v分别为A, B, C对P的贡献系数

将贡献系数分别乘以每个点的颜色,即可计算出指定像素P的颜色

为了遍历的效率,可以取得三个顶点的X、Y坐标的最大最小值,然后在这个矩形中遍历每个像素对方程求解

主体代码如下:

void draw_tricolor_triangle(const tricolor_triangle &tri, const pos &e) {
	const pos *r[3] = { &tri.A,&tri.B,&tri.C };
	pos p[3];
	for (int j = 0; j < 3; ++j) {
		//映射顶点到视窗
		float t = -r[j]->z / e.z;
		float x = e.x + t * r[j]->x;
		float y = e.y + t * r[j]->y;
		//将视窗映射到窗口像素
		p[j].x = int(x * 500);
		p[j].y = int(y * 500);
	}
	//计算包围三角形的最小轴对齐矩形
	int maxX = max(max(p[0].x, p[1].x), p[2].x);
	int maxY = max(max(p[0].y, p[1].y), p[2].y);
	int minX = min(min(p[0].x, p[1].x), p[2].x);
	int minY = min(min(p[0].y, p[1].y), p[2].y);

	vec3 vec[3] = { vec3(),p[1] - p[0], p[2] - p[0] };
	for (int i = maxY; i >= minY; --i) {
		for (int j = minX; j <= maxX; ++j) {
			//遍历每个像素,计算像素是否在三角形内
			vec[0] = pos(j, i, 0) - p[0];
			float M = vec[1].x * vec[2].y - vec[2].x * vec[1].y;
			float v = (vec[1].x * vec[0].y - vec[0].x * vec[1].y) / M;
			float u = -(vec[2].x * vec[0].y - vec[0].x * vec[2].y) / M;
			if (0 <= u  && 0 <= v && u+v <= 1) {
				//如果在,则插值上色
				color Color = tri.Acolor * (1 - u - v) + tri.Bcolor * u + tri.Ccolor * v;
				putpixel(j, i, Color.getBGR());
			}
		}
	}
}

最后完成的效果如图所示

手写光栅化渲染器之三角形和插值_第2张图片

你可能感兴趣的:(手写光栅化渲染器之三角形和插值)