Черный экран при рендеринге с Oculus SDK

В настоящее время я работаю над базовым приложением Oculus Rift на основе SDK 0.3.2 и OpenGL 3.2.0, чтобы научить меня использовать 3D-движок и технологию Oculus Rift.

Сейчас я пытаюсь сделать вращающийся куб внутри Oculus. Для искажения я решил использовать движок рендеринга, предоставленный командой Oculus Rift в SDK.
Итак, сначала я визуализирую свою сцену в одной текстуре, содержащей две копии сцены с другим цветом фона для визуализации (сейчас я не беспокоюсь о стереоскопическом аспекте), и я точно знаю, что это работает:

Скриншот текстуры двойного рендеринга
Окно слишком велико для того, чтобы оно полностью отображалось на экране, но мы можем четко видеть ту же сцену. Окно разрезано по центру


Изменить 4 (Финал):

После много методом проб и ошибок, а также советами Джерико, мне удалось заставить все работать.

Похоже, что в соответствии с Редактировать 3, Я должен был повторно связать буфер вершин glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); каждый кадр. Код (без стерео или отслеживания движения) можно найти Вот. Nota: режим MODE_OCULUS_DEBUG_ больше не работает. Аааа а изображение переворачивается

В заключение...


Изменить 3:

Я перешел на SDK 0.4.1 и последовал всем советам Джерико (кстати, огромное спасибо), и я в итоге с этим. Я действительно не знаю, что происходит. Но одна вещь, которую я заметил, это то, что мне иногда приходится связывать буфер кадра, используя glBindBuffer и иногда glBindFramebuffer… Имейте в виду, что на первом снимке экрана текстура все та же, что и в начале.
Я чувствую, что это проблема синхронизации кадров. Если я достаточно быстро запустил процесс обработки половины первого кадра, у меня не будет ошибок в первом кадре. Обратите внимание, что каждый раз я запускал половину рендера, а это значит, что мне приходилось запускать два раза, чтобы получить кадр. Тогда второй всегда так же, как первый, третий может быть блестящим, если я вызову его поздно, а затем он всегда глюки после четвертого кадра. Появляется глюк только однажды, Я не мог заставить его появиться два раза, даже если я буду ждать долго.

Я попытаюсь исследовать это завтра, но если у вас есть какие-либо идеи, или если это распространенная ошибка OpenGL или недоразумение, вы можете помочь 🙂

Ты можешь найти код здесь

Окулус Глюки


* Редактировать 1:
Я рисую сцену в текстуре, используя рамочный буфер. После ovrHmd_BeginFrame(hmd, 0) Скажите, я связываю кадровый буфер для рендеринга за пределами экрана:

обратите внимание, что текстуры [] содержат сетку и звезду, смешанные с использованием Fragment Shader из shaderProgram

glBindBuffer(GL_FRAMEBUFFER, frameBuffer);
glBindVertexArray(vertexArrayObject);
glEnable(GL_DEPTH_TEST);
glUseProgram(shaderProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);

framebuffer Он создан в этой функции, вызванной после init_ovr() но прежде init_render_ovr():

int init_framebuffers(){

// Framebuffers
//-----------------------------------------------
// In order to display, it has to be "complete" (at least 1 color/depth/stencil buffer attached, 1color attachement, same number of multisamples, attachement completes)
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);// ---- Texture "Color Buffer"glGenTextures(1, &renderedTex);
glBindTexture(GL_TEXTURE_2D, renderedTex);

glTexImage2D(renderedTex, 0, GL_RGB, renderTargetSize.w / 2, renderTargetSize.h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

// Attaching the color buffer to the frame Buffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderedTex, 0);// ---- RenderBuffer
// Render Buffer (to be able to render Depth calculation)
GLuint rboDepthStencil;
glGenRenderbuffers(1, &rboDepthStencil);
glBindRenderbuffer(GL_RENDERBUFFER, rboDepthStencil);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, renderTargetSize.w / 2, renderTargetSize.h);

// Attaching the render buffer to the framebuffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rboDepthStencil);// Binding the Frame Buffer so the rendering happens in it
glBindFramebuffer( GL_FRAMEBUFFER, frameBuffer );

return 0;
}

* Редактировать 2:
Итак, вот мой цикл рендеринга прямо сейчас:

ovrFrameTiming hdmFrameTiming = ovrHmd_BeginFrame (hmd, 0);

        for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++){

ovrEyeType eye = hmdDesc.EyeRenderOrder[eyeIndex];
ovrPosef eyePose = ovrHmd_BeginEyeRender(hmd, eye);

// Clear the screen and the depth buffer (as it is filled with 0 initially,
// nothing will be draw (0 = on top);
glClearColor(0.0f, 0.0f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_FRAMEBUFFER);

// Drawing in the FrameBuffer
glBindBuffer(GL_FRAMEBUFFER, frameBuffer);
glBindVertexArray(vertexArrayObject);
glEnable(GL_DEPTH_TEST);
glUseProgram(shaderProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);if (eye == ovrEye_Right){
glScissor(renderTargetSize.w / 2, 0, renderTargetSize.w / 2, renderTargetSize.h);
glViewport(renderTargetSize.w / 2, 0, renderTargetSize.w / 2, renderTargetSize.h);
}else{
glScissor(0, 0, renderTargetSize.w / 2, renderTargetSize.h);
glViewport(0, 0, renderTargetSize.w / 2, renderTargetSize.h);
}if (eye == ovrEye_Right)
glClearColor(0.0f, 0.3f, 0.0f, 1.0f);
else
glClearColor(0.3f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//Turn around Z
trans = glm::rotate(
trans,
0.7f,
glm::vec3(0.0f, 0.0f, 1.0f)
);
glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(trans));

// Drawing
glDrawArrays(GL_TRIANGLES, 0, 36);

// Unbind the custom frame Buffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);

ovrHmd_EndEyeRender(hmd, eye, eyePose, &EyeTexture[eye].Texture);

}

ovrHmd_EndFrame(hmd);

И моя конфигурация рендеринга:

EyeTexture[0].OGL.Header.API = ovrRenderAPI_OpenGL;
EyeTexture[0].OGL.Header.TextureSize = recommendedTex0Size;
EyeTexture[0].OGL.Header.RenderViewport.Size = recommendedTex0Size;
EyeTexture[0].OGL.Header.RenderViewport.Pos.x = 0;
EyeTexture[0].OGL.Header.RenderViewport.Pos.y = 0;
EyeTexture[0].OGL.TexId = renderedTex;EyeTexture[1].OGL.Header.API = ovrRenderAPI_OpenGL;
EyeTexture[1].OGL.Header.TextureSize = recommendedTex1Size;
EyeTexture[1].OGL.Header.RenderViewport.Size = recommendedTex1Size;
EyeTexture[1].OGL.Header.RenderViewport.Pos.x = recommendedTex1Size.w;
EyeTexture[1].OGL.Header.RenderViewport.Pos.y = 0;
EyeTexture[1].OGL.TexId = renderedTex;

Но я все еще не могу показать что-либо.


Исходное сообщение:

Итак, теперь я хочу исказить эту текстуру в бочку, используя Oculus SDK. Для этого я инициализирую движок Oculus:

int init_ovr(){

// Init the OVR library
ovr_Initialize();

// Create the software device and connect the physical device
hmd = ovrHmd_Create(0);
if (hmd)
ovrHmd_GetDesc( hmd, &hmdDesc );
else
return 1;

//Configuring the Texture size (bigger than screen for barrel distortion)
recommendedTex0Size = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, hmdDesc.DefaultEyeFov[0], 1.0f);
recommendedTex1Size = ovrHmd_GetFovTextureSize(hmd, ovrEye_Right, hmdDesc.DefaultEyeFov[1], 1.0f);

renderTargetSize.w = recommendedTex0Size.w + recommendedTex1Size.w;
renderTargetSize.h = std::max( recommendedTex0Size.h, recommendedTex1Size.h );return 0;
}

и рендеринг:

int init_render_ovr(){

// Configure rendering with OpenGL
ovrGLConfig cfg;
cfg.OGL.Header.API = ovrRenderAPI_OpenGL;
cfg.OGL.Header.RTSize = OVR::Sizei( hmdDesc.Resolution.w, hmdDesc.Resolution.h );
cfg.OGL.Header.Multisample = 0;
cfg.OGL.Window = sdl_window_info.info.win.window;

ovrFovPort eyesFov[2];
// I also tried =  { hmdDesc.DefaultEyeFov[0], hmdDesc.DefaultEyeFov[1] };

if ( !ovrHmd_ConfigureRendering(hmd, &cfg.Config, ovrDistortionCap_Chromatic | ovrDistortionCap_TimeWarp, eyesFov, eyesRenderDesc) )
return 1;

EyeTexture[0].OGL.Header.API = ovrRenderAPI_OpenGL;
EyeTexture[0].OGL.Header.TextureSize = recommendedTex0Size;
EyeTexture[0].OGL.Header.RenderViewport = eyesRenderDesc[0].DistortedViewport;
EyeTexture[0].OGL.TexId = renderedTex;

EyeTexture[1].OGL.Header.API = ovrRenderAPI_OpenGL;
EyeTexture[1].OGL.Header.TextureSize = recommendedTex1Size;
EyeTexture[1].OGL.Header.RenderViewport = eyesRenderDesc[1].DistortedViewport;
EyeTexture[1].OGL.TexId = renderedTex;

return 0;
}

Наконец, я вхожу в мой основной цикл рендеринга

        ovrFrameTiming hdmFrameTiming = ovrHmd_BeginFrame(hmd, 0);

for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++){

ovrEyeType eye = hmdDesc.EyeRenderOrder[eyeIndex];
ovrPosef eyePose = ovrHmd_BeginEyeRender(hmd, eye);

if (eye == ovrEye_Right){
glScissor(renderTargetSize.w / 2, 0, renderTargetSize.w / 2, renderTargetSize.h);
glViewport(renderTargetSize.w / 2, 0, renderTargetSize.w / 2, renderTargetSize.h);
}else{
glScissor(0, 0, renderTargetSize.w / 2, renderTargetSize.h);
glViewport(0, 0, renderTargetSize.w / 2, renderTargetSize.h);
}if (eye == ovrEye_Right)
glClearColor(0.0f, 0.3f, 0.0f, 1.0f);
else
glClearColor(0.3f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//Turn around Z
trans = glm::rotate(
trans,
0.7f,
glm::vec3(0.0f, 0.0f, 1.0f)
);
glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(trans));

// Drawing
glDrawArrays(GL_TRIANGLES, 0, 36);ovrHmd_EndEyeRender(hmd, eye, eyePose, &EyeTexture[eye].Texture);

}
ovrHmd_EndFrame(hmd);

Но в результате получается простой черный экран.
Я попытался переместить glViewport по всей длине, вручную установить структуру EyeRenderDesc, дважды прочитал документацию и строго следовал ей … Но ничего не помогает.

Я что-то забыл где-то? Я не могу получить какие-либо идеи, где смотреть прямо сейчас.

2

Решение

Несколько проблем с кодом. Во-первых, вы настраиваете EyeTexture структуры неправильно.

EyeTexture[0].OGL.Header.TextureSize = recommendedTex0Size;
EyeTexture[0].OGL.Header.RenderViewport = eyesRenderDesc[0].DistortedViewport;

DistortedViewport Используемое здесь значение указывает область на физическом экране, где будет расположен искаженный вид отрисованной сцены. Текстура RenderViewport С другой стороны, значение должно быть областью закадровой текстуры, в которую вы визуализировали сцену. Поскольку вы почти всегда хотите визуализировать всю текстуру, обычно этого достаточно:

EyeTexture[0].OGL.Header.TextureSize = recommendedTex0Size;
EyeTexture[0].OGL.Header.RenderViewport.Size = recommendedTex0Size;
EyeTexture[0].OGL.Header.RenderViewport.Pos.x = 0;
EyeTexture[0].OGL.Header.RenderViewport.Pos.y = 0;

Вы устанавливаете одинаковый идентификатор текстуры в обоих местах.

EyeTexture[0].OGL.TexId = renderedTex;
EyeTexture[1].OGL.TexId = renderedTex;

Вы Можно сделайте это, но затем вам придется сделать текстуру в два раза шире и установить соответствующие значения RenderViewport для каждой целевой половины текстуры. Лично я использую отдельную текстуру для каждого глаза, чтобы избежать этого.

Далее, в предоставленном вами примере кода вы не рендеритесь в буфер за пределами экрана.

for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++){
ovrEyeType eye = hmdDesc.EyeRenderOrder[eyeIndex];
ovrPosef eyePose = ovrHmd_BeginEyeRender(hmd, eye);

... lots of openGL viewport and draw calls ...

ovrHmd_EndEyeRender(hmd, eye, eyePose, &EyeTexture[eye].Texture);
}

Однако, чтобы искажение Oculus SDK сработало, вы не можете рисовать напрямую в основной кадровый буфер. Вам необходимо создать закадровые кадровые буферы, нацеленные на текстуры, указанные в EyeTexture массив.

for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++){
ovrEyeType eye = hmdDesc.EyeRenderOrder[eyeIndex];
ovrPosef eyePose = ovrHmd_BeginEyeRender(hmd, eye);

... activate offscreen framebuffer ...

... lots of openGL viewport and draw calls ...

... decativate offscreen framebuffer ...

ovrHmd_EndEyeRender(hmd, eye, eyePose, &EyeTexture[eye].Texture);
}

Вы можете увидеть полный пример этого Вот. Конечно, этот пример был обновлен для 0.4.x, так что вы можете вернуться в историю, пока не увидите ovrHmd_EndEyeRender (он был сброшен в последнем SDK).

РЕДАКТИРОВАТЬ:

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

            // Clear the screen and the depth buffer (as it is filled with 0 initially,
// nothing will be draw (0 = on top);
glClearColor(0.0f, 0.0f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_FRAMEBUFFER);

// Drawing in the FrameBuffer
glBindBuffer(GL_FRAMEBUFFER, frameBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, rboDepthStencil);
glEnable(GL_DEPTH_TEST);
  • GL_FRAMEBUFFER не является допустимым параметром для glClear. Я понятия не имею, какой эффект он будет иметь, но, вероятно, он не будет таким, как вы ожидаете.
  • Вызов glClear до вызов glBindBuffer означает, что вы на самом деле не очищаете целевую текстуру за пределами экрана. Вы очищаете фактический кадровый буфер рисования, который SDK будет делать в любом случае перед выполнением искажения. Переместите ваш вызов glClear внутрь операций кадрового буфера.
  • Вам не нужно вызывать glBindRenderbuffer. Я не уверен, какой эффект это даст, но если вы уже подключили рендеринг буфера deepStencil к объекту кадрового буфера, то он будет извлечен и использован автоматически при активации кадрового буфера.
  • Вы создаете текстуру RenderedTex, связываете ее, устанавливаете некоторые значения, а затем просто оставляете ее связанной. Это должно быть связано только достаточно долго, чтобы установить параметры. Должно не быть связанным, когда вы звоните glFramebufferTexture2Dи на самом деле оно не должно быть связано с вами в любое время после его настройки.
  • в init_render_ovr вы полностью настроили EyeTexture [0], но вы установили только пару значений в EyeTexture1. EyeTexture1 значения по умолчанию не совпадают со значениями в EyeTexture [0]. Вы должны инициализировать каждого участника.
  • До тех пор, пока вы не решите проблему с черным экраном, ваш код должен быть полностью заправлен вызовами glGetError (). У меня есть GL_CHECK_ERROR, который в отладочных сборках расширяется до чего-то вроде этого:

    GLenum errorCode = glGetError ();
    if (errorCode! = 0) {
    сгенерировать ошибку (errorCode);
    }

4

Другие решения


По вопросам рекламы [email protected]