- 原理:
- 相机的运动实际上是对世界坐标系中的物体进行反向运动变换
- 相机的运动矩阵与其他物体的变换矩阵类似
- 先缩放变换,再进行旋转,最后进行平移
- 所以
glm::lookAt
函数返回的是相机变换矩阵的逆矩阵- 先对相机的平移矩阵求逆,然后乘以旋转矩阵的逆矩阵(参考计算矩阵乘积的逆矩阵公式)
- 注意事项:
- 相机矩阵的
Z轴
与相机的照射方向相反 glm
中的矩阵是列向量优先- 正交矩阵的逆矩阵等于它的转置
- 刚体运动中变换矩阵的逆矩阵求解:
- 刚体运动变换矩阵: $$\begin{equation} T = \begin{bmatrix*}[c] R & t \newline 0^T & 1 \end{bmatrix*} \end{equation}$$
- 分块矩阵求逆公式 $$\begin{equation} M = \begin{bmatrix*}[c] A & B \newline 0 & D \end{bmatrix*} \space\space\space\space M^{-1} = \begin{bmatrix*}[c] A^{-1} & -A^{-1}BD^{-1} \newline 0 & D^{-1} \end{bmatrix*} \end{equation}$$
- 刚体运动变换矩阵的逆矩阵: $$\begin{equation} T^{-1} = \begin{bmatrix*}[c] R^{-1} & -R^{-1}t \newline 0^T & 1 \end{bmatrix*} = \begin{bmatrix*}[c] R^T & -R^Tt \newline 0^T & 1 \end{bmatrix*} \end{equation}$$
- 方法一:
glm::mat4 Camera::calculateLookAtMatrix()
{
// 1. 计算方向
glm::vec3 zAxis = glm::normalize(camPos - target);
// 2. 计算相机右轴
glm::vec3 xAxis = glm::normalize(glm::cross(camUp, zAxis));
// 3. 计算相机向上的向量
glm::vec3 yAxis = glm::normalize(glm::cross(zAxis, xAxis));
// 创建位移和旋转矩阵
// glm 中采用 [col][row] 方式存储
glm::mat4 trans = glm::mat4(1.f);
trans[3][0] = -camPos.x;
trans[3][1] = -camPos.y;
trans[3][2] = -camPos.z;
glm::mat4 rotation = glm::mat4(1.f);
rotation[0][0] = xAxis.x;
rotation[1][0] = xAxis.y;
rotation[2][0] = xAxis.z;
rotation[0][1] = yAxis.x;
rotation[1][1] = yAxis.y;
rotation[2][1] = yAxis.z;
rotation[0][2] = zAxis.x;
rotation[1][2] = zAxis.y;
rotation[2][2] = zAxis.z;
// 先平移再旋转
return rotation * trans;
}
- 方法二:
先构建相机的变换矩阵,然后对矩阵求逆
glm::mat4 Camera::calculateLookAtMatrix()
{
// 相机位移矩阵
glm::mat4 camTrans = glm::mat4(1.f);
camTrans = glm::translate(camTrans, camPos);
// 相机旋转矩阵
glm::vec3 zAxis = glm::normalize(-camFront); // 相机的Z轴是从目标点指向相机点,与相机照射的方向相反
glm::vec3 xAxis = glm::normalize(glm::cross(camUp, zAxis));
glm::vec3 yAxis = glm::normalize(glm::cross(zAxis, xAxis));
// 用相机的 X Y Z 轴单位向量构建旋转矩阵(列向量优先)
glm::mat4 camRotate = glm::mat4(glm::vec4(xAxis, 0.f), glm::vec4(yAxis, 0.f)
, glm::vec4(zAxis, 0.f), glm::vec4(0.f, 0.f, 0.f, 1.f));
glm::mat4 camMat = camTrans * camRotate;
return glm::inverse(camMat);
}
参考: