1. 原理:
  • 相机的运动实际上是对世界坐标系中的物体进行反向运动变换
  • 相机的运动矩阵与其他物体的变换矩阵类似
    • 先缩放变换,再进行旋转,最后进行平移
  • 所以 glm::lookAt 函数返回的是相机变换矩阵的逆矩阵
    • 先对相机的平移矩阵求逆,然后乘以旋转矩阵的逆矩阵(参考计算矩阵乘积的逆矩阵公式)
  1. 注意事项:
  • 相机矩阵的 Z轴 与相机的照射方向相反
  • glm 中的矩阵是列向量优先
  • 正交矩阵的逆矩阵等于它的转置
  1. 刚体运动中变换矩阵的逆矩阵求解:
  • 刚体运动变换矩阵: $$\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}$$
  1. 方法一:

lookat矩阵计算

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;
}
  1. 方法二:

先构建相机的变换矩阵,然后对矩阵求逆

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);
}

参考:

  1. 刚体运动中变换矩阵的逆
  2. 计算机图形学OpenGL:7.1、摄像机LookAt矩阵
  3. OpenGL,Qt实现:1入门篇(已更完)
  4. OpenGL渲染引擎-从理论到实践
  5. OpenGL shader
  6. 最好的OpenGL教程之一