使用不带 GLUT_STEREO 的 glFrustum 渲染两个重叠的 FOV

rendering two overlapped FOV using glFrustum without GLUT_STEREO

我有一个程序可以读取 360 单声道全景图并读取 IMU,根据头部位置绘制全景图的正确部分。

我正在创建两个 windows,每个显示器一个,不想依赖 GLUT_STEREO。因此,每个显示器的 draw() 调用都是独立的,但现在它们呈现相同的东西,即表示全景图的 gluSphere。为了绘制球体的正确部分,IMU 数据(四元数)变成了旋转矩阵,并且该矩阵与投影相乘。

我希望让两张图片有一点重叠,如下图所示:

例如,红色矩形是我左边的显示,蓝色矩形是我右边的显示,但是中间有一些重叠。

我正在阅读一些关于立体渲染的文章,我认为解决方案是替换从 gluPerspective() 到 glFrustum() 的调用,并简单地同时修改左右参数。我认为在显示器上减去 glFrustum() 的 left/right 参数的一些值并向 glFrustum() 的 left/right 参数添加一些值就可以了。我修改了 glutReshapeFunc() 回调的投影矩阵来做到这一点:

void resize(int width, int height)
{
  glViewport(0, 0, width, height);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  GLdouble near = 0.1;
  GLdouble far = 100.0;

  GLdouble aspect = (double) width / (double) height;
  GLdouble top = tan(FOVY / 360 * M_PI) * near;
  GLdouble bottom = -top;
  GLdouble right = top * aspect;
  GLdouble left = -right;

  // TODO: Canned value for testing
  left += 0.5;
  right += 0.5;

  glFrustum(left, right, bottom, top, near, far);
  //  gluPerspective(FOVY, aspect, near, far);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}

不幸的是,这并没有达到我的预期(我真的不确定为什么)。我认为修改 glFrustum() 的左右参数将保持相同的水平 FOV,但将其向左或向右移动。它似乎要么向内拉伸,要么向外拉伸。

我在 ModelView 或 glLookAt() 上使用过 glTranslatef() 或 glLookAt(),但有些地方我不清楚。为什么 glFrustum() 没有正确的行为,我错过了什么?

修改视锥相机。

您需要两个不同的相机矩阵来模拟眼睛分离和稍微不同的截锥体来消除内束。

3D 立体渲染 使用 OpenGL(和 GLUT):

/* Misc stuff */
ratio  = camera.screenwidth / (double)camera.screenheight;
radians = DTOR * camera.aperture / 2;
wd2     = near * tan(radians);
ndfl    = near / camera.focallength;

/* Derive the two eye positions */
CROSSPROD(camera.vd,camera.vu,r);
Normalise(&r);
r.x *= camera.eyesep / 2.0;
r.y *= camera.eyesep / 2.0;
r.z *= camera.eyesep / 2.0;

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
left  = - ratio * wd2 - 0.5 * camera.eyesep * ndfl;
right =   ratio * wd2 - 0.5 * camera.eyesep * ndfl;
top    =   wd2;
bottom = - wd2;
glFrustum(left,right,bottom,top,near,far);

glMatrixMode(GL_MODELVIEW);
glDrawBuffer(GL_BACK_RIGHT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(camera.vp.x + r.x,camera.vp.y + r.y,camera.vp.z + r.z,
          camera.vp.x + r.x + camera.vd.x,
          camera.vp.y + r.y + camera.vd.y,
          camera.vp.z + r.z + camera.vd.z,
          camera.vu.x,camera.vu.y,camera.vu.z);
MakeLighting();
MakeGeometry();

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
left  = - ratio * wd2 + 0.5 * camera.eyesep * ndfl;
right =   ratio * wd2 + 0.5 * camera.eyesep * ndfl;
top    =   wd2;
bottom = - wd2;
glFrustum(left,right,bottom,top,near,far);

glMatrixMode(GL_MODELVIEW);
glDrawBuffer(GL_BACK_LEFT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(camera.vp.x - r.x,camera.vp.y - r.y,camera.vp.z - r.z,
          camera.vp.x - r.x + camera.vd.x,
          camera.vp.y - r.y + camera.vd.y,
          camera.vp.z - r.z + camera.vd.z,
          camera.vu.x,camera.vu.y,camera.vu.z);
MakeLighting();
MakeGeometry();

glutSwapBuffers();

用适当的 FBO 绑定替换 glDrawBuffer() 调用。