【问题标题】:Simple video stream on the Oculus Rift DK2Oculus Rift DK2 上的简单视频流
【发布时间】: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 相机参数。

标签: c++ opencv opengl oculus


【解决方案1】:

问题:两个屏幕当前看到的图像完全相同。这是为什么?两只眼睛不应该看到略有不同的图像吗?

Oculus SDK 不会为您创建立体图像对。这里只需要关注两件事:

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

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

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

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

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

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

来自您的 cmets:

我知道这不是真正的 3D,但我想知道例如如何修改单视场计算机游戏图像以在左眼和右眼上显示略微不同的视图。

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

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

但是,这些都不适用于

我有一个新图像,所以就好像我在使用网络摄像头流一样。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多