我正在使用glm创建一个相机类,我遇到了一些lookat函数的问题。我使用四元数来表示旋转,但我想使用glm的预先编写的lookat函数来避免重复代码。这是我的lookat功能:
void Camera::LookAt(float x, float y, float z) {
glm::mat4 lookMat = glm::lookAt(position, glm::vec3(x, y, z), glm::vec3(0, 1, 0));
rotation = glm::toQuat(lookMat);
}
但是当我拨打LookAt(0.0f,0.0f,0.0f)
时,我的相机没有旋转到那一点。当我在lookat调用之后调用glm::eulerangles(rotation)
时,我得到一个带有以下值的vec3:(180.0f,0.0f,180.0f)。 position
是(0.0f,0.0f,-10.0f),所以我根本不应该有任何轮换来查看0,0,0。这是构建视图矩阵的函数:
glm::mat4 Camera::GetView() {
view = glm::toMat4(rotation) * glm::translate(glm::mat4(), position);
return view;
}
为什么我没有获得正确的四元数,以及如何修复代码?
答案 0 :(得分:6)
<强>解决方案:强>
你必须通过结合它来反转四元数的旋转:
using namespace glm;
quat orientation = conjugate(toQuat(lookAt(vecA, vecB, up)));
<小时/> 的说明:强>
lookAt函数是gluLookAt的替代,用于构造view matrix。
视图矩阵用于围绕观察者旋转世界,因此是相机变换的反转。
通过取倒数的倒数,可以得到实际的变换。
答案 1 :(得分:1)
我碰到了类似的东西,简短的回答是你的lookMat可能需要倒置/转置,因为它是一个相机旋转(至少在我的情况下),而不是世界旋转。旋转世界将是相机旋转的反转。
我有一个m_current_quat,它是一个存储当前相机旋转的四元数。我通过打印出glm :: lookAt生成的矩阵来调试问题,并通过应用m_current_quat和m_camera_position的转换来比较得到的矩阵。这是我测试的相关代码。
void PrintMatrix(const GLfloat m[16], const string &str)
{
printf("%s:\n", str.c_str());
for (int i=0; i<4; i++)
{
printf("[");
//for (int j=i*4+0; j<i*4+4; j++) // row major, 0, 1, 2, 3
for (int j=i+0; j<16; j+=4) // OpenGL is column major by default, 0, 4, 8, 12
{
//printf("%d, ", j); // print matrix index
printf("%.2f, ", m[j]);
}
printf("]\n");
}
printf("\n");
}
void CameraQuaternion::SetLookAt(glm::vec3 look_at)
{
m_camera_look_at = look_at;
// update the initial camera direction and up
//m_initial_camera_direction = glm::normalize(m_camera_look_at - m_camera_position);
//glm::vec3 initial_right_vector = glm::cross(m_initial_camera_direction, glm::vec3(0, 1, 0));
//m_initial_camera_up = glm::cross(initial_right_vector, m_initial_camera_direction);
m_camera_direction = glm::normalize(m_camera_look_at - m_camera_position);
glm::vec3 right_vector = glm::cross(m_camera_direction, glm::vec3(0, 1, 0));
m_camera_up = glm::cross(right_vector, m_camera_direction);
glm::mat4 lookat_matrix = glm::lookAt(m_camera_position, m_camera_look_at, m_camera_up);
// Note: m_current_quat quat stores the camera rotation with respect to the camera space
// The lookat_matrix produces a transformation for world space, where we rotate the world
// with the camera at the origin
// Our m_current_quat need to be an inverse, which is accompolished by transposing the lookat_matrix
// since the rotation matrix is orthonormal.
m_current_quat = glm::toQuat(glm::transpose(lookat_matrix));
// Testing: Make sure our model view matrix after gluLookAt, glmLookAt, and m_current_quat agrees
GLfloat current_model_view_matrix[16];
//Test 1: gluLookAt
gluLookAt(m_camera_position.x, m_camera_position.y, m_camera_position.z,
m_camera_look_at.x, m_camera_look_at.y, m_camera_look_at.z,
m_camera_up.x, m_camera_up.y, m_camera_up.z);
glGetFloatv(GL_MODELVIEW_MATRIX, current_model_view_matrix);
PrintMatrix(current_model_view_matrix, "Model view after gluLookAt");
//Test 2: glm::lookAt
lookat_matrix = glm::lookAt(m_camera_position, m_camera_look_at, m_camera_up);
PrintMatrix(glm::value_ptr(lookat_matrix), "Model view after glm::lookAt");
//Test 3: m_current_quat
glLoadIdentity();
glMultMatrixf( glm::value_ptr( glm::transpose(glm::mat4_cast(m_current_quat))) );
glTranslatef(-m_camera_position.x, -m_camera_position.y, -m_camera_position.z);
glGetFloatv(GL_MODELVIEW_MATRIX, current_model_view_matrix);
PrintMatrix(current_model_view_matrix, "Model view after quaternion transform");
return;
}
希望这有帮助。
答案 2 :(得分:0)
我想使用glm的预先编写的lookat函数来避免重复代码。
但它不重复代码。来自glm::lookat
的矩阵只是mat4
。通过从四元数到3个向量的转换,只有glm::lookat
可以将其转换回方向只是浪费时间。你已经完成了lookat
工作的85%;做其余的事。
答案 3 :(得分:0)
你正在获得(或更好: a )正确的轮播。
当我在外观电话后拨打
glm::eulerangles(rotation)
时,我得到了一个vec3
具有以下值:(180.0f,0.0f,180.0f)。position
是 (0.0f,0.0f,-10.0f),所以我根本不应该有任何轮换 在0,0,0。
glm遵循旧固定功能GL的惯例。在那里,眼睛空间被定义为放置在原点的相机,向右x
指向,y
向上并向 -z
方向看。由于您希望以正z
方向查看,因此相机必须转动。现在,作为人类,我会将其描述为围绕y
旋转180度,但围绕x
旋转180度并结合z
周围的另一个180度旋转将也有同样的效果。
答案 4 :(得分:0)
乘以LookAt
视图矩阵后,世界空间矢量被旋转(引出)到摄像机的视图中在相机方向保持不变的情况下。
因此,通过矩阵将摄像机的实际旋转角度向右移向右旋转45度,该矩阵向世界所有空间的向左旋转45度顶点。
对于Camera
对象,您需要获取其 local forward
和up
方向矢量,以便计算lookAt
视图矩阵
viewMatrix = glm::lookAtLH (position, position + camera_forward, camera_up);
在使用四元数来存储对象(无论是照相机还是其他物体)的方向时,通常将此rotation
quat用于计算定义其局部空间的向量(在以下示例中为左手):
glm::vec3 camera_forward = rotation * glm::vec3(0,0,1); // +Z is forward direction
glm::vec3 camera_right = rotation * glm::vec3(1,0,0); // +X is right direction
glm::vec3 camera_up = rotation * glm::vec3(0,1,0); // +Y is up direction
因此,应将世界空间方向旋转45度到右,以反映相机的正确方向。
这就是为什么lookMat
或从其获得的quat不能直接用于此目的的原因,因为它们描述的方向是相反的。
正确的旋转方式有两种:
lookAt
矩阵的逆并将该旋转矩阵乘以世界空间方向向量glm::inverse
,因为结果是单位四元,并且对于此类四元,其逆等于共轭的。您的LookAt
应该如下所示:
void Camera::LookAt(float x, float y, float z) {
glm::mat4 lookMat = glm::lookAt(position, glm::vec3(x, y, z), glm::vec3(0, 1, 0));
rotation = glm::conjugate( glm::quat_cast(lookMat));
}