我有一个配有眼动仪的Oculus Rift,用于根据眼动仪输入显示实时图像。我想对我处理Rift的显示方式有所了解(是不是?)。
我有一个简单文字的基本图像,使用OpenCV根据眼动仪的凝视坐标进行修改。因此,每次眼动仪输出凝视坐标(60Hz)时,我都会有一个新图像,就好像我正在使用网络摄像头流一样。我有一个工作程序,但由于我是OpenGL的新手,我希望有人可以通过以下步骤来查看我是否错过了一些东西。我将只包含以下书面评论的主要代码块:
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
谢谢!
答案 0 :(得分:1)
问题:两个屏幕当前都看到了相同的图像。这是为什么?两只眼睛不应该看到略有不同的图像吗?
occulus SDK不会为您创建立体图像对。这里只关注两件事:
为您提供正确的投影参数以及视点/方向
后处理用于在裂缝上显示的图像对(翘曲,校正色彩偏差)。
当您从SDK查询投影矩阵和视点位置时,实际上您没有对它进行任何操作。您只需将它们设置为OpenGL投影和模型视图矩阵,而无需使用它进行任何渲染。
代码应该将渲染到纹理中,为 3D 世界提供不同的视角,最后使用ovrHmd_EndFrame
对其进行后处理并渲染到实际窗口。
但是,您只需提供单视场输入纹理作为输入,完全跳过渲染步骤并直接对其进行后处理。
您无法从单个单视场图像中自动推断出立体图像对。
来自您的评论:
我知道这不是真正的3D,但我想知道如何修改单镜电脑游戏图像以显示左眼与右眼的不同视图。
这取决于你如何定义“monoscopic game”。这些游戏中的大多数实际上使用3D数据表示并将其渲染到屏幕上,从而创建2D投影。在这种情况下,对于立体输出,渲染必须进行两次,具有不同的投影和视图矩阵。
另一种方法是使用单视场图像和深度缓冲区创建另一个视图,通过基本上重新投影 3d 点(我们通过深度缓冲区得到)到silgihtly不同的视图配置,并填充所有洞。
但是,这些都不适用于
我有一张新图片,好像我正在使用网络摄像头流。
如果您只有单像摄像头,则无法直接获取渲染场景的不同视角所需的3D信息。有一些方法可以使用视频流的时间一致性来重建这些信息,请参阅structure from motion wikipedia artice。但这非常有限,不适用于任何实时使用。