Bring support for the Looking Glass display to your application
Overview
Integrating with the Bridge SDK consists of five steps:
Configure a shared GPU rendering context
Initialize Bridge to spawn a post-processing thread and allocate resources
Create a Looking Glass window using the shared rendering context
Render views of a 3D scene into a framebuffer object
Trigger the Bridge post-processing step with the framebuffer object
This method of integration works for all Looking Glass displays. It is supported on Windows and MacOS using OpenGL. It is supported on Windows using DirectX 11 and 12. It is supported on MacOS using Metal. This method will apply a special transformation function that will map each diode on the Looking Glass display to the correct color corresponding to the direction of light emitted from the diode. This was previously the responsibility of the developer using HoloPlay Core. This example will demonstrate the aforementioned steps using OpenGL.
Configure a Shared GPU Rendering Context
The first step is to configure a GPU rendering context. This example code uses GLFW with GLAD:
The second step is to initialize Bridge. This step is required before calling any other Bridge functions.
initialize_bridge("Bridge SDK example");// query the available Looking Glass displaysint lkg_display_count =0;std::vector<unsignedlong> lkg_displays;get_displays(&lkg_display_count,nullptr);lkg_displays.resize(lkg_display_count);get_displays(&lkg_display_count,lkg_displays.data());
Create a Looking Glass window
The third step is to create a window that can be used to render to a Looking Glass display.
// perform any desired queries on the Looking Glass displaysstd::wstring serial;std::vector<std::wstring> lkg_display_serials;int serial_count =0;// query all connected Looking Glass displaysfor (auto it : lkg_displays) {get_device_serial_for_display(it,&serial_count,nullptr);serial.resize(serial_count);get_device_serial_for_display(it,&serial_count,serial.data());lkg_display_serials.push_back(serial);}// Note: callers are required to allocate enough memory for return parameters \of variable length// create window using configuration from the target Looking Glass displayunsignedlong lkg_wnd;instance_window_gl(&lkg_wnd,lkg_displays.front());
Render Views of a 3D Scene
The fourth step is to render a 3D scene into a framebuffer object using a quilt layout.
// Configure your 3D scene geometry and rendering pipeline...// Get idealized rendering parameters for the displayget_default_quilt_settings(lkg_wnd,&lkg_aspect,&lkg_quilt_w,&lkg_quilt_h,&lkg_vx,&lkg_vy);lkg_view_w =int(float(lkg_quilt_w) /float(lkg_vx));lkg_view_h =int(float(lkg_quilt_h) /float(lkg_vy));// Configure texture for the framebufferglGenTextures(1,&lkg_render_texture);glBindTexture(GL_TEXTURE_2D, lkg_render_texture);glTexImage2D(GL_TEXTURE_2D,0, GL_RGBA, lkg_quilt_w, lkg_quilt_h,0, GL_RGBA, GL_UNSIGNED_BYTE,nullptr);// Configure the renderbuffer for depthglGenRenderbuffers(1,&lkg_depth_buffer);glBindRenderbuffer(GL_RENDERBUFFER, lkg_depth_buffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, lkg_quilt_w, lkg_quilt_h);// Configure the shared framebuffer objectglGenFramebuffers(1,&lkg_render_fbo);glBindFramebuffer(GL_FRAMEBUFFER, lkg_render_fbo);glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, lkg_render_texture,0);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, lkg_depth_buffer);// Render views into framebuffer using quilt layoutglBindFramebuffer(GL_FRAMEBUFFER, lkg_render_fbo);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);float cam_dist =0.005f;float cam_offset =-(float)(lkg_vx * lkg_vy -1) /2.0f* cam_dist;for (int y =0; y < lkg_vx; y++) {for (int x =0; x < lkg_vy; x++) {glViewport(x*lkg_view_w, y*lkg_view_h, lkg_view_w, lkg_view_h); // drawScene(your_shader, your_geometry, cam_offset); cam_offset += cam_dist; }}
Trigger the Bridge Post-Processing
The fifth and last step consists of trigger the post-processing shader pipeline necessary to apply the Looking Glass optical transformation.