gluLookAt和glFrustum带有移动物体

时间:2011-10-12 17:07:53

标签: c++ opengl

原始问题/代码

我正在调整3D对象的渲染并尝试使用gluLookAt在对象后面实现相机,因为对象的中心y位置一旦达到其最大高度就会不断增加。下面是我设置ModelView和Projection矩阵的代码部分:

float diam = std::max(_framesize, _maxNumRows);
float centerX = _framesize / 2.0f;
float centerY = _maxNumRows / 2.0f + _cameraOffset;
float centerZ = 0.0f;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(centerX - diam,
          centerX + diam,
          centerY - diam,
          centerY + diam,
          diam,
          40 * diam);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0., 0., 2. * diam, centerX, centerY, centerZ, 0, 1.0, 0.0);

目前,该对象显示距离很远,并且似乎进一步返回到屏幕(-z)和向下(-y),直到它最终消失。

我做错了什么?如何让我的曲面出现在屏幕中央,占据整个视图,相机随着对象移动而移动?


更新了代码和当前问题

这是我当前的代码,它现在将对象置于死角并填满我的窗口。

float diam = std::max(_framesize, _maxNumRows);
float centerX = _framesize / 2.0f;
float centerY = _maxNumRows / 2.0f + _cameraOffset;
float centerZ = 0.0f;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(centerX - diam,
          centerX,
          centerY - diam,
          centerY,
          1.0,
          1.0 +  4 * diam);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(centerX, _cameraOffset, diam, centerX, centerY, centerZ, 0, 1.0, 0.0);

当被查看的对象开始移动时,我仍然有一个问题,它不会完全居中。它似乎几乎抖动一个像素,然后在更新时下降2个像素。最终,对象离开当前视图。如何解决这种抖动?

3 个答案:

答案 0 :(得分:5)

您的问题在于了解投影的作用。在您的情况下 glFrustum 。我认为解释glFrustum的最佳方式是通过图片(我只是手绘)。你开始一个名为 Eye Space 的空间。它是由 modelview 矩阵转换后顶点所在的空间。需要将此空间转换为名为规范化设备坐标空间的空间。这发生在两个过程中:

  1. Eye Space 被投影(矩阵)转换为剪辑空间
  2. 应用透视分割{X,Y,Z} = {x,y,z} / w,将其带入规范化设备坐标空间。
  3. 这种可见效果是OpenGL的“镜头”。在下面的图片中,您可以看到眼睛空间中的绿色突出显示区域(技术上是3个体积),即NDC空间反投影到其中。在大写的情况下,示出了对称平截头体的效果,即left = -righttop = -bottom。在底部图片中显示了不对称的平截头体,即left ≠ -righttop ≠ -bottom

    The effect of glFrustum

    请注意,应用这种不对称性(通过中心偏移)不会转动,即旋转你的平截头体,但会使其偏斜。然而,“相机”将保持在原点,仍然指向-Z轴。当然,图像投影的中心会发生变化,但这不是你想要的。

    像这样的平截头体歪斜有应用程序。最重要的是,正确的方法是实现左眼和右眼的不同视图和立体渲染设置。

答案 1 :(得分:2)

glFrustum生成的透视投影矩阵用原点处的相机定义了一个相机空间(它作为输入的顶点空间)。您正在尝试使用不在原点的相机创建透视矩阵。 glFrustum不能这样做,所以你尝试这样做的方式根本行不通。

有一些方法可以生成相机不在原点的透视矩阵。但这样做真的没有意义。

通常处理移动摄像机的方式是简单地将世界空间的变换添加到透视投影的摄像机空间。这只是旋转并将世界转换为相对于相机。这是gluLookAt的工作。但你的参数也是错误的。

前三个值是相机的世界空间位置。接下来的三个应该是相机应该看的世界空间位置(物体的位置)。

答案 2 :(得分:2)

Nicol Bolas的回答几乎可以说明你做错了什么,所以我会跳过这个。你正在寻找一个解决方案,而不是告诉你什么是错的,所以让我们直接进入它。

这是我用于投影矩阵的代码:

glViewport(0, 0, mySize.x, mySize.y);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fovy, (float)mySize.x/(float)mySize.y, nearPlane, farPlane);

用一些词来形容它: glViewport在窗口内设置openGL显示位置的大小和位置。 Dunno为什么,我总是把它包括在投影更新中。如果你像我一样使用它,其中mySize是指定窗口尺寸的2D矢量,openGL渲染区域将会占据整个窗口。你应该熟悉2个下一个电话,最后是gluPerspective。第一个参数是您的“Y轴视野”。它指定了你将看到多少度的角度,我从未使用过45以外的任何东西。虽然它可以用于缩放,但我更喜欢将其留给相机操作。第二个参数是方面。如果你渲染方形并且你的窗口大小不是1:1的比例,它会处理它,它仍然是方形的。第三个是靠近剪裁平面,几何形状比相机更接近相机不会被渲染,与farPlane相同,但相反它设置了几何体渲染的最大距离。

这是modelview矩阵的代码

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(  camera.GetEye().x,camera.GetEye().y,camera.GetEye().z,
camera.GetLookAt().x,camera.GetLookAt().y,camera.GetLookAt().z,
camera.GetUp().x,camera.GetUp().y,camera.GetUp().z);

还有一些你应该知道的事情:同样,你可以使用前2个电话,所以我们跳到gluLookAt。我有相机类来处理所有的运动,旋转,这样的事情。 Eye,LookAt和Up是3D矢量,这3个实际上是摄像机指定的所有内容。眼睛是相机的位置,它在空间中。 LookAt是您正在查看的对象的位置,或更好的3D空间中您正在寻找的点,因为它实际上可以是任何地方而不仅仅是中心对象。如果你担心怎么了Up矢量,它真的很简单。它是矢量perpeicular to vector(LookAt-Eye),但是因为有无数个这样的向量,你必须指定一个。如果您的相机位于(0,0,0)并且您正在查看(0,0,-1)并且您想要站在腿上,那么向上矢量将为(0,1,0)。如果您想站在头上,请使用(0,-1,0)。如果你没有得到这个想法,那就写下评论吧。

由于您没有任何相机类,您需要自己分别存储这3个矢量。我相信你有像移动3D物体中心的东西。每次更新后将该位置设置为LookAt。同样在初始化阶段(当您制作3D对象时)选择摄像机位置和向上矢量。每次更新到对象位置后,以相同的方式更新摄像机位置。如果将对象在Y轴上向上移动1点,请对相机位置执行相同操作。如果您不想旋转相机,向上矢量保持不变。在每次更新后,使用更新的向量调用gluLookAt

有关更新的帖子: 如果没有更大的参考框架,我真的不会得到正在发生的事情(但我还是不想知道它)。我很少有好奇的东西。如果center是存储对象位置的3D矢量,为什么要将此对象的中心设置在窗口的右上角?如果它是中心,那么你应该在glOrtho的第2和第4个参数中得到那些+ diam,如果这样做会使事情变得糟糕,那么你在变量之前使用了错误的名称,或者在错误之前做某事。您正在更新的帖子中设置LookAt位置,但我不知道您为Eye使用这些参数的原因。您应该更像centerX, centerY, centerZ-diam作为gluLookAt中的前3个参数。这使得相机在与物体相同的X和Y位置上,但您将沿着Z轴从距离diam

查看它