Oculus 0.8 SDK Черный экран
Я пытаюсь сделать очень простой пример рендеринга в Oculus, используя их SDK v0.8. Все, что я пытаюсь сделать, это сделать сплошной цвет для обоих глаз. Когда я запускаю это, кажется, что все инициализируется правильно. 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;
}
1 ответ
Здесь есть ряд проблем
- Не инициализируется
ovrLayerEyeFov.RenderPose
- Не используется
ovrSwapTextureSet
правильно - Бесполезные звонки
SDL_GL_SwapWindow
вызовет заикание - Возможно неопределенное поведение при чтении текстуры, пока она еще привязана к рисованию
Не инициализируется ovrLayerEyeFov.RenderPose
Вы главная проблема в том, что вы не устанавливаете RenderPose
член ovrLayerEyeFov
состав. Этот участник сообщает SDK, в какой позе вы рендерились и, следовательно, как он должен применять timewarp в зависимости от текущей позы головы (которая могла измениться с момента рендеринга). Не устанавливая это значение, вы в основном задаете 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);
Вызов не нужен и не имеет смысла, так как вы ничего не рисуете в кадровый буфер по умолчанию. Как только вы отойдете от рисования сплошным цветом, этот вызов в конечном итоге вызовет дрожание, поскольку он будет блокироваться до v-sync (обычно с частотой 60 Гц), что иногда приводит к пропуску референса дисплея Oculus. Прямо сейчас это будет невидимым, потому что ваша сцена - просто сплошной цвет, но позже, когда вы визуализируете объекты в 3D, это вызовет недопустимое дрожание.
Вы можете использовать SDL_GL_SwapWindow
если ты
- Убедитесь, что V-Sync отключен
- Имейте зеркальную текстуру, доступную для рисования в окне. (См. Документацию для
ovr_CreateMirrorTextureGL
)
Возможные проблемы с кадровым буфером
Я менее уверен в том, что это серьезная проблема, но я бы также предложил отсоединить кадровый буфер и отсоединить предоставленную текстуру Oculus перед отправкой ovr_SubmitFrame()
, поскольку я не уверен, что поведение хорошо определено при чтении из текстуры, прикрепленной к кадровому буферу, который в настоящее время привязан к рисованию. Кажется, это не влияет на мою локальную систему, но undefined не означает, что не работает, это просто означает, что вы не можете полагаться на то, что он работает.
Я обновил пример кода и разместил его здесь. В качестве бонуса я изменил его, чтобы он рисовал один цвет для левого глаза и другой цвет для правого глаза, а также настраивал буфер, чтобы обеспечить рендеринг одной половины буфера для каждого глаза.