c++ - Oculus Rift DK2 上的简单视频流

标签 c++ opencv opengl oculus

我有一台配备眼动仪的 Oculus Rift,用于根据眼动仪输入显示实时图像。我想听听您对我处理 Rift 显示的方式的意见(对吗?)。

我有一个简单文本的基本图像,它是根据眼动仪的注视坐标使用 OpenCV 修改的。因此,每次眼动仪输出注视坐标 (60Hz) 时,我都会得到一张新图像,就好像我正在使用网络摄像头流一样。我有一个工作程序,但由于我是 OpenGL 的新手,我希望有人可以完成以下步骤,看看我是否没有遗漏任何东西。我只会在下面包含主要的代码块和书面评论:

1) 首先,我创建并绑定(bind)一个纹理。 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 的更多信息,我将不胜感激。

问题:两个屏幕目前都看到完全相同的图像。这是为什么?两只眼睛不应该看到略有不同的图像吗?我没有正确设置眼睛纹理/视口(viewport)吗?如果需要,我可以上传整个代码。

当我编写这段代码时,我使用的是 Rift 0.5.0,但现在我升级到了 0.8.0 beta

谢谢!

最佳答案

QUESTION: Both the screens currently see the same exact image. Why is that? Shouldn't both eyes see slightly different images?

occulus SDK 不会为您创建立体图像对。这里只有两件事值得关注:

  1. 为您提供正确的投影参数以及视点/方向

  2. 后处理图像对以在裂缝上显示(变形、色差校正)。

虽然您确实从 SDK 查询了投影矩阵和视点位置,但您实际上并没有对其进行任何操作。您只需将它们设置为 OpenGL 投影和模型 View 矩阵,无需使用它渲染任何内容

代码应该将渲染到纹理中,为3D世界提供不同的视角,最后使用ovrHmd_EndFrame来完成对其进行后处理并渲染到实际窗口。

但是,您只需提供单视场输入纹理作为输入,完全跳过渲染步骤并直接对其进行后处理。

您不能从单个单视场图像自动推断出立体图像对。

来自您的评论:

I understand that won't be real 3D, but I would like to know for example how a monoscopic computer game image can be modified to show slighlty different views on left vs. right eye.

这取决于您如何定义“单视场游戏”。这些游戏中的大多数实际上使用 3D 数据表示并将其渲染到屏幕上,从而创建 2D 投影。在这种情况下,对于立体输出,渲染必须进行两次,使用不同的投影和 View 矩阵。

另一种方法是使用单视场图像和深度缓冲区来创建另一个 View ,方法是将 3d 点(我们通过深度缓冲区获得)重新投影到完全不同的 View 配置,并填充所有洞。

然而,这些都不适用于

I have a new image so it is as if I'm working with a webcam stream.

如果您只有单视场网络摄像头,则无法直接获取渲染场景不同视角所需的 3D 信息。有一些方法可以使用视频流的时间相干性来重建此类信息,请参阅 structure from motion wikipedia artice .但这非常有限,不适用于任何实时使用。

关于c++ - Oculus Rift DK2 上的简单视频流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34601009/

相关文章:

c++ - itk 注册两个不同大小的 3D 图像太慢

c - 在经典代码 opencv c++ 中使用池化层

c++ - 在 C++、OpenGL 中使用 De Casteljau 算法绘制贝塞尔曲线

opengl - glBlitFramebuffer 导致访问冲突

C++:变量不受 Void 函数影响

c++ - 发布和调试之间的 ABI 兼容性

python - cv2.destroyAllWindows() 的功能是什么?

c++ - OpenGL绘制多个对象的正确方法?

c++ - [链接器错误] 未定义对 `Set<std::string>::contains(std::string const&) const' 的引用

opencv - 编译OpenCV 3.1.0 videoio错误