Oculus 0.8 SDK黑屏 [英] Oculus 0.8 SDK Black Screen

查看:175
本文介绍了Oculus 0.8 SDK黑屏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试制作一个非常基本的示例,以使用其SDK v0.8渲染到Oculus.我要做的就是给双眼提供纯色.当我运行此命令时,所有内容似乎都可以正确初始化. Oculus显示健康警告消息,但是一旦健康警告消息消失,我所看到的只是一个黑屏.我在这里做什么错了?

I'm trying to make a very basic example of rendering to the Oculus using their SDK v0.8. All I'm trying to do is render a solid color to both eyes. When I run this, everything appears to initialize correctly. The Oculus shows the health warning message, but all I see is a black screen once the health warning message goes away. What am I doing wrong here?

#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.RenderPose
  • 未正确使用ovrSwapTextureSet
  • SDL_GL_SwapWindow的无用调用会导致结结
  • 在仍要为绘图绑定的情况下读取纹理时可能发生的未定义行为
  • Not initializing ovrLayerEyeFov.RenderPose
  • Not using ovrSwapTextureSet correctly
  • Useless calls to SDL_GL_SwapWindow will cause stuttering
  • Possible undefined behavior when reading the texture while it's still bound for drawing

未初始化ovrLayerEyeFov.RenderPose

Not initializing ovrLayerEyeFov.RenderPose

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

You main problem is that you're not setting the RenderPose member of the ovrLayerEyeFov structure. This member tells the SDK what pose you rendered at and therefore how it should apply timewarp based on the current head pose (which might have changed since you rendered). By not setting this value you're basically giving the SDK a random head pose, which is almost certainly not a valid head pose.

此外,图层类型不需要ovrLayerFlag_HeadLocked.这会使Oculus在相对于您的头部的固定位置显示结果图像.它可能会执行您想要的操作,但是,如果您正确地使用正确的值初始化layer.RenderPose成员,则只能执行 (我不确定在ovrLayerEyeFov情况下会是什么情况,因为我只能将标志与ovrLayerQuad一起使用).

Additionally, ovrLayerFlag_HeadLocked isn't needed for your layer type. It causes the Oculus to display the resulting image in a fixed position relative to your head. It might do what you want, but only if you properly initialize the layer.RenderPose members with the correct values (I'm not sure what those would be in the case of ovrLayerEyeFov, as I've only used the flag in combination with ovrLayerQuad).

您应该做的是在图层声明之后添加以下内容,以正确地对其进行初始化:

What you should do is add the following right after the layer declaration to properly initialize it:

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

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

Then, inside your render loop you should add the following right after the check for a quit event:

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

这告诉SDK该图像是从头部当前所在的角度渲染的.

This tells the SDK that this image was rendered from the point of view where the head currently is.

未正确使用ovrSwapTextureSet

Not using ovrSwapTextureSet correctly

代码中的另一个问题是您不正确地使用了纹理集.该文档指定使用纹理集时,需要使用ovrSwapTextureSet.CurrentIndex指向的纹理:

Another problem in the code is that you're incorrectly using the texture set. The documentation specifies that when using the texture set, you need to use the texture pointed to by ovrSwapTextureSet.CurrentIndex:

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

...然后在每次调用ovr_SubmitFrame之后,您需要将ovrSwapTextureSet.CurrentIndex递增1,然后像下面这样通过ovrSwapTextureSet.TextureCount修改值

...and then after each call to ovr_SubmitFrame you need to increment ovrSwapTextureSet.CurrentIndex then mod the value by ovrSwapTextureSet.TextureCount like so

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

SDL_GL_SwapWindow的无用调用会导致卡顿

Useless calls to SDL_GL_SwapWindow will cause stuttering

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

The SDL_GL_SwapWindow(window); call is unnecessary and pointless since you haven't drawn anything to the default framebuffer. Once you move away from drawing a solid color, this call will end up causing judder, since it will block until v-sync (typically at 60hz) causing you to sometimes miss the refersh of the Oculus display. Right now this will be invisible because your scene is just a solid color, but later on when you're rendering objects in 3D, it will cause intolerable judder.

如果您

  • 确保禁用垂直同步
  • 具有可用于绘制到窗口的镜像纹理. (请参阅ovr_CreateMirrorTextureGL的文档)
  • Ensure v-sync is disabled
  • Have a mirror texture available to draw to the window. (See the documentation for ovr_CreateMirrorTextureGL)

可能的帧缓冲问题

我不太确定这是一个严重的问题,但我也建议取消绑定帧缓冲区并分离Oculus提供的纹理 ,然后再将其发送到ovr_SubmitFrame(),因为我不是可以确定,当从附着到当前绑定用于绘制的帧缓冲区的纹理读取时,行为已得到很好的定义.它似乎对我的本地系统没有影响,但是未定义并不表示不起作用,这只是意味着您不能依靠它来工作.

I'm less certain about this one being a serious problem, but I would also suggest unbinding the framebuffer and detaching the Oculus provided texture before sending it to ovr_SubmitFrame(), as I'm not certain that the behavior is well defined when reading from a texture attached to a framebuffer that is currently bound for drawing. It seems to have no impact on my local system, but undefined doesn't mean doesn't work, it just means you can't rely on it to work.

我已经更新了示例代码,并在此处放置了示例代码.作为一项奖励,我对其进行了修改,使其在左眼上绘制一种颜色,在右眼上绘制另一种颜色,并设置了缓冲区以为每只眼睛渲染一半的缓冲区.

I've updated the sample code and put it here. As a bonus I've modified it so it draws one color on the left eye and a different color on the right eye, as well as setting up the buffer to provide for rendering one half of the buffer for each eye.

这篇关于Oculus 0.8 SDK黑屏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆