如何在 openGL 中使用逆视图矩阵绘制相机平截头体
How to draw camera frustum using inverse view matrix in openGL
出于调试目的,我尝试绘制相机视锥体。
我可以使用 NDC space 和以下代码
绘制它
Matrix inv = (camera.getViewMatrix() * camera.getProjectionMatrix()).inverse();
Vector4 f[8u] =
{
// near face
{1, 1, -1, 1.f},
{-1, 1, -1, 1.f},
{1, -1, -1, 1.f},
{-1, -1, -1, 1.f},
// far face
{1, 1, 1, 1.f},
{-1, 1, 1 , 1.f},
{1, -1, 1 , 1.f},
{-1, -1,1, 1.f},
};
Vector3 v[8u];
for (int i = 0; i < 8; i++)
{
Vector4 ff = inv * f[i];
v[i].x = ff.x / ff.w;
v[i].y = ff.y / ff.w;
v[i].z = ff.z / ff.w;
}
drawLine(v[0], v[1], Color::White);
drawLine(v[0], v[2], Color::White);
drawLine(v[3], v[1], Color::White);
drawLine(v[3], v[2], Color::White);
drawLine(v[4], v[5], Color::White);
drawLine(v[4], v[6], Color::White);
drawLine(v[7], v[5], Color::White);
drawLine(v[7], v[6], Color::White);
drawLine(v[0], v[4], Color::White);
drawLine(v[1], v[5], Color::White);
drawLine(v[3], v[7], Color::White);
drawLine(v[2], v[6], Color::White);
但是当我尝试使用反向视图绘制它时,截锥体被绘制到相机后面。
Matrix inv = camera.getViewMatrix().inverse();
float ar = static_cast<float>(800.f / 600.f);
float fov = 60.f;
float near = 0.1f;
float far = 100.f;
float halfHeight = tanf(Deg2Rad * (fov / 2.f));
float halfWidth = halfHeight * ar;
float xn = halfWidth * near;
float xf = halfWidth * far;
float yn = halfHeight * near;
float yf = halfHeight * far;
Vector4 f[8u] =
{
// near face
{xn, yn, near, 1.f},
{-xn, yn, near, 1.f},
{xn, -yn, near, 1.f},
{-xn, -yn,near , 1.f},
// far face
{xf, yf, far, 1.f},
{-xf, yf,far , 1.f},
{xf, -yf,far , 1.f},
{-xf, -yf,far, 1.f},
};
Vector3 v[8];
for (int i = 0; i < 8; i++)
{
Vector4 ff = inv * f[i];
v[i].x = ff.x / ff.w;
v[i].y = ff.y / ff.w;
v[i].z = ff.z / ff.w;
}
drawLine(v[0], v[1], Color::White);
drawLine(v[0], v[2], Color::White);
drawLine(v[3], v[1], Color::White);
drawLine(v[3], v[2], Color::White);
drawLine(v[4], v[5], Color::White);
drawLine(v[4], v[6], Color::White);
drawLine(v[7], v[5], Color::White);
drawLine(v[7], v[6], Color::White);
drawLine(v[0], v[4], Color::White);
drawLine(v[1], v[5], Color::White);
drawLine(v[3], v[7], Color::White);
drawLine(v[2], v[6], Color::White);
正如您在截图中看到的,当我观察场景的中心时,截锥体被绘制在相机后面。
view from camera 1
view from camera 2
计算视图的代码
static const float speed = frametime * 10000.f; // TODO add speed variable
Vector2 delta = m_mousePosition - Mouse::getPosition();
m_mousePosition = Mouse::getPosition();
Quaternion q;
Transformable::rotateX(-delta.y * frametime * 100.f);
Transformable::rotateY(delta.x * frametime * 100.f);
q.fromEuler(Transformable::getRotation());
m_direction = m_originDirection.rotate(q).normalize();
m_right = m_originUp.cross(m_direction).normalize();
m_up = m_direction.cross(m_right).normalize();
if (Keyboard::isKeyPress(GLFW_KEY_A))
Transformable::translate(m_right * frametime * speed);
else if (Keyboard::isKeyPress(GLFW_KEY_D))
Transformable::translate(-m_right * frametime * speed);
if (Keyboard::isKeyPress(GLFW_KEY_W))
Transformable::translate(m_direction * frametime * speed);
else if (Keyboard::isKeyPress(GLFW_KEY_S))
Transformable::translate(-m_direction * frametime * speed);
if (Keyboard::isKeyPress(GLFW_KEY_Q))
Transformable::translate(-m_up * frametime * speed);
else if (Keyboard::isKeyPress(GLFW_KEY_E))
Transformable::translate(m_up * frametime * speed);
m_view = Matrix::lookAt(Transformable::getPosition(), Transformable::getPosition() + m_direction, m_up);
以及 lookAt 函数
Matrix Matrix::lookAt(Vector3 const & eye, Vector3 const & center, Vector3 const & up)
{
Vector3 f = (center - eye).normalize();
Vector3 u = up;
u.normalize();
Vector3 s = f.cross(u).normalize();
u = s.cross(f);
Matrix result(s.x, u.x, -f.x, 0.f,
s.y, u.y, -f.y, 0.f,
s.z, u.z, -f.z, 0.f,
-s.dotProduct(eye), -u.dotProduct(eye), f.dotProduct(eye), 1.f);
return (result);
}
有谁知道我的代码有什么问题吗?
如果缺少信息,请告诉我。
代码也在这个github分支shadow_map
(github.com/jbalestr42/GraphicsEngine)
设置经典的 OpenGL 视图和投影矩阵,使视图 space 为右手,相机朝向 -z
方向,glOrtho
和 glFrustum
函数将 near
和 far
解释为沿视图方向的 距离 ,因此视图 space z
近坐标和远位面
z_near = -near
z_far = -far
而您的代码:
{
// near face
{xn, yn, near, 1.f},
{-xn, yn, near, 1.f},
{xn, -yn, near, 1.f},
{-xn, -yn,near , 1.f},
// far face
{xf, yf, far, 1.f},
{-xf, yf,far , 1.f},
{xf, -yf,far , 1.f},
{-xf, -yf,far, 1.f},
};
只是在+z
方向上绘制截锥体,预计最终会在相机后面。
出于调试目的,我尝试绘制相机视锥体。 我可以使用 NDC space 和以下代码
绘制它Matrix inv = (camera.getViewMatrix() * camera.getProjectionMatrix()).inverse();
Vector4 f[8u] =
{
// near face
{1, 1, -1, 1.f},
{-1, 1, -1, 1.f},
{1, -1, -1, 1.f},
{-1, -1, -1, 1.f},
// far face
{1, 1, 1, 1.f},
{-1, 1, 1 , 1.f},
{1, -1, 1 , 1.f},
{-1, -1,1, 1.f},
};
Vector3 v[8u];
for (int i = 0; i < 8; i++)
{
Vector4 ff = inv * f[i];
v[i].x = ff.x / ff.w;
v[i].y = ff.y / ff.w;
v[i].z = ff.z / ff.w;
}
drawLine(v[0], v[1], Color::White);
drawLine(v[0], v[2], Color::White);
drawLine(v[3], v[1], Color::White);
drawLine(v[3], v[2], Color::White);
drawLine(v[4], v[5], Color::White);
drawLine(v[4], v[6], Color::White);
drawLine(v[7], v[5], Color::White);
drawLine(v[7], v[6], Color::White);
drawLine(v[0], v[4], Color::White);
drawLine(v[1], v[5], Color::White);
drawLine(v[3], v[7], Color::White);
drawLine(v[2], v[6], Color::White);
但是当我尝试使用反向视图绘制它时,截锥体被绘制到相机后面。
Matrix inv = camera.getViewMatrix().inverse();
float ar = static_cast<float>(800.f / 600.f);
float fov = 60.f;
float near = 0.1f;
float far = 100.f;
float halfHeight = tanf(Deg2Rad * (fov / 2.f));
float halfWidth = halfHeight * ar;
float xn = halfWidth * near;
float xf = halfWidth * far;
float yn = halfHeight * near;
float yf = halfHeight * far;
Vector4 f[8u] =
{
// near face
{xn, yn, near, 1.f},
{-xn, yn, near, 1.f},
{xn, -yn, near, 1.f},
{-xn, -yn,near , 1.f},
// far face
{xf, yf, far, 1.f},
{-xf, yf,far , 1.f},
{xf, -yf,far , 1.f},
{-xf, -yf,far, 1.f},
};
Vector3 v[8];
for (int i = 0; i < 8; i++)
{
Vector4 ff = inv * f[i];
v[i].x = ff.x / ff.w;
v[i].y = ff.y / ff.w;
v[i].z = ff.z / ff.w;
}
drawLine(v[0], v[1], Color::White);
drawLine(v[0], v[2], Color::White);
drawLine(v[3], v[1], Color::White);
drawLine(v[3], v[2], Color::White);
drawLine(v[4], v[5], Color::White);
drawLine(v[4], v[6], Color::White);
drawLine(v[7], v[5], Color::White);
drawLine(v[7], v[6], Color::White);
drawLine(v[0], v[4], Color::White);
drawLine(v[1], v[5], Color::White);
drawLine(v[3], v[7], Color::White);
drawLine(v[2], v[6], Color::White);
正如您在截图中看到的,当我观察场景的中心时,截锥体被绘制在相机后面。
view from camera 1
view from camera 2
计算视图的代码
static const float speed = frametime * 10000.f; // TODO add speed variable
Vector2 delta = m_mousePosition - Mouse::getPosition();
m_mousePosition = Mouse::getPosition();
Quaternion q;
Transformable::rotateX(-delta.y * frametime * 100.f);
Transformable::rotateY(delta.x * frametime * 100.f);
q.fromEuler(Transformable::getRotation());
m_direction = m_originDirection.rotate(q).normalize();
m_right = m_originUp.cross(m_direction).normalize();
m_up = m_direction.cross(m_right).normalize();
if (Keyboard::isKeyPress(GLFW_KEY_A))
Transformable::translate(m_right * frametime * speed);
else if (Keyboard::isKeyPress(GLFW_KEY_D))
Transformable::translate(-m_right * frametime * speed);
if (Keyboard::isKeyPress(GLFW_KEY_W))
Transformable::translate(m_direction * frametime * speed);
else if (Keyboard::isKeyPress(GLFW_KEY_S))
Transformable::translate(-m_direction * frametime * speed);
if (Keyboard::isKeyPress(GLFW_KEY_Q))
Transformable::translate(-m_up * frametime * speed);
else if (Keyboard::isKeyPress(GLFW_KEY_E))
Transformable::translate(m_up * frametime * speed);
m_view = Matrix::lookAt(Transformable::getPosition(), Transformable::getPosition() + m_direction, m_up);
以及 lookAt 函数
Matrix Matrix::lookAt(Vector3 const & eye, Vector3 const & center, Vector3 const & up)
{
Vector3 f = (center - eye).normalize();
Vector3 u = up;
u.normalize();
Vector3 s = f.cross(u).normalize();
u = s.cross(f);
Matrix result(s.x, u.x, -f.x, 0.f,
s.y, u.y, -f.y, 0.f,
s.z, u.z, -f.z, 0.f,
-s.dotProduct(eye), -u.dotProduct(eye), f.dotProduct(eye), 1.f);
return (result);
}
有谁知道我的代码有什么问题吗? 如果缺少信息,请告诉我。
代码也在这个github分支shadow_map (github.com/jbalestr42/GraphicsEngine)
设置经典的 OpenGL 视图和投影矩阵,使视图 space 为右手,相机朝向 -z
方向,glOrtho
和 glFrustum
函数将 near
和 far
解释为沿视图方向的 距离 ,因此视图 space z
近坐标和远位面
z_near = -near
z_far = -far
而您的代码:
{ // near face {xn, yn, near, 1.f}, {-xn, yn, near, 1.f}, {xn, -yn, near, 1.f}, {-xn, -yn,near , 1.f}, // far face {xf, yf, far, 1.f}, {-xf, yf,far , 1.f}, {xf, -yf,far , 1.f}, {-xf, -yf,far, 1.f}, };
只是在+z
方向上绘制截锥体,预计最终会在相机后面。