作业描述
给定一个点 P=(2,1), 将该点绕原点先逆时针旋转 45◦,再平移 (1,2), 计算出变换后点的坐标(要求用齐次坐标进行计算)
解
代码:
#include <iostream>
#include <Eigen\Dense>
#include <cmath>
using namespace std;
using namespace Eigen;
void main()
{
Eigen::Vector3d point(2, 1, 1);//齐次坐标
Eigen::Matrix3f rotate, translate;
float angle = 45.0/180.0*acos(-1);
rotate << std::cos(angle), -std::sin(angle), 0.0,
std::sin(angle), std::cos(angle), 0.0,
0.0, 0.0, 1.0;//旋转矩阵,逆时针45°
translate << 1.0, 0.0, 1.0,
0.0, 1.0, 2.0,
0.0, 0.0, 1.0;//平移矩阵,平移 (1,2)
std::cout << translate * rotate * point << std::endl;//先旋转后平移
system("pause");
}
输出:
课后思考
老师在第四课的最后给我们留了一个问题:nf平面之间的坐标经过变换后z轴坐标值会变吗?在透视投影的时候z轴一半距离处的图像在变换后它的z轴坐标值是向n面靠拢还是向f面靠拢了?
首先分析透视投影的原理:
首先看到左边的四棱台,我们可以把平面n看作相机的成像镜头(因为得到的照片是矩形的嘛),整个四棱台就是相机的视线(即相机照片包含的空间)
那么这么大一个空间内的所有图像怎么投影到平面n上呢?首先想象我们从n到f平面之间划分为无数个小平面,然后把每个小平面压缩到n平面的形状,而且我们规定n平面所有点坐标不变,f平面的z轴坐标不变以及它的(0,0)点不变,这样就得到之前对照图右边的那个立方体,然后我们利用正交投影将立方体图像光栅化投影到n平面,这就是透视投影的工作原理。
从公式上来看,对于每个平面上的点,我们可以利用相似三角形来先求出x,y的坐标:
然后利用齐次坐标的性质同乘以一个z:
根据这个坐标,我们就可以求出透视投影矩阵的其中三行:
接下来第三行就利用n平面不变,f平面的(0,0)不变两个性质来求:
那么得到了这么一个公式,我们就来求(n+f)/2处平面坐标的z轴坐标吧:
设被投影点齐次坐标为:
[x’,y’,(n+f)/2,1]
透视投影矩阵为:
(n,0,0,0)
(0,n,0,0)
(0,0,n+f,-nf)
(0,0,1,0)
相乘后得到坐标:
[nx’,ny’,(n+f)^2/2-nf,(n+f)/2]
约分后为:
[x",y",(n+f)-2nf/(n+f),1]
此时我们的z轴坐标为:
(
n
+
f
)
2
(
n
+
f
)
−
2
n
f
(
n
+
f
)
=
n
2
+
f
2
(
n
+
f
)
\frac{(n+f)^2}{(n+f)} - \frac{2nf}{(n+f)} = \frac{n^2+f^2}{(n+f)}
(n+f)(n+f)2−(n+f)2nf=(n+f)n2+f2
将它减去原来的z轴坐标(n+f)/2为:
n
2
+
f
2
(
n
+
f
)
−
n
+
f
2
=
(
n
−
f
)
2
2
(
n
+
f
)
\frac{n^2+f^2}{(n+f)} - \frac{n+f}{2}=\frac{(n-f)^2}{2(n+f)}
(n+f)n2+f2−2n+f=2(n+f)(n−f)2
显而易见的,结果明显要小于0,因为是向-z方向看,n和f都是负的,而分子是一个非负的平方式,所以一半距离处的图像在投影后会向f平面靠拢
这也就解释了中间平面z轴坐标为什么会变的原因,它也符合日常生活中的经验,比如这张图:
可以看到,从镜头前到视线最远处的铁轨,按照相似三角形的性质,它的一半距离处的铁轨也应该是处于图片中铁轨长度的1/2处,但是我们根据日常经验却很明显能感受到铁轨的1/2处应该在图片中铁轨长度的不到1/10处,可以说是基本上向远平面靠拢了,这种现象很常见,总结起来就是离我们视线较近的部分都会被相对拉伸: