【发布时间】:2016-01-04 22:27:40
【问题描述】:
我有一个装有眼动仪的 Oculus Rift,用于根据眼动仪输入显示实时图像。我想听听你对我处理 Rift 显示的方式的意见(对吗?)。
我有一个简单文本的基本图像,它使用 OpenCV 根据眼动仪的注视坐标进行了修改。因此,每次眼动仪输出注视坐标 (60Hz) 时,我都会得到一张新图像,就好像我在使用网络摄像头流一样。我有一个工作程序,但是由于我是 OpenGL 的新手,我希望有人可以通过以下步骤来查看我是否没有遗漏任何东西。我只会在下面包含带有书面 cmets 的主要代码块:
1) 首先,我创建并绑定一个纹理。 matToTexture 是将 cv::mat 图像转换为纹理的函数。
tex = matToTexture(result, GL_NEAREST, GL_NEAREST, GL_CLAMP);
glBindTexture(GL_TEXTURE_2D, tex)
2) 然后我制作眼睛渲染缓冲区并设置 VR 组件,获取眼睛姿势等:
for (int eye=0; eye<2; eye++)
{
idealSize = ovrHmd_GetFovTextureSize(hmd, (ovrEyeType)eye, hmd->DefaultEyeFov[eye], 1.0f);
EyeRenderTexture[eye] = tex;
//EyeRenderViewport[eye].Pos.x = 0;
EyeRenderViewport[0].Pos.x =0;
EyeRenderViewport[1].Pos.x = idealSize.w/2;
EyeRenderViewport[eye].Pos.y = 0;
EyeRenderViewport[eye].Size = idealSize;
}
//Setup VR components
ovrGLConfig oglcfg;
oglcfg.OGL.Header.API = ovrRenderAPI_OpenGL;
oglcfg.OGL.Header.BackBufferSize.w = hmd->Resolution.w;
oglcfg.OGL.Header.BackBufferSize.h = hmd->Resolution.h;
oglcfg.OGL.Header.Multisample = 1;
oglcfg.OGL.Window = handle;
oglcfg.OGL.DC = GetDC(handle);
if (!ovrHmd_ConfigureRendering(hmd, &oglcfg.Config,
ovrDistortionCap_Vignette |
ovrDistortionCap_TimeWarp | ovrDistortionCap_Overdrive,
hmd->DefaultEyeFov, EyeRenderDesc))
return(1);
//Getting eye pose outside the loop since our pose will remain static
ovrVector3f useHmdToEyeViewOffset[2]= {EyeRenderDesc[0].HmdToEyeViewOffset, EyeRenderDesc[1].HmdToEyeViewOffset};
ovrHmd_GetEyePoses(hmd, 0, useHmdToEyeViewOffset, EyeRenderPose, NULL);
glGenTextures(1, &textureID);
//Changing eye tracking location from 1920-1080 to 2364-1461 since that is
//optimal buffer size
float x_scale = static_cast<float>(image.cols)/static_cast<float>(hmd->Resolution.w);
float y_scale = static_cast<float>(image.rows)/static_cast<float>(hmd->Resolution.h);
//x_adjusted and y_adjusted store the new adjusted x,y values
float x_adjusted, y_adjusted;
最后,我有渲染while循环
while(1)
{
//Changing the texture dynamically because the result image is changing
//with eye tracker input
tex = matToTexture(result, GL_NEAREST, GL_NEAREST, GL_CLAMP);
glBindTexture(GL_TEXTURE_2D, tex);
for (int eye = 0; eye<2; eye++)
{
projection[eye] = ovrMatrix4f_Projection(EyeRenderDesc[eye].Fov, 1, 1000, 1);
glMatrixMode(GL_PROJECTION);
glLoadTransposeMatrixf(projection[eye].M[0]);
EyeRenderTexture[eye] = tex;
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(EyeRenderDesc[eye].HmdToEyeViewOffset.x,-EyeRenderDesc[eye].HmdToEyeViewOffset.y, EyeRenderDesc[eye].HmdToEyeViewOffset.z);
//Distortion Rendering
eyeTexture[eye].OGL.Header.API = ovrRenderAPI_OpenGL;
//eyeTexture[eye].OGL.Header.TextureSize = idealSize;
eyeTexture[eye].OGL.Header.TextureSize.h = idealSize.h;
eyeTexture[eye].OGL.Header.TextureSize.w = 2*idealSize.w;
eyeTexture[eye].OGL.Header.RenderViewport.Size = idealSize;
eyeTexture[0].OGL.Header.RenderViewport.Pos.x = 0;
eyeTexture[1].OGL.Header.RenderViewport.Pos.x = idealSize.w;
eyeTexture[eye].OGL.Header.RenderViewport.Pos.y = 0;
eyeTexture[eye].OGL.TexId = EyeRenderTexture[eye];
}
ovrHmd_EndFrame(hmd, EyeRenderPose, &eyeTexture[0].Texture);
//restoring result back to original so that new scotoma position
//can be added onto it
image.copyTo(result);
// Clear the screen to black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
//Exiting loop if 'q' is pressed
if (quit == 1) break;
}
glDeleteTextures(1, &tex);
所以我只有一个 OpenGL 纹理,每帧都会修改它。我已经阅读了有关帧缓冲区以及如何使用它们的信息,但是即使在阅读了一堆来源之后,我仍然对它们是否应该用于这个特定的应用程序感到非常困惑。我在做什么好吗?如果有可以推荐的资源来了解有关此 2D 应用程序的 OpenGL 的更多信息,我将不胜感激。
问题:两个屏幕当前看到的图像完全相同。这是为什么?两只眼睛不应该看到略有不同的图像吗?我没有正确设置眼睛纹理/视口吗?如果需要,我可以上传整个代码。
当我编写这段代码时,我使用的是 Rift 0.5.0,但现在我升级到了 0.8.0 beta
谢谢!
【问题讨论】:
-
你期待 rift SDK 神奇地将单视场视频变成立体视频吗?不会的。
-
我对双眼使用相同的纹理,但视口设置不同。我不知道如何解释两只眼睛看到的图像略有不同的部分。我知道这不是真正的 3D,但我想知道例如如何修改单视场计算机游戏图像以在左眼和右眼上显示略微不同的视图。
-
你设置的垫子应该是双眼的总宽度,是这样吗?如果是这样,您应该在垫子的每一半中都有两份文本,每只眼睛一份。您可以使用文本的相对水平坐标来播放观察到的文本深度。要进行更有用的调整,您需要使用 CV 相机参数。