GAMES101作业1

作业目标:

  • get_model_matrix(float rotation_angle):

逐个元素地构建模型变换矩阵并返回该矩阵。在此函数中,你只需要实现三维中绕 z 轴旋转的变换矩阵,而不用处理平移与缩放

  • get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar):

使用给定的参数逐个元素地构建透视投影矩阵并返回该矩阵。

实现:

  • get_model_matrix(float rotation_angle)
    三维空间,绕Z轴旋转,由一个角度,得到一个旋转矩阵
Eigen::Matrix4f get_model_matrix(float rotation_angle)
{
	float theta = (rotation_angle / 180.0) * MY_PI;//角度转弧度
	Eigen::Matrix4f model = Eigen::Matrix4f::Identity();//新建一个4x4的矩阵

	model << std::cos(theta), -std::sin(theta), 0, 0,
		 std::sin(theta), std::cos(theta), 0, 0,
		 0, 0, 1.0, 0,
		 0, 0, 0, 1.0;
	//PS:绕X、Z轴旋转的旋转矩阵同理,绕Y轴的旋转矩阵略有不同,sin和-sin的位置会互换
	
	return model;
}

  • get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar)

摄像机上方是y正半轴,右边是x正半轴、看向z负半轴

现在假设我们站在x正半轴 看向x负半轴

eye_fov:视角,摄像机最上方能看到的角度到最下方能看到的角度

aspect_ratio:矩形宽高比

zNear、zFar:近处面的z值,远处面的z值,注意,朝向z负半轴,即两者均为负值

目标得到投影矩阵,先将透视图转化为正交图,然后再进行缩放,使得x、y、z三维方向的值的范围均在[-1,1],最后将其平移到视口中心

视锥->立方体
透视图->正交图
image

根据zFar、zNear、eye_fov、aspect_ratio可以算出宽、高。
image

Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar)
{
	//Eigen::Matrix4f::Identity() 初始化为单位矩阵
	Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();

	//透视图,近大远小,是个视锥  此矩阵是一个公式
	Eigen::Matrix4f P2O = Eigen::Matrix4f::Identity();//将透视矩阵挤压成正交矩阵
	P2O << zNear, 0, 0, 0,
		0, zNear, 0, 0,
		0, 0, zNear + zFar, - zFar* zNear,
		0, 0, 1.0, 0;

	float halfEyeAngelRadian = (eye_fov / 2.0 / 180.0) * MY_PI; //视角的一半
	float y_top = -zNear * std::tan(halfEyeAngelRadian);//y轴正方向值 = 显示视口的一半高度 zNear是负值!
	float x_left = -y_top * aspect_ratio;//x轴负方向值 = 显示视口的一半宽度
	float y_down = -y_top;
	float x_right = -x_left;

	//构造缩放矩阵,使视口大小等同窗口大小
	Eigen::Matrix4f scaleMat = Eigen::Matrix4f::Identity();
	scaleMat << 2 / (x_right - x_left), 0, 0, 0,			//将中心视为原点,则窗口的三维方向值域均为[-1,1] 
				0, 2 / (y_top - y_down), 0, 0,				//缩放的倍数为 期望值/当前值
				0, 0, 2 / (zNear - zFar), 0,				//所以缩放的倍数为 (1+1)/某一维度的当前值
				0, 0, 0, 1;

	//构造平移矩阵,将视口左下角移动到原点
	Eigen::Matrix4f translateMat = Eigen::Matrix4f::Identity();
	
	//左下角的点原本为 (x_left,y_down,zNear)
	//注意!此时已经经过了缩放,所以左下角的点的位置已经变化
	//左下角的点现在为 (-1,-1,zNear)
	//即其实可以不用管x和y轴,比较尺寸已经和窗口匹配了
	//但网上其他人却还是右下方注释的那样写的,左侧+右侧或者上侧+下侧,结果不都是0么?
	translateMat << 1, 0, 0, 0,					//-(x_left+x_right)/2
			0, 1, 0, 0,					//-(y_top+y_down)/2
			0, 0, 1, -(zNear+zFar)/2,
			0, 0, 0, 1;
	//注意!此处矩阵相乘,右结合率,必须先压缩矩阵,再缩放,最后平移,顺序一定不可以改!
	projection = translateMat * scaleMat * P2O;
	
	return projection;
}

运行结果:

image

posted @ 2021-04-11 22:23  抚琴思伯牙  阅读(1143)  评论(2编辑  收藏  举报