【问题标题】:Oculus 0.8 SDK Black ScreenOculus 0.8 SDK 黑屏
【发布时间】:2016-02-15 01:45:04
【问题描述】:

我正在尝试使用他们的 SDK v0.8 制作一个非常基本的渲染到 Oculus 的示例。我要做的就是为双眼呈现纯色。当我运行它时,一切似乎都正确初始化。 Oculus 显示健康警告消息,但一旦健康警告消息消失,我看到的只是黑屏。我在这里做错了什么?

#define GLEW_STATIC
#include <GL/glew.h>
#define OVR_OS_WIN32
#include <OVR_CAPI_GL.h>
#include <SDL.h>
#include <iostream>

int main(int argc, char *argv[])
{

    SDL_Init(SDL_INIT_VIDEO);   
    SDL_Window* window = SDL_CreateWindow("OpenGL", 100, 100, 800, 600, SDL_WINDOW_OPENGL);
    SDL_GLContext context = SDL_GL_CreateContext(window);

    //Initialize GLEW
    glewExperimental = GL_TRUE;
    glewInit();

    // Initialize Oculus context
    ovrResult result = ovr_Initialize(nullptr);
    if (OVR_FAILURE(result))
    {
        std::cout << "ERROR: Failed to initialize libOVR" << std::endl;
        SDL_Quit();
        return -1;
    }

    // Connect to the Oculus headset
    ovrSession hmd;
    ovrGraphicsLuid luid;
    result = ovr_Create(&hmd, &luid);
    if (OVR_FAILURE(result))
    {
        std::cout << "ERROR: Oculus Rift not detected" << std::endl;
        SDL_Quit();
        return 0;
    }

    ovrHmdDesc desc = ovr_GetHmdDesc(hmd);

    std::cout << "Found " << desc.ProductName << "connected Rift device" << std::endl;

    ovrSizei recommenedTex0Size = ovr_GetFovTextureSize(hmd, ovrEyeType(0), desc.DefaultEyeFov[0], 1.0f);
    ovrSizei bufferSize;
    bufferSize.w = recommenedTex0Size.w;
    bufferSize.h = recommenedTex0Size.h;

    std::cout << "Buffer Size: " << bufferSize.w << ", " << bufferSize.h << std::endl;

    // Generate FBO for oculus
    GLuint oculusFbo = 0;
    glGenFramebuffers(1, &oculusFbo);

    // Create swap texture
    ovrSwapTextureSet* pTextureSet = nullptr;
    if (ovr_CreateSwapTextureSetGL(hmd, GL_SRGB8_ALPHA8, bufferSize.w, bufferSize.h,&pTextureSet) == ovrSuccess)
    {
        ovrGLTexture* tex = (ovrGLTexture*)&pTextureSet->Textures[0];
        glBindTexture(GL_TEXTURE_2D, tex->OGL.TexId);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    }


    // Create ovrLayerHeader

    ovrEyeRenderDesc eyeRenderDesc[2];
    eyeRenderDesc[0] = ovr_GetRenderDesc(hmd, ovrEye_Left, desc.DefaultEyeFov[0]);
    eyeRenderDesc[1] = ovr_GetRenderDesc(hmd, ovrEye_Right, desc.DefaultEyeFov[1]);

    ovrLayerEyeFov layer;

    layer.Header.Type = ovrLayerType_EyeFov;
    layer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft | ovrLayerFlag_HeadLocked;
    layer.ColorTexture[0] = pTextureSet;
    layer.ColorTexture[1] = pTextureSet;
    layer.Fov[0] = eyeRenderDesc[0].Fov;
    layer.Fov[1] = eyeRenderDesc[1].Fov;

    ovrVector2i posVec;
    posVec.x = 0;
    posVec.y = 0;

    ovrSizei sizeVec;
    sizeVec.w = bufferSize.w;
    sizeVec.h = bufferSize.h;

    ovrRecti rec;
    rec.Pos = posVec;
    rec.Size = sizeVec;

    layer.Viewport[0] = rec;
    layer.Viewport[1] = rec;

    ovrLayerHeader* layers = &layer.Header;


    SDL_Event windowEvent;
    while (true)
    {
        if (SDL_PollEvent(&windowEvent))
        {
            if (windowEvent.type == SDL_QUIT) break;
        }
        ovrGLTexture* tex = (ovrGLTexture*)&pTextureSet->Textures[0];
        glBindFramebuffer(GL_FRAMEBUFFER, oculusFbo);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex->OGL.TexId, 0);
        glViewport(0, 0, bufferSize.w, bufferSize.h);
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        ovr_SubmitFrame(hmd, 0, nullptr, &layers, 1);

        SDL_GL_SwapWindow(window);
    }

    SDL_GL_DeleteContext(context);
    SDL_Quit();
    return 0;
}

【问题讨论】:

  • 经过一些额外的测试,我认为这与我使用ovrLayerEyeFov有关。使用直接图层类型 (ovrLayerDirect) 可以让我看到 oculus 上的纹理。
  • ovrLayerDirect 基本上只是将你的纹理贴到屏幕上而没有任何失真。它现在可能对你有用,但它在未来几乎毫无用处。它主要是一个用于测试显示器输出和镜头失真的工具……一旦你超越了纯色的渲染,它就无济于事了。

标签: opengl oculus


【解决方案1】:

这里有很多问题

  • 未初始化ovrLayerEyeFov.RenderPose
  • 没有正确使用ovrSwapTextureSet
  • SDL_GL_SwapWindow的无用调用会导致卡顿
  • 读取纹理时可能出现未定义的行为,而纹理仍需绘制

未初始化ovrLayerEyeFov.RenderPose

你的主要问题是你没有设置ovrLayerEyeFov 结构的RenderPose 成员。该成员告诉 SDK 您渲染的姿势,因此它应该如何根据当前头部姿势应用时间扭曲(在您渲染后可能已经改变)。通过不设置这个值,你基本上是给 SDK 一个随机的头部姿势,这几乎肯定不是一个有效的头部姿势。

此外,您的图层类型不需要ovrLayerFlag_HeadLocked。它使 Oculus 将生成的图像显示在相对于您头部的固定位置。它可能会做你想做的事,但只有如果你用正确的值正确初始化layer.RenderPose成员(我不确定ovrLayerEyeFov的情况是什么,因为我'我只将标志与ovrLayerQuad 结合使用)。

你应该做的是在图层声明之后添加以下内容以正确初始化它:

memset(&layer, 0, sizeof(ovrLayerEyeFov));

然后,在您的渲染循环中,您应该在检查退出事件之后添加以下内容:

ovrTrackingState tracking = ovr_GetTrackingState(hmd, 0, true);
layer.RenderPose[0] = tracking.HeadPose.ThePose;
layer.RenderPose[1] = tracking.HeadPose.ThePose;

这告诉 SDK 该图像是从头部当前所在的角度呈现的。

没有正确使用ovrSwapTextureSet

代码中的另一个问题是您错误地使用了纹理集。文档规定在使用纹理集时,需要使用ovrSwapTextureSet.CurrentIndex指向的纹理:

ovrGLTexture* tex = (ovrGLTexture*)(&(pTextureSet->Textures[pTextureSet->CurrentIndex]));

...然后在每次调用 ovr_SubmitFrame 之后,您需要增加 ovrSwapTextureSet.CurrentIndex 然后将值修改为 ovrSwapTextureSet.TextureCount 像这样

pTextureSet->CurrentIndex = (pTextureSet->CurrentIndex + 1) % pTextureSet->TextureCount;

SDL_GL_SwapWindow的无用调用会导致卡顿

SDL_GL_SwapWindow(window); 调用是不必要且毫无意义的,因为您没有在默认帧缓冲区中绘制任何内容。一旦你离开绘制纯色,这个调用最终会导致抖动,因为它会阻塞直到垂直同步(通常为 60hz)导致你有时会错过 Oculus 显示的引用。现在这将是不可见的,因为您的 scene 只是纯色,但稍后当您以 3D 渲染对象时,它会导致无法忍受的抖动。

可以使用SDL_GL_SwapWindow如果你

  • 确保禁用垂直同步
  • 有一个可用于绘制到窗口的镜像纹理。 (请参阅ovr_CreateMirrorTextureGL 的文档)

可能的帧缓冲问题

我不太确定这是一个严重的问题,但我也建议解除帧缓冲区的绑定并分离 Oculus 提供的纹理发送到 ovr_SubmitFrame() 之前,因为我不是确保从附加到当前绑定用于绘制的帧缓冲区的纹理中读取时,行为是明确定义的。它似乎对我的本地系统没有影响,但未定义并不意味着不起作用,它只是意味着你不能依赖它来工作。

我已更新示例代码并将其放在here。作为奖励,我对其进行了修改,使其在左眼上绘制一种颜色,在右眼上绘制不同的颜色,并设置缓冲区以提供为每只眼睛渲染一半缓冲区。

【讨论】:

  • 哇,这比我期望有人提供的要多。非常感谢您的帮助!
  • 没有初始化 ovrLayerEyeFov.RenderPose 并且没有正确使用 ovrSwapTextureSet 绝对是问题所在。最后,我得到了“hello world”opengl 三角形出现在 oculus 上 :) 再次感谢。
猜你喜欢
  • 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
相关资源
最近更新 更多