OpenGl 视图矩阵 - 错误 "camera" 方向和位置
OpenGl view matrix - wrong "camera" orientation and position
症状是,"position of the camera" 似乎围绕 x 轴镜像(负 z 而不是正 z)并且 "orientation of the camera" 与预期相反。
换句话说,我必须将相机旋转180度并向前移动才能看到任何效果图。
在我看过的所有 OpenGl 相机教程中,相机位置总是有一个正 z 坐标。也许代码中只有一个符号错误,但我没有看到。我也发布了相应的着色器代码。
我的对象在世界坐标 z=0.1 处渲染。
相机实例的初始化如下所示
m_viewMatrix = math::Matrix4D::lookAt(m_cameraPosition, m_cameraPosition + m_cameraForward, m_cameraUp);
哪里
m_cameraForward(math::Vector3D(0.0f, 0.0f, -1.0f)),
m_cameraRight(math::Vector3D (1.0f, 0.0f, 0.0f)),
m_cameraUp(math::Vector3D(0.0f, 1.0f, 0.0f)),
m_cameraPosition(math::Vector3D(0.0f, 0.0f, 20.0f))
结果是黑屏。当我将相机位置更改为
m_cameraPosition(数学::Vector3D(0.0f, 0.0f, -20.0f)
一切正常。
函数 lookAt 由以下几行给出:
Matrix4D Matrix4D::lookAt(
const Vector3D& f_cameraPosition_r,
const Vector3D& f_targetPosition_r,
const Vector3D& f_upDirection_r)
{
const math::Vector3D l_forwardDirection = (f_targetPosition_r - f_cameraPosition_r).normalized();
const math::Vector3D l_rightDirection = f_upDirection_r.cross(l_forwardDirection).normalized();
const math::Vector3D l_upDirection = l_forwardDirection.cross(l_rightDirection); // is normalized
return math::Matrix4D(
l_rightDirection.x, l_rightDirection.y, l_rightDirection.z, l_rightDirection.dot(f_cameraPosition_r*(-1.0f)),
l_upDirection.x, l_upDirection.y, l_upDirection.z, l_upDirection.dot(f_cameraPosition_r*(-1.0f)),
l_forwardDirection.x, l_forwardDirection.y, l_forwardDirection.z, l_forwardDirection.dot(f_cameraPosition_r*(-1.0f)),
0.0f, 0.0f, 0.0f, 1.0f
);
}
matrix4d 的内存布局是 column major,正如 OpenGl 所期望的那样。
点和交叉等所有其他功能都经过单元测试。
顶点着色器:
#version 430
in layout (location = 0) vec3 position;
in layout (location = 1) vec4 color;
in layout (location = 2) vec3 normal;
uniform mat4 pr_matrix; // projection matrix
uniform mat4 vw_matrix = mat4(1.0); // view matrix <------
uniform mat4 ml_matrix = mat4(1.0); // model matrix
out vec4 colorOut;
void main()
{
gl_Position = pr_matrix * vw_matrix * ml_matrix * vec4(position,1.0);
colorOut = color;
}
片段着色器:
#version 430
out vec4 color;
in vec4 colorOut;
void main()
{
color = colorOut;
}
编辑(添加透视矩阵):
Matrix4D Matrix4D::perspectiveProjection(
const float f_viewportWidth_f,
const float f_viewportHeight_f,
const float f_nearPlaneDistance_f,
const float f_farPlaneDistance_f,
const float f_radFieldOfViewY_f)
{
const float l_aspectRatio_f = f_viewportWidth_f / f_viewportHeight_f;
const float l_tanHalfFovy_f = tan(f_radFieldOfViewY_f * 0.5);
const float l_frustumLength = f_farPlaneDistance_f - f_nearPlaneDistance_f;
const float l_scaleX = 1.0f / (l_aspectRatio_f * l_tanHalfFovy_f);
const float l_scaleY = 1.0f / l_tanHalfFovy_f;
const float l_scaleZ = - (f_farPlaneDistance_f + f_nearPlaneDistance_f) / l_frustumLength;
const float l_value32 = -(2.0f*f_farPlaneDistance_f*f_nearPlaneDistance_f) / l_frustumLength;
return Matrix4D(
l_scaleX, +0.0f, +0.0f, +0.0f,
+0.0f, l_scaleY, +0.0f, +0.0f,
+0.0f, +0.0f, l_scaleZ, l_value32,
+0.0f, +0.0f, -1.0f, +0.0f);
您的投影矩阵遵循 "classic" OpenGL 约定:眼睛 space 中的观察方向为 (0,0,-1)(矩阵的最后一行)。
但是,您的视图矩阵不遵循该约定:您必须将 negated 正向放入矩阵(也用于计算那里的平移 z 分量)。在目前的形式中,视图矩阵只是旋转,因此前向映射到 +z。
否定这一点当然意味着您将为世界使用右手坐标系space(这是经典 GL 所做的)。如果你不想这样,你也可以只改变投影矩阵来实际查看 +z。
症状是,"position of the camera" 似乎围绕 x 轴镜像(负 z 而不是正 z)并且 "orientation of the camera" 与预期相反。
换句话说,我必须将相机旋转180度并向前移动才能看到任何效果图。
在我看过的所有 OpenGl 相机教程中,相机位置总是有一个正 z 坐标。也许代码中只有一个符号错误,但我没有看到。我也发布了相应的着色器代码。
我的对象在世界坐标 z=0.1 处渲染。
相机实例的初始化如下所示
m_viewMatrix = math::Matrix4D::lookAt(m_cameraPosition, m_cameraPosition + m_cameraForward, m_cameraUp);
哪里
m_cameraForward(math::Vector3D(0.0f, 0.0f, -1.0f)),
m_cameraRight(math::Vector3D (1.0f, 0.0f, 0.0f)),
m_cameraUp(math::Vector3D(0.0f, 1.0f, 0.0f)),
m_cameraPosition(math::Vector3D(0.0f, 0.0f, 20.0f))
结果是黑屏。当我将相机位置更改为 m_cameraPosition(数学::Vector3D(0.0f, 0.0f, -20.0f) 一切正常。
函数 lookAt 由以下几行给出:
Matrix4D Matrix4D::lookAt(
const Vector3D& f_cameraPosition_r,
const Vector3D& f_targetPosition_r,
const Vector3D& f_upDirection_r)
{
const math::Vector3D l_forwardDirection = (f_targetPosition_r - f_cameraPosition_r).normalized();
const math::Vector3D l_rightDirection = f_upDirection_r.cross(l_forwardDirection).normalized();
const math::Vector3D l_upDirection = l_forwardDirection.cross(l_rightDirection); // is normalized
return math::Matrix4D(
l_rightDirection.x, l_rightDirection.y, l_rightDirection.z, l_rightDirection.dot(f_cameraPosition_r*(-1.0f)),
l_upDirection.x, l_upDirection.y, l_upDirection.z, l_upDirection.dot(f_cameraPosition_r*(-1.0f)),
l_forwardDirection.x, l_forwardDirection.y, l_forwardDirection.z, l_forwardDirection.dot(f_cameraPosition_r*(-1.0f)),
0.0f, 0.0f, 0.0f, 1.0f
);
}
matrix4d 的内存布局是 column major,正如 OpenGl 所期望的那样。 点和交叉等所有其他功能都经过单元测试。
顶点着色器:
#version 430
in layout (location = 0) vec3 position;
in layout (location = 1) vec4 color;
in layout (location = 2) vec3 normal;
uniform mat4 pr_matrix; // projection matrix
uniform mat4 vw_matrix = mat4(1.0); // view matrix <------
uniform mat4 ml_matrix = mat4(1.0); // model matrix
out vec4 colorOut;
void main()
{
gl_Position = pr_matrix * vw_matrix * ml_matrix * vec4(position,1.0);
colorOut = color;
}
片段着色器:
#version 430
out vec4 color;
in vec4 colorOut;
void main()
{
color = colorOut;
}
编辑(添加透视矩阵):
Matrix4D Matrix4D::perspectiveProjection(
const float f_viewportWidth_f,
const float f_viewportHeight_f,
const float f_nearPlaneDistance_f,
const float f_farPlaneDistance_f,
const float f_radFieldOfViewY_f)
{
const float l_aspectRatio_f = f_viewportWidth_f / f_viewportHeight_f;
const float l_tanHalfFovy_f = tan(f_radFieldOfViewY_f * 0.5);
const float l_frustumLength = f_farPlaneDistance_f - f_nearPlaneDistance_f;
const float l_scaleX = 1.0f / (l_aspectRatio_f * l_tanHalfFovy_f);
const float l_scaleY = 1.0f / l_tanHalfFovy_f;
const float l_scaleZ = - (f_farPlaneDistance_f + f_nearPlaneDistance_f) / l_frustumLength;
const float l_value32 = -(2.0f*f_farPlaneDistance_f*f_nearPlaneDistance_f) / l_frustumLength;
return Matrix4D(
l_scaleX, +0.0f, +0.0f, +0.0f,
+0.0f, l_scaleY, +0.0f, +0.0f,
+0.0f, +0.0f, l_scaleZ, l_value32,
+0.0f, +0.0f, -1.0f, +0.0f);
您的投影矩阵遵循 "classic" OpenGL 约定:眼睛 space 中的观察方向为 (0,0,-1)(矩阵的最后一行)。
但是,您的视图矩阵不遵循该约定:您必须将 negated 正向放入矩阵(也用于计算那里的平移 z 分量)。在目前的形式中,视图矩阵只是旋转,因此前向映射到 +z。
否定这一点当然意味着您将为世界使用右手坐标系space(这是经典 GL 所做的)。如果你不想这样,你也可以只改变投影矩阵来实际查看 +z。