Games101作业1:旋转矩阵及投影变换

本文详细介绍了二维旋转矩阵在三维空间中的应用,以及如何通过定义视锥体的视角和变换来构建相机矩阵。重点讲解了从世界空间到视图空间的转换过程,包括透视投影的原理和计算方法,以及如何构造完整的投影矩阵,以实现3D场景的正确显示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Assignment1

前置知识

旋转矩阵(二维)

(cosα−sinαsinαcosα) \begin{pmatrix} cos\alpha&-sin\alpha \\ sin\alpha&cos\alpha \end{pmatrix} (cosαsinαsinαcosα)
三维的旋转矩阵,保持这四个系数的值和相对位置不变,绕哪个轴转,就将对应列设成1,四个系数补到对应位置上。唯一例外是绕y轴旋转,右上角的符号要移到左下角(相对其他两矩阵转置),因为绕y转时叉积方向和另外两条轴相反(右手拇指向着旋转轴的方向,绕x转是y到z,绕z转是x到y;绕y转若想得到x到z需要拇指背对y轴方向)

View/Transformation

如何定义一个camera 位置、Up方向、Look-at方向

camera坐标系 原点、Y轴(Up)、Z轴(-Look-at)

变换矩阵(从World Space到View Space)
Mview=RviewTview M_{view}=R_{view}T_{view} Mview=RviewTview
涉及坐标系变换,先将原点从World Space的原点移到Camera的位置(-X,-Y,-Z);再旋转(用World Space中的Camera三条轴位置所得矩阵的逆矩阵),由于是纯旋转(正交)矩阵,逆矩阵等于转置矩阵

Perspective Projection

任务 现实中视锥体近平面n比远平面f要小(近大远小),然而我们要将视锥体投影到齐次坐标系中,所以需要将f映射成与n一样的大小并保持对应关系不变(将远平面f挤成近平面n一样大小),再对得到的立方体用正交变换

推导

x轴和y轴不涉及复杂变换,因此用简单投影公式即可(如Ynew = Yold*(Zn/Z) z为视锥体里面的点 n为近平面:将视锥体内挤成和n一样大小)

由此得到变换后结果(同时乘了z,此时z仍未知),由该结果可倒推出部分M
∵MP2O(xyz1)=(nxnyunknownz)∴MP2O=(n0000n00????0010) \because M_{P2O} \begin{pmatrix} x \\ y \\ z \\ 1\end{pmatrix} = \begin{pmatrix} nx \\ ny \\ unknown \\ z\end{pmatrix} \therefore M_{P2O} = \begin{pmatrix} n&0&0&0 \\ 0&n&0&0 \\ ?&?&?&? \\ 0&0&1&0\end{pmatrix} MP2Oxyz1=nxnyunknownzMP2O=n0?00n?000?100?0
接下来从近平面n和远平面分别得到两条性质(相当于代入特殊值n和f解方程)

近平面n上的点全部不变 远平面f上的点Z坐标全部不变

首先运用第一条性质,将n代入Z:
∵MP2O(xyn1)=(nxnyn2n)∴(00AB)(xyn1)=n2 \because M_{P2O}\begin{pmatrix} x \\ y \\ n \\ 1\end{pmatrix} = \begin{pmatrix} nx \\ ny \\ n^{2} \\ n\end{pmatrix} \therefore \begin{pmatrix} 0&0&A&B \end{pmatrix} \begin{pmatrix} x \\ y \\ n \\ 1\end{pmatrix} = n^2 MP2Oxyn1=nxnyn2n(00AB)xyn1=n2
进一步推导除第三行的形式(最终结果n平方和xy都无关,因此前两项为0)

同理运用第二条性质,将f代入Z(形式完全一致)

联立两条方程,得出完整的投影矩阵:
{An+B=n2Af+B=f2→{A=n+fB=−nf→MP2O=(n0000n0000n+f−nf0010) \begin{cases} An+B=n^2 \\Af+B=f^2 \end{cases} \rightarrow \begin{cases} A = n+f \\B=-nf \end{cases} \rightarrow M_{P2O} = \begin{pmatrix} n&0&0&0 \\ 0&n&0&0 \\ 0&0&n+f&-nf \\ 0&0&1&0\end{pmatrix} {An+B=n2Af+B=f2{A=n+fB=nfMP2O=n0000n0000n+f100nf0
再乘上正交矩阵,得到完整投影矩阵:

正交矩阵的任务是先将视线立方体移到(View Space)的原点,再缩放到标准大小[-1,1];在右手坐标系中,近平面n的Z坐标比远平面f要大,因此是n-f
MO=(2/(r−l)00002/(t−b)00002/(n−f)00001)(100−(r+l)/2010−(t+b)/2001−(n+f)/20001) M_{O} = \begin{pmatrix} 2/(r-l)&0&0&0 \\ 0&2/(t-b)&0&0 \\ 0&0&2/(n-f)&0 \\ 0&0&0&1\end{pmatrix} \begin{pmatrix} 1&0&0&-(r+l)/2 \\ 0&1&0&-(t+b)/2 \\ 0&0&1&-(n+f)/2 \\ 0&0&0&1\end{pmatrix} MO=2/(rl)00002/(tb)00002/(nf)00001100001000010(r+l)/2(t+b)/2(n+f)/21
在视锥体内部的点经过变换后的z值比原来小:变换矩阵与(x,y,z,1)相乘后z的值等于(-nf)*z^(-1)+(n+f),是个反比例函数,这个图像恒过(n,n)与(f,f),在n与f之间,是下凹的,所以变小了

code

Eigen::Matrix4f get_model_matrix(float rotation_angle)
{
    //  将角度转换为弧度
    float radian = (rotation_angle * MY_PI)/ 180.0 ;
    Eigen::Matrix4f translate;
    translate <<
        cos(radian), -sin(radian), 0, 0,
        sin(radian), cos(radian), 0, 0,
        0, 0, 1, 0,
        0, 0, 0, 1;
    model = translate * model;
    return model;
}

Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,float zNear, float zFar)
{
    Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();

    //  用参数构造正交矩阵
	Eigen::Matrix4f OrthographicRS = Eigen::Matrix4f::Identity();
    Eigen::Matrix4f OrthographicT = Eigen::Matrix4f::Identity();
    float top = zNear * tan((eye_fov / 2.0) * MY_PI / 180.0);   //  注意用的是zNear(最终大小以n平面为准)
    float right = top * aspect_ratio;                       //  乘屏幕比得x坐标

    OrthographicRS <<
        1 / right, 0, 0, 0,
        0, 1 / top, 0, 0,
        0, 0,1 / (zNear - zFar), 0,
        0, 0, 0, 1;

    OrthographicT <<
        1, 0, 0, 0,
        0, 1, 0, 0,
        0, 0, 1, -(zNear + zFar) / 2,
        0, 0, 0, 1;

    projection = OrthographicRS * OrthographicT;

	//  投影矩阵
	Eigen::Matrix4f P2O = Eigen::Matrix4f::Identity();
	P2O <<
		zNear, 0, 0, 0,
		0, zNear, 0, 0,
		0, 0, zNear + zFar, -zNear * zFar,
		0, 0, 1, 0;

    projection *= P2O;

    return projection;
}

注意事项

角度值转弧度制

angle = rad * PI / 180

bug:看不见三角形,且按a或d几下之后提示溢出

矩阵左乘和右乘的问题:写投影矩阵时,将P2O放在正交矩阵的坐标,实际上应该放到右边(变换矩阵应该放在右边

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值