Простой видеопоток на Oculus Rift DK2

У меня есть Oculus Rift, оснащенный трекером глаз, который я использую для отображения изображений в реальном времени на основе входных данных трекера глаз. Я хотел узнать ваше мнение о том, как я работаю с дисплеем в Rift (правильно ли это?).

У меня есть базовое изображение простого текста, которое изменяется с помощью OpenCV на основе координат взгляда из устройства отслеживания глаз. Таким образом, каждый раз, когда айтрекер выводит координаты взгляда (60 Гц), у меня появляется новое изображение, как будто я работаю с потоком веб-камеры. У меня есть рабочая программа, но, поскольку я новичок в 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(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, которую я изменяю с каждым кадром. Я читал о буферах кадра и о том, как их можно использовать, но даже после прочтения множества источников я очень запутался, следует ли их использовать для этого конкретного приложения. То, что я делаю, в порядке? Если есть источник, который вы можете порекомендовать, чтобы узнать больше об OpenGL для этого 2D-приложения, я был бы признателен.

ВОПРОС: Оба экрана в настоящее время видят одно и то же точное изображение. Это почему? Разве оба глаза не должны видеть немного разные изображения? Я неправильно настроил текстуры/окна просмотра? Если нужно, могу выложить весь код.

Когда я писал этот код, я использовал Rift 0.5.0, но теперь я обновился до бета-версии 0.8.0.

Спасибо!


person Anshul    schedule 04.01.2016    source источник
comment
Ожидаете ли вы, что Rift SDK волшебным образом превратит моноскопическое видео в стереоскопическое? Это не будет.   -  person derhass    schedule 05.01.2016
comment
Я использую одну и ту же текстуру для обоих глаз, но настраиваю окна просмотра по-разному. Я не знаю, как объяснить, что оба глаза видят немного разные части изображения. Я понимаю, что это не будет настоящим 3D, но я хотел бы знать, например, как можно изменить моноскопическое изображение компьютерной игры, чтобы показать немного разные виды для левого и правого глаза.   -  person Anshul    schedule 05.01.2016
comment
В том виде, в котором вы его настроили, ваш коврик должен иметь общую ширину обоих глаз, так ли это? Если да, то у вас должно быть по две копии текста в каждой половине мата, по одной для каждого глаза. Вы можете играть с относительной горизонтальной координатой текста, чтобы играть с наблюдаемой глубиной текста. Для более полезной настройки вам нужно будет работать с параметрами камеры CV.   -  person Joan Charmant    schedule 05.01.2016


Ответы (1)


ВОПРОС: Оба экрана в настоящее время видят одно и то же точное изображение. Это почему? Разве оба глаза не должны видеть немного разные изображения?

occulus SDK не создаст для вас пару стереоскопических изображений. Здесь будут беспокоить только две вещи:

  1. предоставить вам правильные параметры проекции, а также точку обзора / ориентацию

  2. постобработка пар изображений для отображения на рифте (деформация, коррекция хроматической аберрации).

Хотя вы запрашиваете матрицу проекции и положение точки обзора из SDK, на самом деле вы ничего с этим не делаете. Вы просто устанавливаете их как проекцию OpenGL и матрицу просмотра модели, никогда ничего не визуализируя с их помощью.

Предполагается, что код выполняет рендеринг в текстуры, обеспечивая другую перспективу в 3D мире и, наконец, используя ovrHmd_EndFrame для выполнения постобработки и рендеринга в реальном окне. .

Тем не менее, вы просто предоставляете свою моноскопическую входную текстуру в качестве входных данных, полностью пропускаете этап рендеринга и непосредственно выполняете ее постобработку.

Вы не можете автоматически вывести пару стереоскопических изображений из одного моноскопического изображения.

Из ваших комментариев:

Я понимаю, что это не будет настоящим 3D, но я хотел бы знать, например, как можно изменить моноскопическое изображение компьютерной игры, чтобы показать немного разные виды для левого и правого глаза.

Это зависит от того, как вы определяете «моноскопическую игру». Большинство этих игр на самом деле используют трехмерное представление данных и визуализируют их на экране, создавая двухмерную проекцию. В таком случае для стереоскопического вывода рендеринг должен быть выполнен дважды с разными матрицами проекции и вида.

Другим способом может быть использование моноскопического изображения и буфера глубины для создания другого вида путем перепроецирования точек 3d (которые мы получаем с помощью буфера глубины) в несколько иную конфигурацию вида и заполнения всех пробелов.

Однако ничего из этого не относится к

У меня есть новое изображение, как будто я работаю с потоком веб-камеры.

Если у вас есть только моноскопическая веб-камера, у вас нет прямого способа получить 3D-информацию, необходимую для рендеринга сцены с другой точки зрения. Существует несколько подходов к реконструкции такой информации с использованием временной когерентности видеопотоков, см. структура из статьи о движении в википедии. Но это крайне ограничено и неприменимо для любого использования в реальном времени.

person derhass    schedule 05.01.2016