def v_render(): ''' render to vr and window ''' global hmd, ctx, window # resolve multi-sample offscreen buffer gl.glBindFramebuffer(gl.GL_READ_FRAMEBUFFER, ctx.con.offFBO) gl.glReadBuffer(gl.GL_COLOR_ATTACHMENT0) gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, ctx.con.offFBO_r) gl.glDrawBuffer(gl.GL_COLOR_ATTACHMENT0) gl.glBlitFramebuffer(0, 0, 2 * hmd.width, hmd.height, 0, 0, 2 * hmd.width, hmd.height, gl.GL_COLOR_BUFFER_BIT, gl.GL_NEAREST) # blit to window, left only, window is half-size gl.glBindFramebuffer(gl.GL_READ_FRAMEBUFFER, ctx.con.offFBO_r) gl.glReadBuffer(gl.GL_COLOR_ATTACHMENT0) gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, 0) gl.glDrawBuffer(gl.GL_BACK if ctx.con.windowDoublebuffer else gl.GL_FRONT) gl.glBlitFramebuffer(0, 0, hmd.width, hmd.height, 0, 0, hmd.width // 2, hmd.height // 2, gl.GL_COLOR_BUFFER_BIT, gl.GL_NEAREST) # blit to vr texture gl.glActiveTexture(gl.GL_TEXTURE2) gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, ctx.con.offFBO_r) gl.glFramebufferTexture2D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT1, gl.GL_TEXTURE_2D, hmd.idtex, 0) gl.glDrawBuffer(gl.GL_COLOR_ATTACHMENT1) gl.glBlitFramebuffer(0, 0, 2 * hmd.width, hmd.height, 0, 0, 2 * hmd.width, hmd.height, gl.GL_COLOR_BUFFER_BIT, gl.GL_NEAREST) gl.glFramebufferTexture2D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT1, gl.GL_TEXTURE_2D, 0, 0) gl.glDrawBuffer(gl.GL_COLOR_ATTACHMENT0) openvr.VRCompositor().submit(openvr.Eye_Left, hmd.vTex, hmd.boundLeft) openvr.VRCompositor().submit(openvr.Eye_Right, hmd.vTex, hmd.boundRight) # swap if window is double-buffered, flush just in case if ctx.con.windowDoublebuffer: glfw.swap_buffers(window) gl.glFlush()
def blit_multisampled_fbo(width, height, fbo): if fbo == 0: return GL.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, 0) GL.glBindFramebuffer(GL.GL_READ_FRAMEBUFFER, fbo) GL.glDrawBuffer(GL.GL_BACK) GL.glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL.GL_COLOR_BUFFER_BIT, GL.GL_NEAREST) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, fbo)
def render(self, scene, camera, light=(1.0, 1.0, 1.0)): # tr = tracker.SummaryTracker() self.ctx.clear() # create a C-style binary buffer for the scene data scene_packed = scene.pack() vbo = self.ctx.buffer(scene_packed) # merge the textures and load them into a buffer scene.pack_textures() # load the scene data (vertices, colors, etc.) into the renderer vao = self.ctx.simple_vertex_array(self.prog, vbo, *self.shader["params"]) # get the camera parameters and feed them into the renderer proj, lookat = camera.get_view_model() self.prog['model'].write((proj * lookat).astype('f4').tobytes()) self.prog['Light'].value = light # prog['Color'].value = (1.0, 1.0, 1.0, 0.25) # render out the current vao.render(moderngl.TRIANGLES) if self.msaa > 0: gl.glBindFramebuffer(gl.GL_READ_FRAMEBUFFER, self.fbo_msaa.glo) gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, self.fbo.glo) gl.glBlitFramebuffer(0, 0, self.size[0], self.size[1], 0, 0, self.size[0], self.size[1], gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT, gl.GL_NEAREST) # gl.glBindFramebuffer(gl.GL_READ_FRAMEBUFFER, self.fbo_msaa.glo) # gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, self.fbo.glo) # gl.glBlitFramebuffer(0, 0, self.size[0], self.size[1], 0, 0, # self.size[0], self.size[1], # , gl.GL_LINEAR) # get the RGB data and convert to numpy array raw = self.fbo.read(components=4, dtype='f4') # RGBA, floats img = np.frombuffer( raw, dtype='f4').reshape((camera.height, camera.width, 4)) # the y axis is flipped during rendering, so we have to unflip this. # and the image has 4 channels: RGB+Alpha, but we don't care about alpha. # note that the image will be numpy.float32 in range [0,1] img = img[::-1, :, :3] # get the depth buffer and conver to numpy depth = np.frombuffer( self.dbo_smol.read(alignment=1), dtype=np.dtype('f4')).reshape(camera.size()) # similar to the RGB, the dept is flipped upside-down as well so we need to unflip. depth = depth[::-1, :] # tr.print_diff() return img, depth
def submit(self, eye): if self.multisample > 0: GL.glBindFramebuffer(GL.GL_READ_FRAMEBUFFER, self.fb) GL.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, self.resolve_fb) GL.glBlitFramebuffer(0, 0, self.width, self.height, 0, 0, self.width, self.height, GL.GL_COLOR_BUFFER_BIT, GL.GL_LINEAR) GL.glBindFramebuffer(GL.GL_READ_FRAMEBUFFER, 0) GL.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, 0) openvr.VRCompositor().submit(eye, self.texture)
def get_raw_fbo_data(self, dtype: str = 'f1') -> bytes: # Copy blocks from the fbo_msaa to the drawn fbo using Blit pw, ph = (self.pixel_width, self.pixel_height) gl.glBindFramebuffer(gl.GL_READ_FRAMEBUFFER, self.fbo_msaa.glo) gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, self.fbo.glo) gl.glBlitFramebuffer(0, 0, pw, ph, 0, 0, pw, ph, gl.GL_COLOR_BUFFER_BIT, gl.GL_LINEAR) return self.fbo.read( viewport=self.fbo.viewport, components=self.n_channels, dtype=dtype, )
def render(self, gltf, nodes, window_size=(800, 600)): self.vr_compositor.waitGetPoses(self._poses, openvr.k_unMaxTrackedDeviceCount, None, 0) hmd_pose = self._poses[openvr.k_unTrackedDeviceIndex_Hmd] if not hmd_pose.bPoseIsValid: return hmd_34 = np.ctypeslib.as_array(cast(hmd_pose.mDeviceToAbsoluteTracking.m, c_float_p), shape=(3,4)) self.view[:3,:] = hmd_34 view = np.linalg.inv(self.view.T) poses = [hmd_34] for i in self._controller_indices: controller_pose = self._poses[i] if controller_pose.bPoseIsValid: pose_34 = np.ctypeslib.as_array(cast(controller_pose.mDeviceToAbsoluteTracking.m, c_float_p), shape=(3,4)) poses.append(pose_34) view.dot(self.eye_transforms[0], out=self.view_matrices[0]) view.dot(self.eye_transforms[1], out=self.view_matrices[1]) for eye in (0, 1): gl.glViewport(0, 0, self.vr_framebuffers[eye].width, self.vr_framebuffers[eye].height) gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.vr_framebuffers[eye].fb) gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) gltfu.set_material_state.current_material = None gltfu.set_technique_state.current_technique = None for node in nodes: gltfu.draw_node(node, gltf, projection_matrix=self.projection_matrices[eye], view_matrix=self.view_matrices[eye]) self.controllers.display_gl(self.view_matrices[eye], self.projection_matrices[eye]) # self.vr_compositor.submit(openvr.Eye_Left, self.vr_framebuffers[0].texture) # self.vr_compositor.submit(openvr.Eye_Right, self.vr_framebuffers[1].texture) self.vr_framebuffers[0].submit(openvr.Eye_Left) self.vr_framebuffers[1].submit(openvr.Eye_Right) # mirror left eye framebuffer to screen: gl.glBindFramebuffer(gl.GL_READ_FRAMEBUFFER, self.vr_framebuffers[0].fb) gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, 0) gl.glBlitFramebuffer(0, 0, self.vr_framebuffers[0].width, self.vr_framebuffers[0].height, 0, 0, window_size[0], window_size[1], gl.GL_COLOR_BUFFER_BIT, gl.GL_NEAREST) gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0) self._frames_rendered += 1 if self._poll_tracked_device_frequency and self._frames_rendered % self._poll_tracked_device_frequency == 0: self._poll_tracked_device_count()
def render(): global image # Draw to the offscreen FBO gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, fbo) gl.glDrawBuffer(gl.GL_COLOR_ATTACHMENT0) gl.glClear(gl.GL_COLOR_BUFFER_BIT) gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4) # Start to copy off to the pixel buffer; this will continue # asynchronously with frame delay gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, pb) # Yes, you have to do glBufferData every time gl.glBufferData(gl.GL_PIXEL_PACK_BUFFER, WINDOW_WIDTH * WINDOW_HEIGHT * 4, ctypes.c_void_p(0), gl.GL_DYNAMIC_READ) gl.glReadPixels(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, ctypes.c_void_p(0)) # Copy from offscreen framebuffer to display framebuffer gl.glBindFramebuffer(gl.GL_READ_FRAMEBUFFER, fbo) gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, 0) gl.glReadBuffer(gl.GL_COLOR_ATTACHMENT0) gl.glDrawBuffer(gl.GL_BACK_LEFT) gl.glClear(gl.GL_COLOR_BUFFER_BIT) gl.glBlitFramebuffer(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, gl.GL_COLOR_BUFFER_BIT, gl.GL_NEAREST) # Now actually map to the pixel buffer and copy image data image_data_p = ctypes.c_void_p(gl.glMapBuffer(gl.GL_PIXEL_PACK_BUFFER, gl.GL_READ_ONLY)) image_data_ubyte_p = ctypes.cast(image_data_p, ctypes.POINTER(ctypes.c_ubyte)) image = np.ctypeslib.as_array(image_data_ubyte_p, shape=(WINDOW_WIDTH, WINDOW_HEIGHT, 4)) gl.glUnmapBuffer(gl.GL_PIXEL_PACK_BUFFER)
def on_draw(self): if self.started is False: return view = self.controller.getViewM() self.shader.uniform_matrixf("viewM", view) red,green,blue,alpha = 1,1,1,1 GL.glClearColor(red,green,blue,alpha) if self.useFBO is True: GL.glBindFramebuffer(GL.GL_FRAMEBUFFER,self.fbo) GL.glDrawBuffers(2,self.renderBufferAt) self._draw() # Draw on the FBO GL.glBindFramebuffer(GL.GL_FRAMEBUFFER,0) GL.glBindFramebuffer(GL.GL_READ_FRAMEBUFFER, self.fbo); GL.glReadBuffer(GL.GL_COLOR_ATTACHMENT0); # read from FBO color0 GL.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, 0); GL.glDrawBuffers((GL.GL_BACK,)) # write to window frame buffer color0 GL.glBlitFramebuffer(0,0,self.fboWidth,self.fboHeight,0,0,self.width,self.height,GL.GL_COLOR_BUFFER_BIT,GL.GL_LINEAR) else: self._draw()
def render_stereo_targets(self): GL.glClearColor(0, 0, 0, 1) GL.glEnable(GL.GL_MULTISAMPLE) # Left Eye GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, self.left_eye_desc.render_framebuffer_id) GL.glViewport(0, 0, self.render_width, self.render_height) self.render_scene(openvr.Eye_Left) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0) GL.glDisable(GL.GL_MULTISAMPLE) GL.glBindFramebuffer(GL.GL_READ_FRAMEBUFFER, self.left_eye_desc.render_framebuffer_id) GL.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, self.left_eye_desc.resolve_framebuffer_id) GL.glBlitFramebuffer(0, 0, self.render_width, self.render_height, 0, 0, self.render_width, self.render_height, GL.GL_COLOR_BUFFER_BIT, GL.GL_LINEAR) GL.glBindFramebuffer(GL.GL_READ_FRAMEBUFFER, 0) GL.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, 0) # Right Eye GL.glEnable(GL.GL_MULTISAMPLE) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, self.right_eye_desc.render_framebuffer_id) GL.glViewport(0, 0, self.render_width, self.render_height) self.render_scene(openvr.Eye_Right) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0) GL.glDisable(GL.GL_MULTISAMPLE) GL.glBindFramebuffer(GL.GL_READ_FRAMEBUFFER, self.right_eye_desc.render_framebuffer_id) GL.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, self.right_eye_desc.resolve_framebuffer_id) GL.glBlitFramebuffer(0, 0, self.render_width, self.render_height, 0, 0, self.render_width, self.render_height, GL.GL_COLOR_BUFFER_BIT, GL.GL_LINEAR) GL.glBindFramebuffer(GL.GL_READ_FRAMEBUFFER, 0) GL.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, 0)
def renderToImage(self, width, height, filename=None, num_samples=16): """Render the current active GLWindow into a file""" import copy import OpenGL.GL as GL from qtpy import QtOpenGL viewport = GL.glGetIntegerv( GL.GL_VIEWPORT ) GL.glViewport(0, 0, width, height) GL.glEnable(GL.GL_MULTISAMPLE) # ======================================= # create framebuffer without multisampling simple_fb = GL.glGenFramebuffers(1) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, simple_fb) # create renderbuffer for image without multisampling simple_rb = GL.glGenRenderbuffers(1) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, simple_rb) GL.glRenderbufferStorage(GL.GL_RENDERBUFFER, GL.GL_RGBA8, width, height) GL.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, GL.GL_RENDERBUFFER, simple_rb) # ======================================= # create framebuffer with multisampling fb = GL.glGenFramebuffers(1) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, fb) # create renderbuffer for image rb = GL.glGenRenderbuffers(1) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, rb) GL.glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, num_samples, GL.GL_RGBA8, width, height) GL.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, GL.GL_RENDERBUFFER, rb) # renderbuffer for depth depth_rb = GL.glGenRenderbuffers(1) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, depth_rb) GL.glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, num_samples, GL.GL_DEPTH_COMPONENT32, width, height) GL.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, depth_rb) # render image self.window_tabber.activeGLWindow.glWidget.paintGL() GL.glFinish() # blit image from multisampled framebuffer to simple frambuffer GL.glBindFramebuffer(GL.GL_READ_FRAMEBUFFER, fb) GL.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, simple_fb) GL.glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL.GL_COLOR_BUFFER_BIT, GL.GL_NEAREST) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, simple_fb) data = GL.glReadPixels(0, 0, width, height, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, outputType=None) import PIL.Image as im image = im.frombytes('RGBA', (width,height), data).transpose(im.FLIP_TOP_BOTTOM) if filename!=None: image.save(filename) # cleanup GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0) GL.glDeleteFramebuffers(2, [fb, simple_fb]) GL.glDeleteRenderbuffers(2, [rb, simple_rb]) GL.glDeleteRenderbuffers(1, [depth_rb]) GL.glViewport(*viewport) return image
def render(self, meshes=None, **frame_data): self.vr_compositor.waitGetPoses(self.poses, openvr.k_unMaxTrackedDeviceCount, None, 0) hmd_pose = self.poses[openvr.k_unTrackedDeviceIndex_Hmd] if not hmd_pose.bPoseIsValid: yield None return hmd_34 = np.ctypeslib.as_array(cast( hmd_pose.mDeviceToAbsoluteTracking.m, c_float_p), shape=(3, 4)) poses = [hmd_34] velocities = [np.ctypeslib.as_array(hmd_pose.vVelocity.v)] angular_velocities = [ np.ctypeslib.as_array(hmd_pose.vAngularVelocity.v) ] for i in self._controller_indices: controller_pose = self.poses[i] if controller_pose.bPoseIsValid: pose_34 = np.ctypeslib.as_array(cast( controller_pose.mDeviceToAbsoluteTracking.m, c_float_p), shape=(3, 4)) poses.append(pose_34) velocities.append( np.ctypeslib.as_array(controller_pose.vVelocity.v)) angular_velocities.append( np.ctypeslib.as_array(controller_pose.vAngularVelocity.v)) hmd_matrix = self.hmd_matrix hmd_matrix_inv = self.hmd_matrix_inv hmd_matrix[:, :3] = hmd_34.T hmd_matrix_inv[:3, :3] = hmd_34[:, :3] np.dot(hmd_matrix[:3, :3], hmd_matrix[3, :3], out=hmd_matrix_inv[3, :3]) hmd_matrix_inv[3, :3] *= -1 for eye in (0, 1): np.dot(hmd_matrix_inv, self.eye_transforms[eye], out=self.eye_matrices[eye]) np.dot(self.eye_to_head_transforms[eye], hmd_matrix, out=self.camera_matrices[eye]) frame_data.update({ 'hmd_pose': hmd_34, 'hmd_velocity': velocities[0], 'hmd_angular_velocity': angular_velocities[0], 'controller_indices': self._controller_indices, 'controller_poses': poses[1:], 'controller_velocities': velocities[1:], 'controller_angular_velocities': angular_velocities[1:], 'camera_matrices': self.camera_matrices, 'eye_matrices': self.eye_matrices, 'projection_matrices': self.projection_matrices, 'projection_lrbts': self.projection_lrbts, 'window_size': self.render_target_size, 'iResolution': self.render_target_size, 'znear': self.znear, 'zfar': self.zfar }) # if self._nframes % 90 == 0: # _logger.debug('yielding frame_data:\n\n%s\n\n', # '\n'.join('%s:\n%s' % item for item in frame_data.items())) yield frame_data for eye in (0, 1): gl.glViewport(0, 0, self.vr_framebuffers[eye].width, self.vr_framebuffers[eye].height) gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.vr_framebuffers[eye].fb) gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) frame_data['view_matrix'] = self.eye_matrices[eye] frame_data['camera_matrix'] = self.camera_matrices[eye] frame_data['projection_matrix'] = self.projection_matrices[eye] frame_data['projection_lrbt'] = self.projection_lrbts[eye] # if self._nframes % 90 == 0: # _logger.debug('drawing for eye %d with frame_data:\n\n%s\n\n', eye, # '\n'.join('%s:\n%s' % item for item in frame_data.items())) if meshes is not None: for mesh in meshes: mesh.draw(**frame_data) #self.vr_compositor.submit(openvr.Eye_Left, self.vr_framebuffers[0].texture) #self.vr_compositor.submit(openvr.Eye_Right, self.vr_framebuffers[1].texture) self.vr_framebuffers[0].submit(openvr.Eye_Left) self.vr_framebuffers[1].submit(openvr.Eye_Right) # mirror left eye framebuffer to screen: gl.glBindFramebuffer( gl.GL_READ_FRAMEBUFFER, self.vr_framebuffers[0].resolve_fb if self.vr_framebuffers[0].multisample else self.vr_framebuffers[0].fb) gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, 0) gl.glBlitFramebuffer(0, 0, self.vr_framebuffers[0].width, self.vr_framebuffers[0].height, 0, 0, self.window_size[0], self.window_size[1], gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT, gl.GL_NEAREST) self._nframes += 1
def main(): # start GLFW if not glfw.init(): return -1 # setup GLFW window options glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 2) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 1) # open the window window = glfw.create_window(800, 600, "Oculus Test", None, None) if not window: glfw.terminate() # always call this before setting up render layers glfw.make_context_current(window) # disable v-sync, we are syncing to the v-trace of head-set, leaving this on # will cause the HMD to lock to the frequency/phase of the display. glfw.swap_interval(0) # -------------------------------------------------------------------------- # Configure Rendering # initialize the runtime if failure(initialize()): _, msg = getLastErrorInfo() raise RuntimeError(msg) # create a new session if failure(create()): _, msg = getLastErrorInfo() raise RuntimeError(msg) # get general information about the HMD hmdInfo = getHmdInfo() # specify the eye render FOV for each render layer for eye, fov in enumerate(hmdInfo.defaultEyeFov): setEyeRenderFov(eye, fov) # get the optimal buffer dimensions for each eye texSizeLeft = calcEyeBufferSize(LIBOVR_EYE_LEFT) texSizeRight = calcEyeBufferSize(LIBOVR_EYE_RIGHT) # We are using a shared texture, so we need to combine dimensions. bufferW = texSizeLeft[0] + texSizeRight[0] bufferH = max(texSizeLeft[1], texSizeRight[1]) # initialize texture swap chain createTextureSwapChainGL(LIBOVR_TEXTURE_SWAP_CHAIN0, bufferW, bufferH) # set the same swap chain for both eyes since we are using a shared buffer for eye in range(LIBOVR_EYE_COUNT): setEyeColorTextureSwapChain(eye, LIBOVR_TEXTURE_SWAP_CHAIN0) # determine the viewports for each eye's image on the buffer eye_w = int(bufferW / 2) eye_h = bufferH # set the viewports viewports = ((0, 0, eye_w, eye_h), (eye_w, 0, eye_w, eye_h)) for eye, vp in enumerate(viewports): setEyeRenderViewport(eye, vp) # enable high quality mode setHighQuality(True) # create a frame buffer object as a render target for the HMD textures fboId = GL.GLuint() GL.glGenFramebuffers(1, ctypes.byref(fboId)) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, fboId) depthRb_id = GL.GLuint() GL.glGenRenderbuffers(1, ctypes.byref(depthRb_id)) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, depthRb_id) GL.glRenderbufferStorage(GL.GL_RENDERBUFFER, GL.GL_DEPTH24_STENCIL8, int(bufferW), int(bufferH)) # buffer size used here! GL.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, depthRb_id) GL.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, GL.GL_RENDERBUFFER, depthRb_id) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, 0) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0) # mirror texture FBO mirrorFbo = GL.GLuint() GL.glGenFramebuffers(1, ctypes.byref(mirrorFbo)) # setup a mirror texture, same size as the window createMirrorTexture(800, 600) # frame index, increment this every frame frame_index = 0 # begin application loop while not glfw.window_should_close(window): # wait for the buffer to be freed by the compositor, this is like # waiting for v-sync. waitToBeginFrame(frame_index) # predicted mid-frame time abs_time = getPredictedDisplayTime(frame_index) # get the current tracking state tracking_state, calibrated_origin = getTrackingState(abs_time, True) # calculate eye poses, this needs to be called every frame headPose, state = tracking_state[LIBOVR_TRACKED_DEVICE_TYPE_HMD] calcEyePoses(headPose.pose) # start frame rendering beginFrame(frame_index) # bind the render FBO GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, fboId) # get the current texture handle for this eye view, these are queued # in the swap chain and released when free. Making draw calls to # any other texture in the swap chain not returned here will report # and error. _, swapIdx = getTextureSwapChainCurrentIndex( LIBOVR_TEXTURE_SWAP_CHAIN0) _, tex_id = getTextureSwapChainBufferGL(LIBOVR_TEXTURE_SWAP_CHAIN0, swapIdx) # bind the returned texture ID to the frame buffer's texture slot GL.glFramebufferTexture2D(GL.GL_DRAW_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, GL.GL_TEXTURE_2D, tex_id, 0) # for each eye, do some rendering for eye in range(LIBOVR_EYE_COUNT): # Set the viewport as what was configured for the render layer. We # also need to enable scissor testings with the same rect as the # viewport. This constrains rendering operations to one partition of # of the buffer since we are using a 'packed' layout. vp = getEyeRenderViewport(eye) GL.glViewport(*vp) GL.glScissor(*vp) # Get view and projection matrices, must be flattened assuming # column-major ('F') order into a 1x16 vector. P = np.ctypeslib.as_ctypes( getEyeProjectionMatrix(eye).flatten('F')) MV = np.ctypeslib.as_ctypes(getEyeViewMatrix(eye).flatten('F')) # Note - you don't need to get eye projection matrices each frame, # they are computed only when the eye FOVs are updated. You can # compute the eye projection matrices once before entering your # render loop if you don't plan on changing them during a session. # # However, the view matrices should be computed every frame! GL.glEnable(GL.GL_SCISSOR_TEST) # enable scissor test GL.glEnable(GL.GL_DEPTH_TEST) # Set the projection matrix. GL.glMatrixMode(GL.GL_PROJECTION) GL.glLoadIdentity() GL.glMultMatrixf(P) # Set the view matrix. This contains the translation for the head in # the virtual space computed by the API. GL.glMatrixMode(GL.GL_MODELVIEW) GL.glLoadIdentity() GL.glMultMatrixf(MV) # Note - We are not using shaders here to keep things simple. # However, you can pass computed transforms to a shader program # if you like. # Okay, let's begin drawing stuff. Clear the background first. GL.glClearColor(0.5, 0.5, 0.5, 1.0) GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) # Draw a white 2x2 meter square positioned 5 meters in front of the # virtual space's origin. GL.glColor3f(1.0, 1.0, 1.0) GL.glPushMatrix() GL.glBegin(GL.GL_QUADS) GL.glVertex3f(-1.0, -1.0, -5.0) GL.glVertex3f(-1.0, 1.0, -5.0) GL.glVertex3f(1.0, 1.0, -5.0) GL.glVertex3f(1.0, -1.0, -5.0) GL.glEnd() GL.glPopMatrix() GL.glDisable(GL.GL_DEPTH_TEST) # commit the texture when were done drawing to it commitTextureSwapChain(LIBOVR_TEXTURE_SWAP_CHAIN0) # unbind the frame buffer, we're done with it GL.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, 0) # end frame rendering, submitting the eye layer to the compositor endFrame(frame_index) # increment frame index frame_index += 1 # blit mirror texture GL.glBindFramebuffer(GL.GL_READ_FRAMEBUFFER, mirrorFbo) GL.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, 0) _, mirrorId = getMirrorTexture() # bind the rift's mirror texture to the framebuffer GL.glFramebufferTexture2D(GL.GL_READ_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, GL.GL_TEXTURE_2D, mirrorId, 0) # render the mirror texture to the on-screen window's back buffer GL.glViewport(0, 0, 800, 600) GL.glScissor(0, 0, 800, 600) GL.glClearColor(0.0, 0.0, 0.0, 1.0) GL.glClear(GL.GL_COLOR_BUFFER_BIT) GL.glBlitFramebuffer( 0, 0, 800, 600, 0, 600, 800, 0, # this flips the texture GL.GL_COLOR_BUFFER_BIT, GL.GL_NEAREST) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0) # if button 'A' is released on the touch controller, recenter the # viewer in the scene. If 'B' was pressed, exit the loop. updateInputState(LIBOVR_CONTROLLER_TYPE_TOUCH) A = getButton(LIBOVR_CONTROLLER_TYPE_TOUCH, LIBOVR_BUTTON_A, 'falling') B = getButton(LIBOVR_CONTROLLER_TYPE_TOUCH, LIBOVR_BUTTON_B, 'falling') if A[0]: # first value is the state, second is the polling time recenterTrackingOrigin() elif B[0]: # exit if button 'B' is pressed break # flip the GLFW window and poll events glfw.swap_buffers(window) glfw.poll_events() # free resources destroyMirrorTexture() destroyTextureSwapChain(LIBOVR_TEXTURE_SWAP_CHAIN0) destroy() # end the rift session cleanly shutdown() # close the GLFW application glfw.terminate() return 0
def render(self, meshes=None): self.vr_compositor.waitGetPoses(self.poses, openvr.k_unMaxTrackedDeviceCount, None, 0) hmd_pose = self.poses[openvr.k_unTrackedDeviceIndex_Hmd] if not hmd_pose.bPoseIsValid: yield None return hmd_34 = np.ctypeslib.as_array(cast( hmd_pose.mDeviceToAbsoluteTracking.m, c_float_p), shape=(3, 4)) poses = [hmd_34] velocities = [np.ctypeslib.as_array(hmd_pose.vVelocity.v)] angular_velocities = [ np.ctypeslib.as_array(hmd_pose.vAngularVelocity.v) ] self.hmd_matrix[:, :3] = hmd_34.T view = np.linalg.inv(self.hmd_matrix) for i in self._controller_indices: controller_pose = self.poses[i] if controller_pose.bPoseIsValid: pose_34 = np.ctypeslib.as_array(cast( controller_pose.mDeviceToAbsoluteTracking.m, c_float_p), shape=(3, 4)) poses.append(pose_34) velocities.append( np.ctypeslib.as_array(controller_pose.vVelocity.v)) angular_velocities.append( np.ctypeslib.as_array(controller_pose.vAngularVelocity.v)) for eye in (0, 1): view.dot(self.eye_transforms[eye], out=self.view_matrices[eye]) frame_data = { 'hmd_pose': hmd_34, 'hmd_velocity': velocities[0], 'hmd_angular_velocity': angular_velocities[0], 'controller_poses': poses[1:], 'controller_velocities': velocities[1:], 'controller_angular_velocities': angular_velocities[1:], 'view_matrices': self.view_matrices, 'projection_matrices': self.projection_matrices, } yield frame_data gl.glViewport(0, 0, self.vr_framebuffers[0].width, self.vr_framebuffers[0].height) for eye in (0, 1): gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.vr_framebuffers[eye].fb) gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) frame_data['view_matrix'] = self.view_matrices[eye] frame_data['projection_matrix'] = self.projection_matrices[eye] if meshes is not None: for mesh in meshes: mesh.draw(**frame_data) #self.vr_compositor.submit(openvr.Eye_Left, self.vr_framebuffers[0].texture) self.vr_framebuffers[0].submit(openvr.Eye_Left) #self.vr_compositor.submit(openvr.Eye_Right, self.vr_framebuffers[1].texture) self.vr_framebuffers[1].submit(openvr.Eye_Right) # mirror left eye framebuffer to screen: # gl.glBlitNamedFramebuffer(self.vr_framebuffers[0].fb, 0, # 0, 0, self.vr_framebuffers[0].width, self.vr_framebuffers[0].height, # 0, 0, self.window_size[0], self.window_size[1], # gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT | gl.GL_STENCIL_BUFFER_BIT, gl.GL_LINEAR) gl.glBindFramebuffer(gl.GL_READ_FRAMEBUFFER, self.vr_framebuffers[0].fb) gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, 0) gl.glBlitFramebuffer(0, 0, self.vr_framebuffers[0].width, self.vr_framebuffers[0].height, 0, 0, self.window_size[0], self.window_size[1], gl.GL_COLOR_BUFFER_BIT, gl.GL_NEAREST) gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0)
def frame(self): ovr.waitToBeginFrame(self._i_frame) abs_time = ovr.getPredictedDisplayTime(self._i_frame) tracking_state = ovr.getTrackingState(abs_time, True) ovr.calcEyePoses(tracking_state.headPose.thePose) self.ypr = tracking_state.headPose.thePose.getYawPitchRoll() (self.yaw, self.pitch, self.roll) = self.ypr ovr.beginFrame(self._i_frame) (_, i_swap) = ovr.getTextureSwapChainCurrentIndex(ovr.TEXTURE_SWAP_CHAIN0) (_, i_t) = ovr.getTextureSwapChainBufferGL(ovr.TEXTURE_SWAP_CHAIN0, i_swap) if self._msaa == 1: gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.i_fbo) gl.glFramebufferTexture2D( gl.GL_DRAW_FRAMEBUFFER, # target gl.GL_COLOR_ATTACHMENT0, # attachment gl.GL_TEXTURE_2D, # tex target i_t, # texture 0, # level ) else: gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.i_msaa_fbo) gl.glEnable(gl.GL_MULTISAMPLE) # "OpenGL will automatically convert the output colors from linear to the sRGB # colorspace if, and only if, GL_FRAMEBUFFER_SRGB is enabled" gl.glEnable(gl.GL_FRAMEBUFFER_SRGB) gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) view = ovr.getEyeViewMatrix(0) yield view if self._msaa > 1: gl.glBindFramebuffer(gl.GL_READ_FRAMEBUFFER, self.i_msaa_fbo) gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, self.i_fbo) gl.glFramebufferTexture2D( gl.GL_DRAW_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D, i_t, 0, ) gl.glBlitFramebuffer( 0, 0, self.tex_width, self.tex_height, 0, 0, self.tex_width, self.tex_height, gl.GL_COLOR_BUFFER_BIT, gl.GL_NEAREST, ) gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0) ovr.commitTextureSwapChain(ovr.TEXTURE_SWAP_CHAIN0) gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, 0) ovr.endFrame(self._i_frame) if self.mirror: gl.glBindFramebuffer(gl.GL_READ_FRAMEBUFFER, self.i_mirror_fbo) gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, 0) (_, mirror_id) = ovr.getMirrorTexture() # bind the rift's mirror texture to the framebuffer gl.glFramebufferTexture2D( gl.GL_READ_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D, mirror_id, 0, ) # render the mirror texture to the on-screen window's back buffer gl.glViewport(0, 0, self.tex_width, self.tex_height) gl.glBlitFramebuffer( 0, 0, self.tex_width, self.tex_height, 0, self.tex_height // 2, self.tex_width // 2, 0, # this flips the texture gl.GL_COLOR_BUFFER_BIT, gl.GL_NEAREST, ) gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0) gl.glDisable(gl.GL_FRAMEBUFFER_SRGB) gl.glDisable(gl.GL_DEPTH_TEST) gl.glDisable(gl.GL_SCISSOR_TEST) self._i_frame += 1
def main(): # start GLFW if not glfw.init(): return -1 # setup GLFW window options glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 2) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 1) # open the window window = glfw.create_window(800, 600, "Oculus Test", None, None) if not window: glfw.terminate() # always call this before setting up render layers glfw.make_context_current(window) # disable v-sync, we are syncing to the v-trace of head-set, leaving this on # will cause the HMD to lock to the frequency/phase of the display. glfw.swap_interval(0) # start an Oculus session capi.startSession() # get general information about the HMD hmd_desc = capi.getHmdDesc() # set the perf hud on capi.perfHudMode("PerfSummary") # configure the internal render descriptors for each eye for eye in range(capi.ovrEye_Count): capi.configEyeRenderDesc(eye, hmd_desc.DefaultEyeFov[eye]) # Get the buffer dimensions specified by the Rift SDK, we need them to # setup OpenGL frame buffers. tex_size_left = capi.getFovTextureSize( capi.ovrEye_Left, hmd_desc.DefaultEyeFov[0]) tex_size_right = capi.getFovTextureSize( capi.ovrEye_Right, hmd_desc.DefaultEyeFov[1]) # We are using a shared texture, so we need to combine dimensions. buffer_w = tex_size_left.w + tex_size_right.w buffer_h = max(tex_size_left.h, tex_size_right.h) # Allocate a swap chain for render buffer textures, the handle used is an # integer. You can allocated up to 32 swap chains, however you will likely # run out of video memory by then. # configure the swap chain swap_config = capi.ovrTextureSwapChainDesc() swap_config.Format = capi.OVR_FORMAT_R8G8B8A8_UNORM_SRGB swap_config.Type = capi.ovrTexture_2D swap_config.Width = buffer_w swap_config.Height = buffer_h # Initialize texture swap chain swap_chain = capi.createTextureSwapChainGL(swap_config) # Since we are using a shared texture, each eye's viewport is half the width # of the allocated buffer texture. eye_w = int(buffer_w / 2) eye_h = buffer_h # setup the render layer viewports = (vrmath.ovrRecti(0, 0, eye_w, eye_h), vrmath.ovrRecti(eye_w, 0, eye_w, eye_h)) for eye in range(capi.ovrEye_Count): capi.setRenderViewport(eye, viewports[eye]) capi.setRenderSwapChain(0, swap_chain) # set the swap chain #rift.setRenderSwapChain(1, None) # create a frame buffer object as a render target for the HMD textures fboId = GL.GLuint() GL.glGenFramebuffers(1, ctypes.byref(fboId)) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, fboId) depthRb_id = GL.GLuint() GL.glGenRenderbuffers(1, ctypes.byref(depthRb_id)) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, depthRb_id) GL.glRenderbufferStorage(GL.GL_RENDERBUFFER, GL.GL_DEPTH24_STENCIL8, int(buffer_w), int(buffer_h)) # buffer size used here! GL.glFramebufferRenderbuffer( GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, depthRb_id) GL.glFramebufferRenderbuffer( GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, GL.GL_RENDERBUFFER, depthRb_id) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, 0) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0) # mirror texture FBO mirrorFbo = GL.GLuint() GL.glGenFramebuffers(1, ctypes.byref(mirrorFbo)) # setup a mirror texture mirror_config = capi.ovrMirrorTextureDesc() mirror_config.Width = 800 mirror_config.Height = 600 capi.setupMirrorTexture(mirror_config) # same size as window # frame index, increment this every frame frame_index = 0 # compute projection matrices proj_left = capi.getEyeProjectionMatrix(capi.ovrEye_Left) proj_right = capi.getEyeProjectionMatrix(capi.ovrEye_Right) # get the player height print(capi.getPlayerHeight()) # begin application loop while not glfw.window_should_close(window): # wait for the buffer to be freed by the compositor, this is like # waiting for v-sync. capi.waitToBeginFrame(frame_index) #print(proj_left.M) # get current display time + predicted mid-frame time abs_time = capi.getDisplayTime(frame_index) # get the current tracking state tracking_state = capi.getTrackingState(abs_time) # Calculate eye poses, this needs to be called every frame, do this # after calling 'wait_to_begin_frame' to minimize the motion-to-photon # latency. left_eye_pose, right_eye_pose = capi.calcEyePoses( tracking_state) # get the view matrix from the HMD after calculating the pose view_left = capi.getEyeViewMatrix(left_eye_pose) view_right = capi.getEyeViewMatrix(right_eye_pose) # start frame rendering capi.beginFrame(frame_index) # bind the render FBO GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, fboId) # get the current texture handle for this eye view, these are queued # in the swap chain and released when free. Making draw calls to # any other texture in the swap chain not returned here will report # and error. tex_id = capi.getTextureSwapChainBufferGL(swap_chain) # bind the returned texture ID to the frame buffer's texture slot GL.glFramebufferTexture2D( GL.GL_DRAW_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, GL.GL_TEXTURE_2D, tex_id, 0) # for each eye, do some rendering for eye in range(capi.ovrEye_Count): # Set the viewport as what was configured for the render layer. We # also need to enable scissor testings with the same rect as the # viewport. This constrains rendering operations to one partition of # of the buffer since we are using a 'packed' layout. vp = capi.getRenderViewport(eye) GL.glViewport(*vp.asTuple()) GL.glScissor(*vp.asTuple()) GL.glEnable(GL.GL_SCISSOR_TEST) # enable scissor test GL.glEnable(GL.GL_DEPTH_TEST) # Here we can make whatever OpenGL we wish to draw our image. As an # example, I'm going to clear the eye buffer texture all some color, # with the colour determined by the active eye buffer. if eye == capi.ovrEye_Left: GL.glMatrixMode(GL.GL_PROJECTION) GL.glLoadIdentity() GL.glMultMatrixf(proj_left.ctypes) GL.glMatrixMode(GL.GL_MODELVIEW) GL.glLoadIdentity() if HEAD_TRACKING: GL.glMultMatrixf(view_left.ctypes) GL.glClearColor(0.5, 0.5, 0.5, 1.0) GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) GL.glColor3f(1.0, 1.0, 1.0) GL.glPushMatrix() GL.glBegin(GL.GL_QUADS) GL.glVertex3f(-1.0, -1.0, -5.0) GL.glVertex3f(-1.0, 1.0, -5.0) GL.glVertex3f(1.0, 1.0, -5.0) GL.glVertex3f(1.0, -1.0, -5.0) GL.glEnd() GL.glPopMatrix() elif eye == capi.ovrEye_Right: GL.glMatrixMode(GL.GL_PROJECTION) GL.glLoadIdentity() GL.glMultMatrixf(proj_right.ctypes) GL.glMatrixMode(GL.GL_MODELVIEW) GL.glLoadIdentity() if HEAD_TRACKING: GL.glMultMatrixf(view_right.ctypes) GL.glClearColor(0.5, 0.5, 0.5, 1.0) GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) GL.glColor3f(1.0, 1.0, 1.0) GL.glPushMatrix() GL.glBegin(GL.GL_QUADS) GL.glVertex3f(-1.0, -1.0, -5.0) GL.glVertex3f(-1.0, 1.0, -5.0) GL.glVertex3f(1.0, 1.0, -5.0) GL.glVertex3f(1.0, -1.0, -5.0) GL.glEnd() GL.glPopMatrix() GL.glDisable(GL.GL_DEPTH_TEST) # commit the texture when were done drawing to it capi.commitSwapChain(swap_chain) # unbind the frame buffer, we're done with it GL.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, 0) # end frame rendering, submitting the eye layer to the compositor capi.endFrame(frame_index) # increment frame index frame_index += 1 # update session status session_status = capi.getSessionStatus() # blit mirror texture GL.glBindFramebuffer(GL.GL_READ_FRAMEBUFFER, mirrorFbo) GL.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, 0) # bind the rift's texture to the framebuffer GL.glFramebufferTexture2D( GL.GL_READ_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, GL.GL_TEXTURE_2D, capi.getMirrorTexture(), 0) GL.glViewport(0, 0, 800, 600) GL.glScissor(0, 0, 800, 600) GL.glClearColor(0.0, 0.0, 0.0, 1.0) GL.glClear(GL.GL_COLOR_BUFFER_BIT) GL.glBlitFramebuffer(0, 0, 800, 600, 0, 600, 800, 0, # this flips the texture GL.GL_COLOR_BUFFER_BIT, GL.GL_NEAREST) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0) capi.pollController('touch') # update touch controller state # if button 'A' is released on the touch controller, recenter the # viewer in the scene. if capi.getButtons('touch', 'A', 'falling'): capi.recenterTrackingOrigin() elif capi.getButtons('touch', 'B', 'falling'): # exit if button 'B' is pressed break # flip the GLFW window and poll events glfw.swap_buffers(window) glfw.poll_events() # switch off the performance summary capi.perfHudMode("Off") # end the rift session cleanly, all swap chains are destroyed here capi.endSession() # close the GLFW application glfw.terminate() return 0
def main(): if not glfw.init(): return -1 if not glfw.init(): return -1 glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 2) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 1) window = glfw.create_window(800, 600, "Oculus Test", None, None) if not window: glfw.terminate() glfw.make_context_current(window) glfw.swap_interval(0) if failure(initialize()): return -1 if failure(create()): shutdown() return -1 hmdInfo = getHmdInfo() for eye, fov in enumerate(hmdInfo.defaultEyeFov): setEyeRenderFov(eye, fov) texSizeLeft = calcEyeBufferSize(EYE_LEFT) texSizeRight = calcEyeBufferSize(EYE_RIGHT) bufferW = texSizeLeft[0] + texSizeRight[0] bufferH = max(texSizeLeft[1], texSizeRight[1]) createTextureSwapChainGL(TEXTURE_SWAP_CHAIN0, bufferW, bufferH) for eye in range(EYE_COUNT): setEyeColorTextureSwapChain(eye, TEXTURE_SWAP_CHAIN0) eye_w = int(bufferW / 2) eye_h = bufferH viewports = ((0, 0, eye_w, eye_h), (eye_w, 0, eye_w, eye_h)) for eye, vp in enumerate(viewports): setEyeRenderViewport(eye, vp) setHighQuality(True) fboId = GL.GLuint() GL.glGenFramebuffers(1, ctypes.byref(fboId)) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, fboId) depthRb_id = GL.GLuint() GL.glGenRenderbuffers(1, ctypes.byref(depthRb_id)) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, depthRb_id) GL.glRenderbufferStorage(GL.GL_RENDERBUFFER, GL.GL_DEPTH24_STENCIL8, int(bufferW), int(bufferH)) # buffer size used here! GL.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, depthRb_id) GL.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, GL.GL_RENDERBUFFER, depthRb_id) GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, 0) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0) mirrorFbo = GL.GLuint() GL.glGenFramebuffers(1, ctypes.byref(mirrorFbo)) createMirrorTexture(800, 600, mirrorOptions=MIRROR_OPTION_DEFAULT) frame_index = 0 projectionMatrix = [] for eye in range(EYE_COUNT): projectionMatrix.append(getEyeProjectionMatrix(eye)) planePose = LibOVRPose((0., 0., -2.)) # begin application loop while not glfw.window_should_close(window): waitToBeginFrame(frame_index) abs_time = getPredictedDisplayTime(frame_index) tracking_state = getTrackingState(abs_time, True) calcEyePoses(tracking_state.headPose.thePose) beginFrame(frame_index) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, fboId) _, swapIdx = getTextureSwapChainCurrentIndex(TEXTURE_SWAP_CHAIN0) _, tex_id = getTextureSwapChainBufferGL(TEXTURE_SWAP_CHAIN0, swapIdx) GL.glFramebufferTexture2D(GL.GL_DRAW_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, GL.GL_TEXTURE_2D, tex_id, 0) for eye in range(EYE_COUNT): vp = getEyeRenderViewport(eye) GL.glViewport(*vp) GL.glScissor(*vp) P = projectionMatrix[eye] MV = getEyeViewMatrix(eye) GL.glEnable(GL.GL_SCISSOR_TEST) GL.glEnable(GL.GL_DEPTH_TEST) GL.glMatrixMode(GL.GL_PROJECTION) GL.glLoadTransposeMatrixf(P) GL.glMatrixMode(GL.GL_MODELVIEW) GL.glLoadTransposeMatrixf(MV) GL.glClearColor(0.0, 0.0, 0.0, 1.0) GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) GL.glPushMatrix() GL.glMultTransposeMatrixf(planePose.modelMatrix) GL.glBegin(GL.GL_QUADS) GL.glColor3f(1.0, 0.0, 0.0) GL.glVertex3f(-1.0, -1.0, 0.0) GL.glColor3f(0.0, 1.0, 0.0) GL.glVertex3f(-1.0, 1.0, 0.0) GL.glColor3f(0.0, 0.0, 1.0) GL.glVertex3f(1.0, 1.0, 0.0) GL.glColor3f(1.0, 1.0, 1.0) GL.glVertex3f(1.0, -1.0, 0.0) GL.glEnd() GL.glPopMatrix() GL.glDisable(GL.GL_DEPTH_TEST) commitTextureSwapChain(TEXTURE_SWAP_CHAIN0) GL.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, 0) endFrame(frame_index) frame_index += 1 GL.glBindFramebuffer(GL.GL_READ_FRAMEBUFFER, mirrorFbo) GL.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, 0) _, mirrorId = getMirrorTexture() GL.glFramebufferTexture2D(GL.GL_READ_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, GL.GL_TEXTURE_2D, mirrorId, 0) GL.glViewport(0, 0, 800, 600) GL.glScissor(0, 0, 800, 600) GL.glClearColor(0.0, 0.0, 0.0, 1.0) GL.glClear(GL.GL_COLOR_BUFFER_BIT) GL.glBlitFramebuffer(0, 0, 800, 600, 0, 600, 800, 0, GL.GL_COLOR_BUFFER_BIT, GL.GL_NEAREST) GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0) glfw.swap_buffers(window) updateInputState(CONTROLLER_TYPE_TOUCH) A = getButton(CONTROLLER_TYPE_TOUCH, BUTTON_A, 'falling') B = getButton(CONTROLLER_TYPE_TOUCH, BUTTON_B, 'falling') if A[0]: recenterTrackingOrigin() elif B[0]: break glfw.poll_events() _, sessionStatus = getSessionStatus() if sessionStatus.shouldQuit: break destroyMirrorTexture() destroyTextureSwapChain(TEXTURE_SWAP_CHAIN0) destroy() # shutdown() causes access violation on exit return 0