Forum Discussion
DoZo1971
11 years agoExplorer
Simple, one page, OpenGL example (0.4.3 beta)
Hi,
The older simple OpenGL example converted to 0.4.3 beta. Just uses GLEW, GLFW and the OculusSDK.
Slight "ghosting" in the image when you move your head fast and Time Warp is enabled.
Thanks,
Daniel Dekkers
EDIT: Fixed bug where EyeIndex was used instead of Eye in the setup of the textures.
EDIT: Back to a single FBO for both eyes because Oculus seems to favor it and it avoids the FBO struct which makes the order in which setup of the various components is performed slightly more clear.
EDIT: Support Extended Desktop mode as well as Direct mode. OS X only supports extended mode until now (SDK 0.4.3).
EDIT: Cleanup the FBO.
EDIT: Some reordering to more closely follow the setup sequence in the Oculus examples. Added simple camera position so you can walk around a bit.
The older simple OpenGL example converted to 0.4.3 beta. Just uses GLEW, GLFW and the OculusSDK.
Slight "ghosting" in the image when you move your head fast and Time Warp is enabled.
Thanks,
Daniel Dekkers
EDIT: Fixed bug where EyeIndex was used instead of Eye in the setup of the textures.
EDIT: Back to a single FBO for both eyes because Oculus seems to favor it and it avoids the FBO struct which makes the order in which setup of the various components is performed slightly more clear.
EDIT: Support Extended Desktop mode as well as Direct mode. OS X only supports extended mode until now (SDK 0.4.3).
EDIT: Cleanup the FBO.
EDIT: Some reordering to more closely follow the setup sequence in the Oculus examples. Added simple camera position so you can walk around a bit.
// GLFWOculusRiftTest
// (c) cThrough 2014 (Daniel Dekkers)
// Version 2014111400 Based on DK2, OculusSDK 4.0.3 beta
#include <GL/glew.h>
#if defined(_WIN32)
#include <Windows.h>
#define GLFW_EXPOSE_NATIVE_WIN32
#define GLFW_EXPOSE_NATIVE_WGL
#elif defined(__linux__)
#include <X11/X.h>
#include <X11/extensions/Xrandr.h>
#define GLFW_EXPOSE_NATIVE_X11
#define GLFW_EXPOSE_NATIVE_GLX
#endif
#include <GLFW/glfw3.h>
#if !defined(__APPLE__)
#include <GLFW/glfw3native.h>
#endif
#include <OVR.h>
#include <OVR_CAPI.h>
#include <OVR_CAPI_GL.h>
const bool l_MultiSampling = false;
const bool l_Spin = false;
int g_DistortionCaps = 0
| ovrDistortionCap_Vignette
| ovrDistortionCap_Chromatic
| ovrDistortionCap_Overdrive
// | ovrDistortionCap_TimeWarp // Turning this on gives ghosting???
;
ovrHmd g_Hmd;
ovrGLConfig g_Cfg;
ovrEyeRenderDesc g_EyeRenderDesc[2];
ovrVector3f g_EyeOffsets[2];
ovrPosef g_EyePoses[2];
ovrTexture g_EyeTextures[2];
OVR::Matrix4f g_ProjectionMatrici[2];
OVR::Sizei g_RenderTargetSize;
ovrVector3f g_CameraPosition;
GLfloat l_VAPoints[] =
{
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f,-0.5f, 0.5f,
0.5f,-0.5f, 0.5f,
-0.5f,-0.5f,-0.5f,
-0.5f, 0.5f,-0.5f,
0.5f, 0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f,-0.5f,
-0.5f, 0.5f,-0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f,-0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
0.5f,-0.5f, 0.5f,
-0.5f,-0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
0.5f,-0.5f, 0.5f,
0.5f,-0.5f,-0.5f,
0.5f, 0.5f,-0.5f,
-0.5f,-0.5f,-0.5f,
-0.5f,-0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, 0.5f,-0.5f
};
GLfloat l_VANormals[] =
{
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f,-1.0f,
0.0f, 0.0f,-1.0f,
0.0f, 0.0f,-1.0f,
0.0f, 0.0f,-1.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f,-1.0f, 0.0f,
0.0f,-1.0f, 0.0f,
0.0f,-1.0f, 0.0f,
0.0f,-1.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f
};
GLuint l_VAIndici[] =
{
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15,
16, 17, 18, 19,
20, 21, 22, 23
};
// =============================================================================
static void ErrorCallback(int p_Error, const char* p_Description)
{
fputs(p_Description, stderr);
}
// =============================================================================
static void KeyCallback(GLFWwindow* p_Window, int p_Key, int p_Scancode, int p_Action, int p_Mods)
{
if (p_Action==GLFW_PRESS)
{
switch (p_Key)
{
case GLFW_KEY_ESCAPE:
glfwSetWindowShouldClose(p_Window, GL_TRUE);
break;
case GLFW_KEY_R:
ovrHmd_RecenterPose(g_Hmd);
break;
case GLFW_KEY_UP:
g_CameraPosition.z += 0.1f;
break;
case GLFW_KEY_DOWN:
g_CameraPosition.z -= 0.1f;
break;
case GLFW_KEY_LEFT:
g_CameraPosition.x += 0.1f;
break;
case GLFW_KEY_RIGHT:
g_CameraPosition.x -= 0.1f;
break;
}
// Remove HSW on every key...
ovrHSWDisplayState l_HasWarningState;
ovrHmd_GetHSWDisplayState(g_Hmd, &l_HasWarningState);
if (l_HasWarningState.Displayed) ovrHmd_DismissHSWDisplay(g_Hmd);
}
}
// =============================================================================
static void WindowSizeCallback(GLFWwindow* p_Window, int p_Width, int p_Height)
{
if (p_Width>0 && p_Height>0)
{
g_Cfg.OGL.Header.RTSize.w = p_Width;
g_Cfg.OGL.Header.RTSize.h = p_Height;
ovrBool l_ConfigureResult = ovrHmd_ConfigureRendering(g_Hmd, &g_Cfg.Config, g_DistortionCaps, g_Hmd->MaxEyeFov, g_EyeRenderDesc);
glUseProgram(0); // Avoid OpenGL state leak in ovrHmd_ConfigureRendering...
if (!l_ConfigureResult)
{
printf("Configure failed.\n");
exit(EXIT_FAILURE);
}
}
}
// ============================================================================
void RenderCubeVertexArrays(void)
{
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, l_VAPoints);
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, l_VANormals);
glDrawElements(GL_QUADS, 6*4, GL_UNSIGNED_INT, l_VAIndici);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
// ============================================================================
void RenderCubeFixedFunction(void)
{
// Obsolete, remains as a fall back for the vertex arrays version...
glBegin(GL_QUADS);
glNormal3f( 0.0f, 0.0f, 1.0f);
glVertex3f( 0.5f, 0.5f, 0.5f);
glVertex3f(-0.5f, 0.5f, 0.5f);
glVertex3f(-0.5f,-0.5f, 0.5f);
glVertex3f( 0.5f,-0.5f, 0.5f);
glNormal3f( 0.0f, 0.0f,-1.0f);
glVertex3f(-0.5f,-0.5f,-0.5f);
glVertex3f(-0.5f, 0.5f,-0.5f);
glVertex3f( 0.5f, 0.5f,-0.5f);
glVertex3f( 0.5f,-0.5f,-0.5f);
glNormal3f( 0.0f, 1.0f, 0.0f);
glVertex3f( 0.5f, 0.5f, 0.5f);
glVertex3f( 0.5f, 0.5f,-0.5f);
glVertex3f(-0.5f, 0.5f,-0.5f);
glVertex3f(-0.5f, 0.5f, 0.5f);
glNormal3f( 0.0f,-1.0f, 0.0f);
glVertex3f(-0.5f,-0.5f,-0.5f);
glVertex3f( 0.5f,-0.5f,-0.5f);
glVertex3f( 0.5f,-0.5f, 0.5f);
glVertex3f(-0.5f,-0.5f, 0.5f);
glNormal3f( 1.0f, 0.0f, 0.0f);
glVertex3f( 0.5f, 0.5f, 0.5f);
glVertex3f( 0.5f,-0.5f, 0.5f);
glVertex3f( 0.5f,-0.5f,-0.5f);
glVertex3f( 0.5f, 0.5f,-0.5f);
glNormal3f(-1.0f, 0.0f, 0.0f);
glVertex3f(-0.5f,-0.5f,-0.5f);
glVertex3f(-0.5f,-0.5f, 0.5f);
glVertex3f(-0.5f, 0.5f, 0.5f);
glVertex3f(-0.5f, 0.5f,-0.5f);
glEnd();
}
// ============================================================================
static void SetOpenGLState(void)
{
// Some state...
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if (l_MultiSampling) glEnable(GL_MULTISAMPLE); else glDisable(GL_MULTISAMPLE);
glClearColor(0.2f, 0.3f, 0.4f, 1.0f);
// Material...
GLfloat l_MaterialSpecular[] = { 0.3f, 0.3f, 0.3f, 1.0f };
GLfloat l_MaterialShininess[] = { 10.0f };
glMaterialfv(GL_FRONT, GL_SPECULAR, l_MaterialSpecular);
glMaterialfv(GL_FRONT, GL_SHININESS, l_MaterialShininess);
// Some (stationary) lights, position will be set every frame separately...
GLfloat l_Light0Diffuse[] = { 1.0f, 0.8f, 0.6f, 1.0f };
glLightfv(GL_LIGHT0, GL_DIFFUSE, l_Light0Diffuse);
glEnable(GL_LIGHT0);
GLfloat l_Light1Diffuse[] = { 0.6f, 0.8f, 1.0f, 1.0f };
glLightfv(GL_LIGHT1, GL_DIFFUSE, l_Light1Diffuse);
glEnable(GL_LIGHT1);
}
// ============================================================================
static void SetStaticLightPositions(void)
{
GLfloat l_Light0Position[] = { 3.0f, 4.0f, 2.0f, 0.0f };
glLightfv(GL_LIGHT0, GL_POSITION, l_Light0Position);
GLfloat l_Light1Position[] = { -3.0f, -4.0f, 2.0f, 0.0f };
glLightfv(GL_LIGHT1, GL_POSITION, l_Light1Position);
}
// =============================================================================
int main(void)
{
printf("[R] to recenter, [Esc] to quit, dismiss the HSW with any key (after the hidden timer runs out)...\n");
// Initialize LibOVR...
ovr_Initialize();
// Check for attached head mounted display...
g_Hmd = ovrHmd_Create(0);
if (!g_Hmd)
{
printf("No Oculus Rift device attached, using virtual version...\n");
g_Hmd = ovrHmd_CreateDebug(ovrHmd_DK2);
}
// Create a window...
GLFWwindow* l_Window;
glfwSetErrorCallback(ErrorCallback);
if (!glfwInit()) exit(EXIT_FAILURE);
if (l_MultiSampling) glfwWindowHint(GLFW_SAMPLES, 4); else glfwWindowHint(GLFW_SAMPLES, 0);
// Check to see if we are running in "Direct" or "Extended Desktop" mode...
bool l_DirectMode = ((g_Hmd->HmdCaps & ovrHmdCap_ExtendDesktop)==0);
GLFWmonitor* l_Monitor;
ovrSizei l_ClientSize;
if (l_DirectMode)
{
printf("Running in \"Direct\" mode...\n");
l_Monitor = NULL;
l_ClientSize.w = g_Hmd->Resolution.w/2; // Something reasonable, smaller, but maintain aspect ratio...
l_ClientSize.h = g_Hmd->Resolution.h/2; // Something reasonable, smaller, but maintain aspect ratio...
}
else // Extended Desktop mode...
{
printf("Running in \"Extended Desktop\" mode...\n");
int l_Count;
GLFWmonitor** l_Monitors = glfwGetMonitors(&l_Count);
switch (l_Count)
{
case 0:
printf("No monitors found, exiting...\n");
exit(EXIT_FAILURE);
break;
case 1:
printf("Two monitors expected, found only one, using primary...\n");
l_Monitor = glfwGetPrimaryMonitor();
break;
case 2:
printf("Two monitors found, using second monitor...\n");
l_Monitor = l_Monitors[1];
break;
default:
printf("More than two monitors found, using second monitor...\n");
l_Monitor = l_Monitors[1];
}
l_ClientSize.w = g_Hmd->Resolution.w; // 1920 for DK2...
l_ClientSize.h = g_Hmd->Resolution.h; // 1080 for DK2...
}
// Create the window based on the parameters set above...
l_Window = glfwCreateWindow(l_ClientSize.w, l_ClientSize.h, "GLFW Oculus Rift Test", l_Monitor, NULL);
// Check if window creation was succesfull...
if (!l_Window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
// Attach the window in "Direct Mode"...
#if defined(_WIN32)
if (l_DirectMode)
{
ovrBool l_AttachResult = ovrHmd_AttachToWindow(g_Hmd, glfwGetWin32Window(l_Window), NULL, NULL);
if (!l_AttachResult)
{
printf("Could not attach to window...");
exit(EXIT_FAILURE);
}
}
#endif
// Make the context current for this window...
glfwMakeContextCurrent(l_Window);
// Don't forget to initialize Glew, turn glewExperimental on to avoid problem fetching function pointers...
glewExperimental = GL_TRUE;
GLenum l_GlewResult = glewInit();
if (l_GlewResult!=GLEW_OK)
{
printf("glewInit() error.\n");
exit(EXIT_FAILURE);
}
// Print some info about the OpenGL context...
int l_Major = glfwGetWindowAttrib(l_Window, GLFW_CONTEXT_VERSION_MAJOR);
int l_Minor = glfwGetWindowAttrib(l_Window, GLFW_CONTEXT_VERSION_MINOR);
int l_Profile = glfwGetWindowAttrib(l_Window, GLFW_OPENGL_PROFILE);
printf("OpenGL: %d.%d ", l_Major, l_Minor);
if (l_Major>=3) // Profiles introduced in OpenGL 3.0...
{
if (l_Profile==GLFW_OPENGL_COMPAT_PROFILE) printf("GLFW_OPENGL_COMPAT_PROFILE\n"); else printf("GLFW_OPENGL_CORE_PROFILE\n");
}
printf("Vendor: %s\n", (char*)glGetString(GL_VENDOR));
printf("Renderer: %s\n", (char*)glGetString(GL_RENDERER));
// Create some lights, materials, etc...
SetOpenGLState();
// Find out what the texture sizes should be for each eye separately first...
ovrSizei l_EyeTextureSizes[2];
l_EyeTextureSizes[ovrEye_Left] = ovrHmd_GetFovTextureSize(g_Hmd, ovrEye_Left, g_Hmd->MaxEyeFov[ovrEye_Left], 1.0f);
l_EyeTextureSizes[ovrEye_Right] = ovrHmd_GetFovTextureSize(g_Hmd, ovrEye_Right, g_Hmd->MaxEyeFov[ovrEye_Right], 1.0f);
// Combine for one texture for both eyes...
g_RenderTargetSize.w = l_EyeTextureSizes[ovrEye_Left].w + l_EyeTextureSizes[ovrEye_Right].w;
g_RenderTargetSize.h = (l_EyeTextureSizes[ovrEye_Left].h>l_EyeTextureSizes[ovrEye_Right].h ? l_EyeTextureSizes[ovrEye_Left].h : l_EyeTextureSizes[ovrEye_Right].h);
// Create the FBO being a single one for both eyes (this is open for debate)...
GLuint l_FBOId;
glGenFramebuffers(1, &l_FBOId);
glBindFramebuffer(GL_FRAMEBUFFER, l_FBOId);
// The texture we're going to render to...
GLuint l_TextureId;
glGenTextures(1, &l_TextureId);
// "Bind" the newly created texture : all future texture functions will modify this texture...
glBindTexture(GL_TEXTURE_2D, l_TextureId);
// Give an empty image to OpenGL (the last "0")
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, g_RenderTargetSize.w, g_RenderTargetSize.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
// Linear filtering...
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// Create Depth Buffer...
GLuint l_DepthBufferId;
glGenRenderbuffers(1, &l_DepthBufferId);
glBindRenderbuffer(GL_RENDERBUFFER, l_DepthBufferId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, g_RenderTargetSize.w, g_RenderTargetSize.h);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, l_DepthBufferId);
// Set the texture as our colour attachment #0...
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, l_TextureId, 0);
// Set the list of draw buffers...
GLenum l_GLDrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, l_GLDrawBuffers); // "1" is the size of DrawBuffers
// Check if everything is OK...
GLenum l_Check = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
if (l_Check!=GL_FRAMEBUFFER_COMPLETE)
{
printf("There is a problem with the FBO.\n");
exit(EXIT_FAILURE);
}
// Unbind...
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Setup textures for each eye...
// Left eye...
g_EyeTextures[ovrEye_Left].Header.API = ovrRenderAPI_OpenGL;
g_EyeTextures[ovrEye_Left].Header.TextureSize = g_RenderTargetSize;
g_EyeTextures[ovrEye_Left].Header.RenderViewport.Pos.x = 0;
g_EyeTextures[ovrEye_Left].Header.RenderViewport.Pos.y = 0;
g_EyeTextures[ovrEye_Left].Header.RenderViewport.Size = l_EyeTextureSizes[ovrEye_Left];
((ovrGLTexture&)(g_EyeTextures[ovrEye_Left])).OGL.TexId = l_TextureId;
// Right eye (mostly the same as left but with the viewport on the right side of the texture)...
g_EyeTextures[ovrEye_Right] = g_EyeTextures[ovrEye_Left];
g_EyeTextures[ovrEye_Right].Header.RenderViewport.Pos.x = (g_RenderTargetSize.w+1)/2;
g_EyeTextures[ovrEye_Right].Header.RenderViewport.Pos.y = 0;
// Oculus Rift eye configurations...
g_Cfg.OGL.Header.API = ovrRenderAPI_OpenGL;
g_Cfg.OGL.Header.RTSize.w = l_ClientSize.w;
g_Cfg.OGL.Header.RTSize.h = l_ClientSize.h;
g_Cfg.OGL.Header.Multisample = (l_MultiSampling ? 1 : 0);
#if defined(_WIN32)
g_Cfg.OGL.Window = glfwGetWin32Window(l_Window);
g_Cfg.OGL.DC = GetDC(g_Cfg.OGL.Window);
#elif defined(__linux__)
l_Cfg.OGL.Win = glfwGetX11Window(l_Window);
l_Cfg.OGL.Disp = glfwGetX11Display();
#endif
// Enable capabilities...
// ovrHmd_SetEnabledCaps(g_Hmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction);
ovrBool l_ConfigureResult = ovrHmd_ConfigureRendering(g_Hmd, &g_Cfg.Config, g_DistortionCaps, g_Hmd->MaxEyeFov, g_EyeRenderDesc);
glUseProgram(0); // Avoid OpenGL state leak in ovrHmd_ConfigureRendering...
if (!l_ConfigureResult)
{
printf("Configure failed.\n");
exit(EXIT_FAILURE);
}
// Start the sensor which provides the Rift’s pose and motion...
uint32_t l_SupportedSensorCaps = ovrTrackingCap_Orientation | ovrTrackingCap_MagYawCorrection | ovrTrackingCap_Position;
uint32_t l_RequiredTrackingCaps = 0;
ovrBool l_TrackingResult = ovrHmd_ConfigureTracking(g_Hmd, l_SupportedSensorCaps, l_RequiredTrackingCaps);
if (!l_TrackingResult)
{
printf("Could not start tracking...");
exit(EXIT_FAILURE);
}
// Projection matrici for each eye will not change at runtime, we can set them here...
g_ProjectionMatrici[ovrEye_Left] = ovrMatrix4f_Projection(g_EyeRenderDesc[ovrEye_Left].Fov, 0.3f, 100.0f, true);
g_ProjectionMatrici[ovrEye_Right] = ovrMatrix4f_Projection(g_EyeRenderDesc[ovrEye_Right].Fov, 0.3f, 100.0f, true);
// IPD offset values will not change at runtime, we can set them here...
g_EyeOffsets[ovrEye_Left] = g_EyeRenderDesc[ovrEye_Left].HmdToEyeViewOffset;
g_EyeOffsets[ovrEye_Right] = g_EyeRenderDesc[ovrEye_Right].HmdToEyeViewOffset;
// Initial camera position...
g_CameraPosition.x = 0.0f;
g_CameraPosition.y = 0.0f;
g_CameraPosition.z = -2.0f;
glfwSetKeyCallback(l_Window, KeyCallback);
glfwSetWindowSizeCallback(l_Window, WindowSizeCallback);
GLfloat l_SpinX;
GLfloat l_SpinY;
// Do a single recenter to calibrate orientation to current state of the Rift...
ovrHmd_RecenterPose(g_Hmd);
// Main loop...
unsigned int l_FrameIndex = 0;
while (!glfwWindowShouldClose(l_Window))
{
if (l_Spin)
{
l_SpinX = (GLfloat) fmod(glfwGetTime()*17.0, 360.0);
l_SpinY = (GLfloat) fmod(glfwGetTime()*23.0, 360.0);
}
else
{
l_SpinX = 30.0f;
l_SpinY = 40.0f;
}
// Begin the frame...
ovrHmd_BeginFrame(g_Hmd, l_FrameIndex);
// Get eye poses for both the left and the right eye. g_EyePoses contains all Rift information: orientation, positional tracking and
// the IPD in the form of the input variable g_EyeOffsets.
ovrHmd_GetEyePoses(g_Hmd, l_FrameIndex, g_EyeOffsets, g_EyePoses, NULL);
// Bind the FBO...
glBindFramebuffer(GL_FRAMEBUFFER, l_FBOId);
// Clear...
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for (int l_EyeIndex=0; l_EyeIndex<ovrEye_Count; l_EyeIndex++)
{
ovrEyeType l_Eye = g_Hmd->EyeRenderOrder[l_EyeIndex];
glViewport(
g_EyeTextures[l_Eye].Header.RenderViewport.Pos.x,
g_EyeTextures[l_Eye].Header.RenderViewport.Pos.y,
g_EyeTextures[l_Eye].Header.RenderViewport.Size.w,
g_EyeTextures[l_Eye].Header.RenderViewport.Size.h
);
// Pass projection matrix on to OpenGL...
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMultMatrixf(&(g_ProjectionMatrici[l_Eye].Transposed().M[0][0]));
// Create the model-view matrix and pass on to OpenGL...
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Multiply with orientation retrieved from sensor...
OVR::Quatf l_Orientation = OVR::Quatf(g_EyePoses[l_Eye].Orientation);
OVR::Matrix4f l_ModelViewMatrix = OVR::Matrix4f(l_Orientation.Inverted());
glMultMatrixf(&(l_ModelViewMatrix.Transposed().M[0][0]));
// Translation due to positional tracking (DK2) and IPD...
glTranslatef(-g_EyePoses[l_Eye].Position.x, -g_EyePoses[l_Eye].Position.y, -g_EyePoses[l_Eye].Position.z);
// Move the world forward a bit to show the scene in front of us...
glTranslatef(g_CameraPosition.x, g_CameraPosition.y, g_CameraPosition.z);
// (Re)set the light positions so they don't move along with the cube...
SetStaticLightPositions();
// Make the cube spin...
glRotatef(l_SpinX, 1.0f, 0.0f, 0.0f);
glRotatef(l_SpinY, 0.0f, 1.0f, 0.0f);
// Render...
// RenderCubeFixedFunction();
RenderCubeVertexArrays();
}
// Back to the default framebuffer...
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Do everything, distortion, front/back buffer swap...
ovrHmd_EndFrame(g_Hmd, g_EyePoses, g_EyeTextures);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Avoid OpenGL state leak in ovrHmd_EndFrame...
glBindBuffer(GL_ARRAY_BUFFER, 0); // Avoid OpenGL state leak in ovrHmd_EndFrame...
++l_FrameIndex;
glfwPollEvents();
}
// Clean up FBO...
glDeleteRenderbuffers(1, &l_DepthBufferId);
glDeleteTextures(1, &l_TextureId);
glDeleteFramebuffers(1, &l_FBOId);
// Clean up Oculus...
ovrHmd_Destroy(g_Hmd);
ovr_Shutdown();
// Clean up window...
glfwDestroyWindow(l_Window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
21 Replies
- jhericoAdventurerThat's a lot of code that's not usable on a core context. I mean, nice job and all, but it's a lot of effort to go through just to write to a spec that honestly, no one should be using anymore. Also, something of a strange mix of C++ and C conventions.
You might want to take a look at my minimal example. Just about all of my OpenGL usage is done through the oglplus wrappers, but it's all compatible with a 3.3 core context. I'd update it to a 4.x context, but a lot of Mac hardware doesn't support a high enough version of OpenGL 4 to make it worth the work. - DoZo1971ExplorerHi jherico,
I just want to focus on the Oculus stuff, with the least amount of "extra" code (So yeah no shaders specified, relying on fixed function) or building of external libs. Ideally it should be straight C. I'll try to remove C++ specifics.
The problems I had yesterday were because of some state leaks still existent in ovrHmd_ConfigureRendering() (program remains bound) and ovrHmd_EndFrame() (buffers remain bound). Now it seems to work. So (keeping positive) direct mode in OpenGL! Yay! I can even resize the window on the desktop without interfering with the Rift. Just what I wanted.
I did take a look at your minimal example but didn't get OGLplus to build (I tried both the "Configure" and the CMake route). I love CMake and use it all the time but I *hate* the CMake find module system (that never finds anything). For my own projects I gave up on it in most cases and just added paths that the user can change in the CMake GUI.
I copied "separate FBOs for each eye" from your minimal example. I used to use a single FBO for both eyes. Is that deprecated by the way? Two FBOs needs an extra glBindFramebuffer() which I would think would be inefficient.
Today I will test OS X (Yosemite in my case).
Thanks,
Daniel - tmason101Honored Guest
"jherico" wrote:
That's a lot of code that's not usable on a core context. I mean, nice job and all, but it's a lot of effort to go through just to write to a spec that honestly, no one should be using anymore. Also, something of a strange mix of C++ and C conventions.
You might want to take a look at my minimal example. Just about all of my OpenGL usage is done through the oglplus wrappers, but it's all compatible with a 3.3 core context. I'd update it to a 4.x context, but a lot of Mac hardware doesn't support a high enough version of OpenGL 4 to make it worth the work.
I'll second @Dozo1971 on this, I just couldn't get the OGLPlus wrappers to work.
In general the less dependencies the better; can you take out the OGLPlus stuff and just use pure OpenGL calls with GLEW?
That way folks are not dependent on an unnecessary library for getting stuff like this to work. - jhericoAdventurer
"DoZo1971" wrote:
I did take a look at your minimal example but didn't get OGLplus to build (I tried both the "Configure" and the CMake route). I love CMake and use it all the time but I *hate* the CMake find module system (that never finds anything). For my own projects I gave up on it in most cases and just added paths that the user can change in the CMake GUI.
I don't really like the cmake find module system either, which is why all of my dependencies are included. I don't use find_module for almost anything other than threads. Instead I use add_subdirectory. If you followed the readme here and had errors with CMake, please let me know or open an issue, because that shouldn't happen."DoZo1971" wrote:
I copied "separate FBOs for each eye" from your minimal example. I used to use a single FBO for both eyes. Is that deprecated by the way? Two FBOs needs an extra glBindFramebuffer() which I would think would be inefficient.
Using a single FBO or dual FBOs is pretty much a matter of taste I think. I find the code for 'FBO per eye' to be easier to follow, which is why I use it. And the addition of a single addition glBindFramebuffer() call per frame isn't going to have a significant impact on rendering speed. - jhericoAdventurer
"tmason101" wrote:
I'll second @Dozo1971 on this, I just couldn't get the OGLPlus wrappers to work.
In general the less dependencies the better; can you take out the OGLPlus stuff and just use pure OpenGL calls with GLEW?
I'm probably going to replace the FBO wrapper with raw OpenGL calls, since that's a critical component of working with the Rift. The other places I use oglplus are in the particular scene rendering, which presumably would be replaced by someone who has their own stuff to render, so I'm less inclined to switch all that to raw calls.
Can you tell me what issues you had with oglplus? - rjoyceHonored Guest
"jherico" wrote:
Using a single FBO or dual FBOs is pretty much a matter of taste I think. I find the code for 'FBO per eye' to be easier to follow, which is why I use it. And the addition of a single addition glBindFramebuffer() call per frame isn't going to have a significant impact on rendering speed.
Yup, I think they'll support both indefinitely (especially since one is just a special case of the other). There was a slide on this in the Connect Mastering the SDK talk (slides linked below). The difference boils down to the minute differences in GPU's handling one large FBO vs two small FBO's. I think worrying about which one to use is a waste of time, and you should worry about optimization everywhere first. I find the single FBO to be easier to follow in my code, so do what pleases you :P
http://static.oculus.com/connect/slides/OculusConnect_Mastering_the_SDK.pdf - jhericoAdventurer
"rjoyce" wrote:
Yup, I think they'll support both indefinitely (especially since one is just a special case of the other).
'They' being who in this case? Oculus doesn't really have any say in the matter. The inputs to the distortion mechanism are texture IDs, not framebuffers. The SDK doesn't care how the texture was generated. You could use one framebuffer, or a dozen, or just load up a texture from disk. - rjoyceHonored GuestWhoops yeah I was interchanging texture and FBO there. They have a say in if you use 1 or 2 textures, but I don't think they'll ever care which you use
- DoZo1971ExplorerOk, thanks for the discussion. Oculus themselves seem to favor a single texture for both eyes (as seen in the documentation, Oculus Developer Guide 0.4, 8.2.1) but I'll leave it for now.
Something else...
In the abovementioned code I see a double cube (sort of ghost) if I turn my head quickly. If I turn time warping off (don't include ovrDistortionCap_TimeWarp in the distortion capabilities) it's gone. So I guess I'm doing something wrong there. Any ideas?
Thanks,
Daniel Dekkers - tmason101Honored Guest
"DoZo1971" wrote:
Ok, thanks for the discussion. Oculus themselves seem to favor a single texture for both eyes (as seen in the documentation, Oculus Developer Guide 0.4, 8.2.1) but I'll leave it for now.
Something else...
In the abovementioned code I see a double cube (sort of ghost) if I turn my head quickly. If I turn time warping off (don't include ovrDistortionCap_TimeWarp in the distortion capabilities) it's gone. So I guess I'm doing something wrong there. Any ideas?
Thanks,
Daniel Dekkers
Hey, I am working with your example now as I am trying to troubleshoot mine :D :D :D
Once I figure things out I will be sure to post.
Quick Links
- Horizon Developer Support
- Quest User Forums
- Troubleshooting Forum for problems with a game or app
- Quest Support for problems with your device
Other Meta Support
Related Content
- 9 months ago
- 11 years ago
- 4 years ago