В настоящее время я работаю над базовым приложением 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, дважды прочитал документацию и строго следовал ей … Но ничего не помогает.
Я что-то забыл где-то? Я не могу получить какие-либо идеи, где смотреть прямо сейчас.
Несколько проблем с кодом. Во-первых, вы настраиваете 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);
glFramebufferTexture2D
и на самом деле оно не должно быть связано с вами в любое время после его настройки. init_render_ovr
вы полностью настроили EyeTexture [0], но вы установили только пару значений в EyeTexture1. EyeTexture1 значения по умолчанию не совпадают со значениями в EyeTexture [0]. Вы должны инициализировать каждого участника. До тех пор, пока вы не решите проблему с черным экраном, ваш код должен быть полностью заправлен вызовами glGetError (). У меня есть GL_CHECK_ERROR, который в отладочных сборках расширяется до чего-то вроде этого:
GLenum errorCode = glGetError ();
if (errorCode! = 0) {
сгенерировать ошибку (errorCode);
}