使用 Qt/OpenGL 保持正交投影成比例的问题
Problems keeping orthographic projection proportional using Qt/OpenGL
我很难理解我应该在对 QMatrix4x4::ortho(left, right, bottom, top, near, far) 的调用中使用什么值。
具体来说,我不理解有关左、右、下和上值的文档。我有一个可以使用投影矩阵绘制 OpenGL 猴子的工作演示。我设置了演示,以便当我在键盘上按下 'O' 时,它会将投影矩阵从透视切换到正交。透视投影效果很好,因为它使模型的纵横比保持不变(即它不会在宽度或高度上拉伸)。这是调用 'O' 或 'P' 键并更新 m_proj 时调用的函数。如您所见,这有点乱七八糟,我已经尝试了很多想法,none 其中的想法确实按照我想要的方式工作。
感谢任何有助于我理解这一点的见解。其他有用的细节:我的视线位于 z=2 面向中心 (0,0,0),向上为 (0,1,0)。
void AppGLScene::setProjectionMatrix(void)
{
m_projectionMatrix.setToIdentity();
float windowWidth = rect().width();
float windowHeight = rect().height();
float left, right, bottom, top;
float aratio = (float) windowWidth / (float) windowHeight;
qDebug() << "win wid, win hei" << windowWidth << windowHeight;
// I modify the vertical FOV in an attempt to keep the size of the
// model the same as the vertical size of the window changes.
//
float vFov = 90 * ((float)windowHeight / m_initialWinHeight);
qDebug() << "vFov" << vFov;
switch (m_proj)
{
case PROJ_PERSP:
m_projectionMatrix.perspective(vFov, qreal(windowWidth)/qreal(windowHeight), 0.5, 40);
break;
case PROJ_ORTHO:
default:
// left = rect().x();
// right = rect().x() + rect().width();
// bottom = rect().y();
// top = rect().y() + rect().height();
if (windowWidth > windowHeight)
{
left = -(3.0 - ((float)windowHeight/(float)windowWidth));
right = -left;
bottom = -3.0;
top = 3.0;
}
else
{
left = -3.0;
right = 3.0;
bottom = -(3.0 - ((float)windowWidth/(float)windowHeight));
top = -bottom;
}
qDebug() << "l r b t = " << left << right << bottom << top;
m_projectionMatrix.ortho(left, right, bottom, top, 0.5, 40);
// m_projectionMatrix.ortho(-3.0, 3.0, -3.0, 3.0, 0.5, 40);
// m_projectionMatrix.ortho(-aratio, aratio, -aratio, aratio, 0.5, 40);
break;
}
}
为避免在任一方向拉伸对象,您需要 (右 - 左)/(上 - 下) 与 window 的纵横比相匹配.在您的情况下,您可以通过 right 将 top 的值乘以纵横比来确保。
您似乎想对较短的 window 维度使用范围 [-3.0, 3.0],并相应地调整较长的维度。上面然后翻译成:
if (windowWidth > windowHeight)
{
top = 3.0f;
bottom = -top;
right = top * aratio;
left = -right;
}
else
{
right = 3.0f;
left = -right;
top = right / aratio;
bottom = -top;
}
请注意,对于这两种情况,right / top = aratio。
我很难理解我应该在对 QMatrix4x4::ortho(left, right, bottom, top, near, far) 的调用中使用什么值。
具体来说,我不理解有关左、右、下和上值的文档。我有一个可以使用投影矩阵绘制 OpenGL 猴子的工作演示。我设置了演示,以便当我在键盘上按下 'O' 时,它会将投影矩阵从透视切换到正交。透视投影效果很好,因为它使模型的纵横比保持不变(即它不会在宽度或高度上拉伸)。这是调用 'O' 或 'P' 键并更新 m_proj 时调用的函数。如您所见,这有点乱七八糟,我已经尝试了很多想法,none 其中的想法确实按照我想要的方式工作。
感谢任何有助于我理解这一点的见解。其他有用的细节:我的视线位于 z=2 面向中心 (0,0,0),向上为 (0,1,0)。
void AppGLScene::setProjectionMatrix(void)
{
m_projectionMatrix.setToIdentity();
float windowWidth = rect().width();
float windowHeight = rect().height();
float left, right, bottom, top;
float aratio = (float) windowWidth / (float) windowHeight;
qDebug() << "win wid, win hei" << windowWidth << windowHeight;
// I modify the vertical FOV in an attempt to keep the size of the
// model the same as the vertical size of the window changes.
//
float vFov = 90 * ((float)windowHeight / m_initialWinHeight);
qDebug() << "vFov" << vFov;
switch (m_proj)
{
case PROJ_PERSP:
m_projectionMatrix.perspective(vFov, qreal(windowWidth)/qreal(windowHeight), 0.5, 40);
break;
case PROJ_ORTHO:
default:
// left = rect().x();
// right = rect().x() + rect().width();
// bottom = rect().y();
// top = rect().y() + rect().height();
if (windowWidth > windowHeight)
{
left = -(3.0 - ((float)windowHeight/(float)windowWidth));
right = -left;
bottom = -3.0;
top = 3.0;
}
else
{
left = -3.0;
right = 3.0;
bottom = -(3.0 - ((float)windowWidth/(float)windowHeight));
top = -bottom;
}
qDebug() << "l r b t = " << left << right << bottom << top;
m_projectionMatrix.ortho(left, right, bottom, top, 0.5, 40);
// m_projectionMatrix.ortho(-3.0, 3.0, -3.0, 3.0, 0.5, 40);
// m_projectionMatrix.ortho(-aratio, aratio, -aratio, aratio, 0.5, 40);
break;
}
}
为避免在任一方向拉伸对象,您需要 (右 - 左)/(上 - 下) 与 window 的纵横比相匹配.在您的情况下,您可以通过 right 将 top 的值乘以纵横比来确保。
您似乎想对较短的 window 维度使用范围 [-3.0, 3.0],并相应地调整较长的维度。上面然后翻译成:
if (windowWidth > windowHeight)
{
top = 3.0f;
bottom = -top;
right = top * aratio;
left = -right;
}
else
{
right = 3.0f;
left = -right;
top = right / aratio;
bottom = -top;
}
请注意,对于这两种情况,right / top = aratio。