GAMES101-现代计算机图形学学习笔记(作业02)

参考:https://blog.csdn.net/qq_36242312/article/details/105758619

思路
①三角形栅格算法

作业要求已经给出了*rasterize_triangle()*函数的工作流程:

创建三角形的 2 维 bounding box。
遍历此 bounding box 内的所有像素(使用其整数索引)。然后,使用像素中心的屏幕空间坐标来检查中心点是否在三角形内。
如果在内部,则将其位置处的插值深度值 (interpolated depth value) 与深度 缓冲区 (depth buffer) 中的相应值进行比较。
如果当前点更靠近相机,请设置像素颜色并更新深度缓冲区 (depth buffer)。
老师这里要求实现的是Barycentric Algorithm(三角形栅格化),下面几个点可能需要注意一下:
①寻找三角形的bounding box:根据三角形的三个坐标,找出最大x,最小x,最大y,最小y坐标即可,注意最小x,y坐标需要取比原数小,最大x,y坐标需要取比原数大
②点是否在三角形内:只需要连接点和三角形个点,形成一系列向量,然后判断它们的叉乘结果的z值是否统一即可
③MSAA 4X 深度:把一个点看成一个格子,判断里面4个小点是否落在三角形内,然后找到其中插值的最小z值,和帧缓冲中的z值进行比较替换即可。
③MSAA 4X 颜色:
判断有4个小点中有几个小点落入三角形,然后按比例对颜色进行采样即可。

光栅化函数:

//Screen space rasterization
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
    //v进行转换后是std::array,不能直接&来获取,作为数组的指针
    auto v = t.toVector4();

	// bounding box
	float min_x = std::min(v[0][0], std::min(v[1][0], v[2][0]));
    float max_x = std::max(v[0][0], std::max(v[1][0], v[2][0]));
	float min_y = std::min(v[0][1], std::min(v[1][1], v[2][1]));
	float max_y = std::max(v[0][1], std::max(v[1][1], v[2][1]));
   //hero:将bounding box扩展一点,将坐标取整为索引(每个像素都是一个有面积的矩形)
	min_x = (int)std::floor(min_x);
	max_x = (int)std::ceil(max_x);
	min_y = (int)std::floor(min_y);
	max_y = (int)std::ceil(max_y);

	bool MSAA = false;
	//MSAA 4X
	if (MSAA) {
		// 格子里的细分四个小点坐标
		std::vector<Eigen::Vector2f> pos
		{
			{0.25,0.25},
			{0.75,0.25},
			{0.25,0.75},
			{0.75,0.75},
		};
//hero:以下遍历screen的像素,x,y这里相当于像素的索引(而不是坐标,从0,0到width-1,height-1)
		for (int x = min_x; x <= max_x; x++) {
			for (int y = min_y; y <= max_y; y++) {
				// 记录最小深度
				float minDepth = FLT_MAX;
				// 四个小点中落入三角形中的点的个数
				int count = 0;
				// 对四个小点坐标进行判断 
				for (int i = 0; i < 4; i++) {
					// hero:小点是否在三角形内
/*hero:因为x,y是像素索引,也是该像素的左下角点坐标,所以可以加上pos[i][0基础偏移量,得到4个细分位置*/
					if (insideTriangle((float)x + pos[i][0], (float)y + pos[i][1], t.v)) {
						/* 如果在,对深度z进行插值,computeBarycentric2D计算该采样点的重心坐标*/
						auto tup = computeBarycentric2D((float)x + pos[i][0], (float)y + pos[i][1], t.v);
/*hero:以下就是该采样点相对三角形3个顶点的权重值,而且获得权重后,color、normal、texture、所有顶点信息都可以根据权重被采样*/
						float alpha;
						float beta;
						float gamma;
						std::tie(alpha, beta, gamma) = tup;
						float w_reciprocal = 1.0 / (alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
						float z_interpolated = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() + gamma * v[2].z() / v[2].w();
						z_interpolated *= w_reciprocal;
//获得这4个采样点中最小的minDepth
						minDepth = std::min(minDepth, z_interpolated);
						count++;
					}
				}
				if (count != 0) {
//hero:如果有值,就有采样点落入三角形,判断是否小于该索引处的像素深度,小于则更新深度,并绘制
					if (depth_buf[get_index(x, y)] > minDepth) {
//hero:下面应该采用双线性采样,来计算权重后的color
						Vector3f color = t.getColor() * count / 4.0;
						Vector3f point(3);
						point << (float)x, (float)y, minDepth;
						// 替换深度
						depth_buf[get_index(x, y)] = minDepth;
						// 修改颜色
						set_pixel(point, color);
					}
				}
			}
		}
	}
//hero:以下是没有采用MSAA的方式
	else {
		for (int x = min_x; x <= max_x; x++) {
			for (int y = min_y; y <= max_y; y++) {
				if (insideTriangle((float)x + 0.5, (float)y + 0.5, t.v)) {
					auto tup = computeBarycentric2D((float)x + 0.5, (float)y + 0.5, t.v);
					float alpha;
					float beta;
					float gamma;
					std::tie(alpha, beta, gamma) = tup;
					float w_reciprocal = 1.0 / (alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
					float z_interpolated = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() + gamma * v[2].z() / v[2].w();
					z_interpolated *= w_reciprocal;

					if (depth_buf[get_index(x, y)] > z_interpolated) {
						Vector3f color = t.getColor();
						Vector3f point(3);
						point << (float)x, (float)y, z_interpolated;
						depth_buf[get_index(x, y)] = z_interpolated;
						set_pixel(point, color);
					}
				}
			}
		}
	}
}

判断点是否位于三角形内函数

static bool insideTriangle(double x, double y, const Vector3f* _v)
{   
    // TODO : Implement this function to check if the point (x, y) is inside the triangle represented by _v[0], _v[1], _v[2]
//hero:对应Vector2的二维向量不能计算Cross叉乘,因为叉乘只出现在3D矢量中
	Eigen::Vector2f p;
	p << x, y;
/*hero:此时,三角形是具有3D信息的,Sceen2D“图形”(被正交投影过,并适配到视口screen),所以去深度值,只进行平面计算*/
	Eigen::Vector2f AB = _v[1].head(2) - _v[0].head(2);
	Eigen::Vector2f BC = _v[2].head(2) - _v[1].head(2);
	Eigen::Vector2f CA = _v[0].head(2) - _v[2].head(2);

	Eigen::Vector2f AP = p - _v[0].head(2);
	Eigen::Vector2f BP = p - _v[1].head(2);
	Eigen::Vector2f CP = p - _v[2].head(2);
	
	// 判断每个z坐标是否统一
	return AB[0] * AP[1] - AB[1] * AP[0] > 0 
		&& BC[0] * BP[1] - BC[1] * BP[0] > 0
		&& CA[0] * CP[1] - CA[1] * CP[0] > 0;
}

结果

以下是结果:
在这里插入图片描述
以下依次是没有做MSAA 4X的结果和做了MSAA 4X的结果:
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值