Nov 2, 2024
9 mins read
齐次坐标的最后一位为 0 表示方向或无穷远点
平移变换不会影响最后一位为 0 的坐标,因此这些坐标无法通过平移操作改变位置。
三维与二维变换同理
先平移再旋转与先旋转再平移得到的结果是不一样的
由此可推出矩阵乘法是不符合交换律
$$ A_n (\dots A_2 (A_1 (\mathbf{x}))) = A_n \cdots A_2 \cdot A_1 \cdot \begin{pmatrix} x \\ y \\ 1 \end{pmatrix} $$在齐次坐标中的矩阵变换计算中,运算顺序是从右到左,即最先应用的是最右边的矩阵,然后依次往左应用。
先平移到原点,然后再旋转,最后再平移回去
围绕 x 轴的旋转矩阵:
$$ R_x(\alpha) = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos \alpha & -\sin \alpha & 0 \\ 0 & \sin \alpha & \cos \alpha & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} $$围绕 y 轴的旋转矩阵:
$$ R_y(\alpha) = \begin{bmatrix} \cos \alpha & 0 & \sin \alpha & 0 \\ 0 & 1 & 0 & 0 \\ -\sin \alpha & 0 & \cos \alpha & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} $$围绕 z 轴的旋转矩阵:
$$ R_z(\alpha) = \begin{bmatrix} \cos \alpha & -\sin \alpha & 0 & 0 \\ \sin \alpha & \cos \alpha & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} $$透视投影矩阵的主要目的是通过将三维坐标缩放并转换为齐次坐标,将视锥体中的物体投影到二维平面上
透视投影转正交矩阵为:
$$ M_{\text{persp\_to\_ortho}} = \begin{bmatrix} z_{\text{Near}} & 0 & 0 & 0 \\ 0 & z_{\text{Near}} & 0 & 0 \\ 0 & 0 & z_{\text{Near}} + z_{\text{Far}} & -z_{\text{Near}} \cdot z_{\text{Far}} \\ 0 & 0 & 1 & 0 \end{bmatrix} $$正交投影矩阵为:
$$ M_{ortho} = \begin{bmatrix} \frac{2}{r-l} & 0 & 0 & 0 \\ 0 & \frac{2}{t-b} & 0 & 0 \\ 0 & 0 & \frac{2}{n-f} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & -\frac{r+l}{2} \\ 0 & 1 & 0 & -\frac{t+b}{2} \\ 0 & 0 & 1 & -\frac{n+f}{2} \\ 0 & 0 & 0 & 1 \end{bmatrix} $$缩放矩阵(缩放至[−1,1] 区间为2)和平移矩阵(移动到原点位置)
t = tan(angle / 2) * -zNear (因为右手定则z轴为负)
b = -t
r = t * aspect_ratio
l = -r
其中:
I是单位矩阵。
kkT 是旋转轴的外积,表示旋转轴的投影矩阵。
最后一项是旋转轴的叉积矩阵,表示垂直旋转轴的旋转分量。
给定一个点P=(2,1),将该点绕原点先逆时针旋转45◦,再平移(1,2),计算出 变换后点的坐标。(要求用齐次坐标进行计算)
编译
为方便之后的作业编写,本次作业要求使用cmake进行编译。
首先,编写好本次作业的程序main.cpp。 然后, 在 main.cpp 所在目录下,打开终端(命令行),依次输入:
• mkdir build: 创建名为 build 的文件夹。
• cd build: 移动到 build 文件夹下。
• cmake ..: 注意其中’..’ 表示上一级目录,若为’.’ 则表示当前目录。
• make: 编译程序,错误提示会显示在终端中。
**• ./Transformation:**若上一步无错误,则可运行程序(这里的Transformation 为可执行文件名,可参照CMakeLists.txt 中修改)。
#include<cmath>
#include<eigen3/Eigen/Core>
#include<eigen3/Eigen/Dense>
#include<iostream>
int main(){
// init point
Eigen::Vector3f p(2.0f, 1.0f, 1.0f);
// rotate and transformation matrix
// x' = xcos - ysin
// y' = xsin + ycos
// x' = x + tx
// y' = y + ty
Eigen::Matrix3f R, T;
// cos45 = sin45 = sqrt(2) / 2
float ftheta = sqrt(2.0f) / 2;
R << ftheta, -ftheta, 0,
ftheta, ftheta, 0,
0, 0,1.0f;
T << 1.0f, 0, 1.0f,
0, 1.0f, 2.0f,
0, 0, 1.0f;
p = R * p;
std::cout << "After Rotate \n";
std::cout << p << std::endl;
p = T * p;
std::cout << "After Transformation \n";
std::cout << p << std::endl;
return 0;
}
附件
模型变换矩阵
Eigen::Matrix4f get_model_matrix(float rotation_angle)
{
Eigen::Matrix4f model = Eigen::Matrix4f::Identity();
float rotation_angle_radian = rotation_angle * MY_PI / 180;
Eigen::Matrix4f rotation;
rotation << cos(rotation_angle_radian), -sin(rotation_angle_radian), 0, 0,
sin(rotation_angle_radian), cos(rotation_angle_radian), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1;
model = rotation * model;
return model;
}
投影变换矩阵
Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,
float zNear, float zFar)
{
Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();
float eye_fov_radian = eye_fov * MY_PI / 180;
float t = tan(eye_fov_radian / 2) * abs(zNear);
float r = t * aspect_ratio;
float b = -t;
float l = -r;
Eigen::Matrix4f translation;
translation << 1, 0, 0, -(r + l) / 2.0f,
0, 1, 0, -(t + b) / 2.0f,
0, 0, 1, -(zNear + zFar) / 2.0f,
0, 0, 0, 1;
Eigen::Matrix4f scale;
scale << 2.0f / (r - l), 0, 0, 0,
0, 2.0f / (t - b), 0, 0,
0, 0, 2 / (zNear - zFar), 0,
0, 0, 0, 1;
projection = scale * translation;
Eigen::Matrix4f M_persp_ortho;
M_persp_ortho << zNear, 0, 0, 0,
0, zNear, 0, 0,
0, 0, zNear + zFar, -zFar*zNear,
0, 0, 1, 0;
projection = projection * M_persp_ortho;
return projection;
}
任意轴旋转矩阵罗德里格斯旋转公式
Eigen::Matrix4f getRotation(Vector3f axis, float angle){
float rotation_angle_radian = angle * MY_PI / 180;
Eigen::Matrix3f I = Eigen::Matrix3f::Identity();
Eigen::Matrix3f N;
N << 0, -axis(2), axis(1),
axis(2), 0, -axis(0),
-axis(1), axis(0), 0;
Eigen::Matrix3f r3 = cos(rotation_angle_radian) * I
+ (1 - cos(rotation_angle_radian)) * (axis * axis.transpose())
+ sin(rotation_angle_radian) * N;
Eigen::Matrix4f rotation = Eigen::Matrix4f::Identity();
rotation.block(0, 0, 3, 3) << r3;
return rotation;
}
附件
Sharing is caring!