如何实现OpenGL的缩放功能?

3

我有一个OpenGL应用程序,实现了导航功能,如环绕、行走、平移、旋转等,用于在3D环境中导航。所有这些都能完美地工作,并且使用gluPerspectivegluLookAt设置起来相当简单。

glMatrixMode GL_PROJECTION
   glLoadIdentity
   gluPerspective m_ViewAngle, m_AspectRatio, m_ClipDistance_Near, m_ClipDistance_Far          

   glMatrixMode GL_MODELVIEW
   glLoadIdentity
   gluLookAt m_Eye.X, m_Eye.Y, m_Eye.Z, m_Focus.X, m_Focus.Y, m_Focus.Z, m_ViewUP.X, m_ViewUP.Y, m_ViewUP.Z

   glCallList DisplayListIndex

类似于CAD软件中的典型“ZoomExtents”或“ZoomToFit”命令,从任意视点(视线方向),我希望能够缩放以便: (1) 整个3D环境可见,并且 (2) 3D环境模型填充整个视口(在当前视口大小下尽可能大)。
我知道环境边界框(极值XYZ)。然而,我无法推导出给定ViewAngle和AspectRatio以及环境极值的Eye和Focus位置应该是什么。
也许有一种比使用“gluLookAt”更容易实现这一目标的方法。感谢您的帮助!
2个回答

2
实际上,这可以更加“容易”地完成。
你需要做的是将你的模型投影到一个平面上。然后,确定最高点和最低点(顶部y,底部y,最左x,最右x),最后确定你需要多少缩放才能将这个矩形适应实际需要的矩形。
你需要投影的平面是屏幕平面。
幸运的是,你已经在做这个了。
所以,使用你已经设置好的矩阵来转换你模型的每个点,并确定最大点。
计算出你需要多少缩放来适应屏幕。并将此缩放应用于对象的缩放中。
就是这样。

我想问一下,当你说“你已经在做这个了”的时候,我的理解是OpenGL正在为他完成这个操作?我不知道如何访问这些计算的结果。这容易吗?如果不容易,他需要在自己的代码中复制矩阵/顶点运算:取PROJECTION和MODELVIEW矩阵,将它们与模型中的每个顶点相乘等等。一个快捷方式是只对整个模型的边界框执行相同的计算,而不是对模型中的每个顶点执行。 - Jonathan Hartley
啊,鉴于JRS对这个问题的其他答案的评论,很明显边界框快捷方式是不够的。 - Jonathan Hartley

1
将整个物体近似为一个球体,并应用以下公式乘以像素到模型单位比率。您可以通过在已知z坐标处渲染单位球体来计算像素到模型单位比率。球体的好处是,无论从哪个角度观察,其宽度始终是直径。有关详细信息,请参见透视投影

alt text

编辑:球体的好处在于它与方向无关。无论是盒子还是球体,您都需要指定相机向量和向量的方向。一旦您有了这个,唯一未知的就是从眼睛视角的深度z。从那里,您可以通过以下方式计算眼睛的位置:

 eye := (center.x, center.y, center.z) - depth * (camera.x, camera.y, camera.z)

从公式中,Bx := Ax * Bz / Az,你可以推导出 Bz := Bx * Az / Ax
让我定义一个模型坐标1.0为1.0米。假设半径为1.0米的球体在距离100.0米处看起来有20个像素宽。
Bz := 1.0 * 100.0 / 10
Bz := 10.0

现在假设你的边界框宽度为200.0米,这使得Ax为100.0,而你的屏幕宽度为1024像素,这使得Bx为512像素。

Az := (Ax / Bx) * Bz
Az := (100.0/512.0) * 10.0
Az := 1.953m

在上述代码中,m和像素之间的单位转换被Bz吸收了。

假设向上的向量为(0,0,1),相机向量为(1,0,0),中心点为(0,0,0)。

eye := center - depth * camera
eye := (0, 0, 0) - 1.953 * (1, 0, 0)
eye := (-1.953, 0, 0)

使用一个球体是行不通的。它保证整个环境都可见。然而,这种方法并不能在所有情况下使环境尽可能大地显示在屏幕上(例如,当包围盒的尺寸为X=10,Y=10,Z=2,并且视点从侧面看时)。 - JRS
1
如果这是你的抱怨,那么当从非轴向对齐的方向查看场景时,基于轴的边界框同样无用。那么你需要使用场景的凸包。 - Eric
JRS:我一开始没有理解你的评论。我想你的意思是说当边界框大小为X=10,Y=2,Z=2,并且从侧面观察时它不起作用。 - Jonathan Hartley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接