c++ - 使用 Oculus SDK 渲染时出现黑屏

标签 c++ c opengl oculus

我目前正在开发一个基于 SDK 0.3.2 和 OpenGL 3.2.0 的基本 Oculus Rift 应用程序,以便让我习惯 3D 引擎和 Oculus Rift 技术。

现在我正在尝试在 Oculus 内渲染一个旋转立方体。对于失真,我决定使用 Oculus Rift 团队在 SDK 中提供的渲染引擎。 因此,首先我在单个纹理中渲染我的场景,其中包含具有不同背景颜色的场景的两个拷贝以进行可视化(目前我不关心立体方面),并且我知道它有效的事实:

Texture double rendering Screenshot 窗口太大,无法完全显示在屏幕上,但我们可以清楚地看到相同的场景。窗口在其中心被切割


编辑 4(最终):

经过大量的尝试和错误以及 Jherico 的建议,我成功地让一切运行起来。

看来,重新编辑编辑3时,我必须在每一帧重新绑定(bind)顶点缓冲区glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);。代码(没有立体声或运动跟踪)可以找到 here注意:MODE_OCULUS_DEBUG_ 模式不再起作用。啊啊图像被翻转了。

Finally...


编辑3:

我跳到了 SDK 0.4.1,并遵循了 Jherico 的所有建议(顺便说一句,非常感谢),最后我得到了这个。我真的不知道发生了什么事。但我注意到的一件事是,有时必须使用 glBindBuffer 绑定(bind)帧缓冲区,有时必须使用 glBindFramebuffer...请记住,纹理仍然与从第一个屏幕截图开始。 我觉得这是一个关于帧时序的问题。如果我足够快地触发第一帧一半的过程,那么第一帧就没有错误。 请注意,我每次都会触发半个渲染,这意味着我必须触发两次才能获得一帧。然后第二个总是与第一个相同,如果我延迟触发第三个帧,那么它可能会很不稳定,然后它在第四帧之后总是会出现故障。这个故障只出现一次,我也不能让它出现两次,即使我等了很长时间。

明天我会尝试对此进行调查,但如果您有任何想法,或者这是一个常见的 OpenGL 错误或误解,欢迎您提供帮助:)

您可以找到the code here

Oculus Glitches


*编辑 1: 我使用帧缓冲区在纹理中绘制场景。在 ovrHmd_BeginFrame(hmd, 0) 语句之后,我绑定(bind)了帧缓冲区以进行离屏渲染:

注意纹理[]包含网格和星形,使用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 ui 在该函数中创建,在 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 值指定物理屏幕上将放置渲染场景的扭曲 View 的区域。另一方面,纹理 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;

您在两个位置设置相同的纹理 ID。

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);
}

您可以看到完整的示例 here 。当然,该示例已更新为 0.4.x,因此您可能需要返回历史记录,直到看到 ovrHmd_EndEyeRender(它已在最新的 SDK 中删除)。

编辑:

我看了你发布的代码。它不完整,因为您没有包含您所依赖的 header 。无论如何,仍然存在一些明显的问题:

            // 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 的有效参数。我不知道它会产生什么影响,但它可能不会是你所期望的那样。
  • 在调用 glBindBuffer 之前调用 glClear 意味着您实际上并未清除屏幕外纹理目标。您正在清除实际的绘制帧缓冲区,SDK 在执行扭曲之前无论如何都会执行此操作。将 glClear 调用移至帧缓冲区操作内部。
  • 您不需要调用 glBindRenderbuffer。我不确定这会产生什么效果,但如果您已经将深度模板渲染缓冲区附加到帧缓冲区对象,那么当您激活帧缓冲区时,它将被自动拉入并使用。
  • 您创建了 renderTex 纹理,将其绑定(bind),设置一些值,然后将其保留为绑定(bind)状态。它应该只绑定(bind)足够长的时间来设置参数。当您调用glFramebufferTexture2D时,它不应该被绑定(bind),事实上也不应该在您设置它之后的任何时候被您绑定(bind)。
  • init_render_ovr 中,您完全设置了 EyeTexture[0],但仅在 EyeTexture 1 中设置了几个值。 。眼睛纹理 1值不默认为 EyeTexture[0] 中的值。您必须初始化每个成员。
  • 在您解决黑屏问题之前,您的代码应该大量使用 glGetError() 调用。我有一个 GL_CHECK_ERROR 在调试版本中扩展为如下所示:

    GLenum 错误代码 = glGetError(); if (错误代码!= 0) { 抛出错误(错误代码); }

关于c++ - 使用 Oculus SDK 渲染时出现黑屏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25291131/

相关文章:

c - 如何在线程之间共享变量?

c - C语言strtok有一些错误

c - 使用 Break 终止 for 循环

c++ - 魔鬼 ilLoad 错误 1285

c++ - 这个代码片段有什么作用?

c++ - 可以将原始指针传递给需要迭代器的模板函数吗?

c++ - 面向 OpenGL 2.0

c++ - 在 Opengl 中增加相机远距离

c++ - 实现 atomic<T>::store

c++ - STL 迭代器 : Assertion Error