VR SDK for Android 0.1.1 ARM Developer Center
armvr.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2015-2017, ARM Limited and Contributors
2  *
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge,
6  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
21 #include "armvr.h"
22 
23 // These are the dimensions of the viewports (in pixels) used
24 // when rendering each eye's framebuffer.
25 #define View_Resolution_X (Screen_Resolution_X / 2)
26 #define View_Resolution_Y Screen_Resolution_Y
27 
28 // These are used to ensure that the distortion appears
29 // circular, even when the quad is stretched across a
30 // non-square region of the device. Furthermore, we use
31 // them to fit the resulting distorted image such that
32 // the rendered scene fully fits into the viewport.
33 #define View_Aspect_Ratio ((float)View_Resolution_X / (float)View_Resolution_Y)
34 #define Eye_Fb_Aspect_Ratio ((float)Eye_Fb_Resolution_X / (float)Eye_Fb_Resolution_Y)
35 
36 // The near-clipping plane does not need to be equal to the
37 // projection plane (the hmd). It can be set larger as long
38 // as you can ensure that no geometry gets clipped (since
39 // that is really jarring for users).
40 #define Z_Near (Eye_Display_Distance)
41 #define Z_Far Meter(12.0f)
42 
43 // Instead of recomputing the distortion per frame, we store
44 // the distorted texel lookup coordinates in the attributes of
45 // a tessellated quad. The coordinates are linearly interpolated
46 // between each vertex. This gives acceptable results given a
47 // high enough resolution of the mesh, even though the distortion
48 // equations are nonlinear.
49 #define Warp_Mesh_Resolution_X 64
50 #define Warp_Mesh_Resolution_Y 64
51 
53 typedef void (GL_APIENTRY* PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVR) (GLenum, GLenum, GLuint, GLint, GLsizei, GLint, GLsizei);
54 Framebuffer make_eye_framebuffer(int width, int height, int num_views)
55 {
56  Framebuffer result = {};
57  result.width = width;
58  result.height = height;
59  PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVR glFramebufferTextureMultiviewOVR =
60  (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVR)eglGetProcAddress ("glFramebufferTextureMultiviewOVR");
61  PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVR glFramebufferTextureMultisampleMultiviewOVR =
62  (PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVR)eglGetProcAddress ("glFramebufferTextureMultisampleMultiviewOVR");
63  if (!glFramebufferTextureMultiviewOVR)
64  {
65  LOGE("Did not have glFramebufferTextureMultiviewOVR\n");
66  exit(EXIT_FAILURE);
67  }
68  if (!glFramebufferTextureMultisampleMultiviewOVR)
69  {
70  LOGE("Did not have glFramebufferTextureMultisampleMultiviewOVR\n");
71  }
72  bool have_multisampled_ext = glFramebufferTextureMultisampleMultiviewOVR != 0;
73  GL_CHECK(glGenFramebuffers(1, &result.framebuffer));
74  GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, result.framebuffer));
75  GL_CHECK(glGenTextures(1, &result.depthbuffer));
76  GL_CHECK(glBindTexture(GL_TEXTURE_2D_ARRAY, result.depthbuffer));
77  GL_CHECK(glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_DEPTH_COMPONENT16, width, height, num_views));
78  if (have_multisampled_ext)
79  {
80  GL_CHECK(glFramebufferTextureMultisampleMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, result.depthbuffer, 0, Multisample_Samples, 0, num_views));
81  }
82  else
83  {
84  GL_CHECK(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, result.depthbuffer, 0, 0, num_views));
85  }
86  GL_CHECK(glGenTextures(1, &result.colorbuffer));
87  GL_CHECK(glBindTexture(GL_TEXTURE_2D_ARRAY, result.colorbuffer));
88  GL_CHECK(glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, width, height, num_views));
89  GL_CHECK(glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
90  GL_CHECK(glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
91  GL_CHECK(glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER_EXT));
92  GL_CHECK(glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER_EXT));
93  GLint border_color[4] = {0, 0, 0, 0};
94  GL_CHECK(glTexParameteriv(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BORDER_COLOR_EXT, border_color));
95  GL_CHECK(glBindTexture(GL_TEXTURE_2D_ARRAY, 0));
96  if (have_multisampled_ext)
97  {
98  GL_CHECK(glFramebufferTextureMultisampleMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, result.colorbuffer, 0, Multisample_Samples, 0, num_views));
99  }
100  else
101  {
102  GL_CHECK(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, result.colorbuffer, 0, 0, num_views));
103  }
104  GLenum status = GL_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER));
105  if (status != GL_FRAMEBUFFER_COMPLETE)
106  LOGE("Framebuffer not complete\n");
107  GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
108  return result;
109 }
111 {
112  float v[] = {
113  // front
114  -1.0f, -1.0f, +1.0f, 0.0f, 0.0f, +1.0f,
115  +1.0f, -1.0f, +1.0f, 0.0f, 0.0f, +1.0f,
116  +1.0f, +1.0f, +1.0f, 0.0f, 0.0f, +1.0f,
117  +1.0f, +1.0f, +1.0f, 0.0f, 0.0f, +1.0f,
118  -1.0f, +1.0f, +1.0f, 0.0f, 0.0f, +1.0f,
119  -1.0f, -1.0f, +1.0f, 0.0f, 0.0f, +1.0f,
120  // back
121  -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f,
122  -1.0f, +1.0f, -1.0f, 0.0f, 0.0f, -1.0f,
123  +1.0f, +1.0f, -1.0f, 0.0f, 0.0f, -1.0f,
124  +1.0f, +1.0f, -1.0f, 0.0f, 0.0f, -1.0f,
125  +1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f,
126  -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f,
127  // left
128  -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f,
129  -1.0f, -1.0f, +1.0f, -1.0f, 0.0f, 0.0f,
130  -1.0f, +1.0f, +1.0f, -1.0f, 0.0f, 0.0f,
131  -1.0f, +1.0f, +1.0f, -1.0f, 0.0f, 0.0f,
132  -1.0f, +1.0f, -1.0f, -1.0f, 0.0f, 0.0f,
133  -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f,
134  // right
135  +1.0f, -1.0f, -1.0f, +1.0f, 0.0f, 0.0f,
136  +1.0f, +1.0f, -1.0f, +1.0f, 0.0f, 0.0f,
137  +1.0f, +1.0f, +1.0f, +1.0f, 0.0f, 0.0f,
138  +1.0f, +1.0f, +1.0f, +1.0f, 0.0f, 0.0f,
139  +1.0f, -1.0f, +1.0f, +1.0f, 0.0f, 0.0f,
140  +1.0f, -1.0f, -1.0f, +1.0f, 0.0f, 0.0f,
141  // up
142  -1.0f, +1.0f, -1.0f, 0.0f, +1.0f, 0.0f,
143  -1.0f, +1.0f, +1.0f, 0.0f, +1.0f, 0.0f,
144  +1.0f, +1.0f, +1.0f, 0.0f, +1.0f, 0.0f,
145  +1.0f, +1.0f, +1.0f, 0.0f, +1.0f, 0.0f,
146  +1.0f, +1.0f, -1.0f, 0.0f, +1.0f, 0.0f,
147  -1.0f, +1.0f, -1.0f, 0.0f, +1.0f, 0.0f,
148  // down
149  -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f,
150  +1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f,
151  +1.0f, -1.0f, +1.0f, 0.0f, -1.0f, 0.0f,
152  +1.0f, -1.0f, +1.0f, 0.0f, -1.0f, 0.0f,
153  -1.0f, -1.0f, +1.0f, 0.0f, -1.0f, 0.0f,
154  -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f
155  };
156  GLuint result = 0;
157  GL_CHECK(glGenBuffers(1, &result));
158  GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, result));
159  GL_CHECK(glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW));
160  return result;
161 }
162 // Computes the distorted texel coordinate given the
163 // position on the image plane.
164 vec2 compute_distortion(float x, float y,
165  vec2 distort_centre,
166  DistortionCoefficients coefficients,
167  float tex_coord_factor)
168 {
169  float k1 = coefficients.k1;
170  float k2 = coefficients.k2;
171  float k3 = coefficients.k3;
172  float p1 = coefficients.p1;
173  float p2 = coefficients.p2;
174  // We need to correct for aspect ratio to ensure that
175  // the distortion appears circular on the device.
176  y /= View_Aspect_Ratio;
177  float dx = x - distort_centre.x;
178  float dy = y - distort_centre.y;
179  float r2 = dx * dx + dy * dy;
180  float r4 = r2 * r2;
181  float r6 = r4 * r2;
182  float radial_x = x * (k1 * r2 + k2 * r4 + k3 * r6);
183  float radial_y = y * (k1 * r2 + k2 * r4 + k3 * r6);
184  float tangential_x = p1 * (r2 + 2.0f*x*x) + 2.0f*p2*x*y;
185  float tangential_y = p2 * (r2 + 2.0f*y*y) + 2.0f*p1*x*y;
186  float distorted_x = x + radial_x + tangential_x;
187  float distorted_y = y + radial_y + tangential_y;
188  float result_x = 0.5f + tex_coord_factor * distorted_x;
189  float result_y = 0.5f + tex_coord_factor * distorted_y * View_Aspect_Ratio;
190  return vec2(result_x, result_y);
191 }
193 {
194  struct Vertex
195  {
196  vec2 position;
197  vec2 uv_red_low_res;
198  vec2 uv_green_low_res;
199  vec2 uv_blue_low_res;
200  vec2 uv_red_high_res;
201  vec2 uv_green_high_res;
202  vec2 uv_blue_high_res;
203  };
204  static Vertex v[(Warp_Mesh_Resolution_X + 1) * (Warp_Mesh_Resolution_Y + 1)];
205  // Compute vertices
206  int vi = 0;
207  for (int yi = 0; yi <= Warp_Mesh_Resolution_Y; yi++)
208  for (int xi = 0; xi <= Warp_Mesh_Resolution_X; xi++)
209  {
210  float x = -1.0f + 2.0f * xi / Warp_Mesh_Resolution_X;
211  float y = -1.0f + 2.0f * yi / Warp_Mesh_Resolution_Y;
212  v[vi].position = vec2(x, y) * config.fill_scale + config.image_centre;
213  v[vi].uv_red_low_res = compute_distortion(x, y, config.distort_centre, config.coefficients_red, 0.5f);
214  v[vi].uv_green_low_res = compute_distortion(x, y, config.distort_centre, config.coefficients_green, 0.5f);
215  v[vi].uv_blue_low_res = compute_distortion(x, y, config.distort_centre, config.coefficients_blue, 0.5f);
216  // The texture coordinates for the higher resolution texture go from -0.5 to 1.5 so
217  // that only the center of the screen samples the high resolution texture.
218  v[vi].uv_red_high_res = compute_distortion(x, y, config.distort_centre, config.coefficients_red, 1.0f);
219  v[vi].uv_green_high_res = compute_distortion(x, y, config.distort_centre, config.coefficients_green, 1.0f);
220  v[vi].uv_blue_high_res = compute_distortion(x, y, config.distort_centre, config.coefficients_blue, 1.0f);
221  vi++;
222  }
223  // Generate faces from vertices
224  static Vertex f[Warp_Mesh_Resolution_X * Warp_Mesh_Resolution_Y * 6];
225  int fi = 0;
226  for (int yi = 0; yi < Warp_Mesh_Resolution_Y; yi++)
227  for (int xi = 0; xi < Warp_Mesh_Resolution_X; xi++)
228  {
229  Vertex v0 = v[(yi ) * (Warp_Mesh_Resolution_X + 1) + xi ];
230  Vertex v1 = v[(yi ) * (Warp_Mesh_Resolution_X + 1) + xi + 1];
231  Vertex v2 = v[(yi + 1) * (Warp_Mesh_Resolution_X + 1) + xi + 1];
232  Vertex v3 = v[(yi + 1) * (Warp_Mesh_Resolution_X + 1) + xi ];
233  f[fi++] = v0;
234  f[fi++] = v1;
235  f[fi++] = v2;
236  f[fi++] = v2;
237  f[fi++] = v3;
238  f[fi++] = v0;
239  }
240  GLuint result = 0;
241  GL_CHECK(glGenBuffers(1, &result));
242  GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, result));
243  GL_CHECK(glBufferData(GL_ARRAY_BUFFER, sizeof(f), f, GL_STATIC_DRAW));
244  return result;
245 }
246 // This computes a general frustum given four field-of-view (FOV)
247 // angles and the near and far clipping planes. The FOV angle is
248 // defined as the angle between the optical axis (i.e. the eye's
249 // forward direction) and the line from the eye to the respective
250 // edge of the screen.
251 mat4 make_frustum(float left_fov,
252  float right_fov,
253  float bottom_fov,
254  float top_fov,
255  float z_near,
256  float z_far)
257 {
258  mat4 result(0.0f);
259  float tt = tan(top_fov);
260  float tb = tan(bottom_fov);
261  float tl = tan(left_fov);
262  float tr = tan(right_fov);
263  result.x.x = 2.0f / (tl + tr);
264  result.y.y = 2.0f / (tt + tb);
265  result.z.x = (tl - tr) / (tl + tr);
266  result.z.y = (tt - tb) / (tt + tb);
267  result.z.z = (z_near + z_far) / (z_near - z_far);
268  result.w.w = -1.0f;
269  result.w.z = 2.0f * z_near * z_far / (z_near - z_far);
270  return result;
271 }
272 // This computes a general frustum given the distance
273 // from the viewer's eye to the display, and the corners
274 // of that eye's screen half relative to the eye.
275 // z_near and z_far decide the near and far clipping planes.
276 mat4 make_frustum_screen_viewer(float eye_display_distance,
277  float left,
278  float right,
279  float bottom,
280  float top,
281  float z_near,
282  float z_far)
283 {
284  mat4 result(0.0f);
285  result.x.x = 2.0f * eye_display_distance / (right - left);
286  result.y.y = 2.0f * eye_display_distance / (top - bottom);
287  result.z.x = (right + left) / (right - left);
288  result.z.y = (top + bottom) / (top - bottom);
289  result.z.z = (z_near + z_far) / (z_near - z_far);
290  result.z.w = -1.0f;
291  result.w.z = 2.0f * z_near * z_far / (z_near - z_far);
292  return result;
293 }
295 {
296  // Make sure the required extensions are present.
297  const GLubyte* extensions = glGetString(GL_EXTENSIONS);
298  char * found_multiview2_extension = strstr ((char*)extensions, "GL_OVR_multiview2");
299  char * found_multisample_multiview_extension = strstr ((char*)extensions, "GL_OVR_multiview_multisampled_render_to_texture");
300  char * found_border_clamp_extension = strstr ((char*)extensions, "GL_EXT_texture_border_clamp");
301  if (found_multiview2_extension == NULL)
302  {
303  LOGI("OpenGL ES 3.0 implementation does not support GL_OVR_multiview2 extension.\n");
304  exit(EXIT_FAILURE);
305  }
306  if (found_multisample_multiview_extension == NULL)
307  {
308  // If multisampled multiview is not supported, multisampling will not be used, so no need to exit here.
309  LOGI("OpenGL ES 3.0 implementation does not support GL_OVR_multiview_multisampled_render_to_texture extension.\n");
310  }
311  if (found_border_clamp_extension == NULL)
312  {
313  LOGI("OpenGL ES 3.0 implementation does not support GL_EXT_texture_border_clamp extension.\n");
314  exit(EXIT_FAILURE);
315  }
316  GL_CHECK(glGenVertexArrays(1, &app->vao));
317  GL_CHECK(glBindVertexArray(app->vao));
318  GL_CHECK(glViewport(0, 0, app->window_width, app->window_height));
319  app->vbo_cube = make_cube();
321  // The coefficients below may be calibrated by photographing an
322  // image containing straight lines, both vertical and horizontal,
323  // through the lenses of the HMD, at the position where the viewer
324  // would be looking through them.
325  // Ideally, the user would be allowed to calibrate them for their
326  // own eyes, through some calibration utility. The application should
327  // then load a stored user-profile on runtime. For now, we hardcode
328  // some values based on our calibration of the SM-R320 Gear VR
329  // lenses.
330  // Left lens
331  app->hmd.left.coefficients_red.k1 = 0.19f;
332  app->hmd.left.coefficients_red.k2 = 0.21f;
333  app->hmd.left.coefficients_red.k3 = 0.0f;
334  app->hmd.left.coefficients_red.p1 = 0.0f;
335  app->hmd.left.coefficients_red.p2 = 0.0f;
336  app->hmd.left.coefficients_green.k1 = 0.22f;
337  app->hmd.left.coefficients_green.k2 = 0.24f;
338  app->hmd.left.coefficients_green.k3 = 0.0f;
339  app->hmd.left.coefficients_green.p1 = 0.0f;
340  app->hmd.left.coefficients_green.p2 = 0.0f;
341  app->hmd.left.coefficients_blue.k1 = 0.24f;
342  app->hmd.left.coefficients_blue.k2 = 0.26f;
343  app->hmd.left.coefficients_blue.k3 = 0.0f;
344  app->hmd.left.coefficients_blue.p1 = 0.0f;
345  app->hmd.left.coefficients_blue.p2 = 0.0f;
346  // Right lens
347  app->hmd.right.coefficients_red.k1 = 0.19f;
348  app->hmd.right.coefficients_red.k2 = 0.21f;
349  app->hmd.right.coefficients_red.k3 = 0.0f;
350  app->hmd.right.coefficients_red.p1 = 0.0f;
351  app->hmd.right.coefficients_red.p2 = 0.0f;
352  app->hmd.right.coefficients_green.k1 = 0.22f;
353  app->hmd.right.coefficients_green.k2 = 0.24f;
354  app->hmd.right.coefficients_green.k3 = 0.0f;
355  app->hmd.right.coefficients_green.p1 = 0.0f;
356  app->hmd.right.coefficients_green.p2 = 0.0f;
357  app->hmd.right.coefficients_blue.k1 = 0.24f;
358  app->hmd.right.coefficients_blue.k2 = 0.26f;
359  app->hmd.right.coefficients_blue.k3 = 0.0f;
360  app->hmd.right.coefficients_blue.p1 = 0.0f;
361  app->hmd.right.coefficients_blue.p2 = 0.0f;
362  // These may be computed by measuring the distance between the top
363  // of the unscaled distorted image and the top of the screen. Denote
364  // this distance by Delta. The normalized view coordinate of the
365  // distorted image top is
366  // Y = 1 - 2 Delta / Screen_Size_Y
367  // We want to scale this coordinate such that it maps to the top of
368  // the view. That is,
369  // Y * fill_scale = 1
370  // Solving for fill_scale gives the equations below.
371  float delta = Centimeter(0.7f);
372  app->hmd.left.fill_scale = 1.0f / (1.0f - 2.0f * delta / Screen_Size_Y);
373  app->hmd.right.fill_scale = 1.0f / (1.0f - 2.0f * delta / Screen_Size_Y);
374  // These are computed such that the centers of the displayed framebuffers
375  // on the device are seperated by the viewer's IPD.
376  app->hmd.left.image_centre = vec2(+1.0f - Eye_IPD / (Screen_Size_X / 2.0f), 0.0f);
377  app->hmd.right.image_centre = vec2(-1.0f + Eye_IPD / (Screen_Size_X / 2.0f), 0.0f);
378  // These are computed such that the distortion takes place around
379  // an offset determined by the difference between lens seperation
380  // and the viewer's eye IPD. If the difference is zero, the distortion
381  // takes place around the image centre.
382  app->hmd.left.distort_centre = vec2((Lens_IPD - Eye_IPD) / (Screen_Size_X / 2.0f), 0.0f);
383  app->hmd.right.distort_centre = vec2((Eye_IPD - Lens_IPD) / (Screen_Size_X / 2.0f), 0.0f);
384  app->warp_mesh[0] = make_warp_mesh(app->hmd.left);
385  app->warp_mesh[1] = make_warp_mesh(app->hmd.right);
386  get_attrib_location( distort, position);
387  get_attrib_location( distort, uv_red_low_res);
388  get_attrib_location( distort, uv_green_low_res);
389  get_attrib_location( distort, uv_blue_low_res);
390  get_attrib_location( distort, uv_red_high_res);
391  get_attrib_location( distort, uv_green_high_res);
392  get_attrib_location( distort, uv_blue_high_res);
393  get_uniform_location(distort, layer_index);
394  get_uniform_location(distort, framebuffer);
395  get_attrib_location (cube, position);
396  get_attrib_location (cube, normal);
397  get_uniform_location(cube, projection);
398  get_uniform_location(cube, view);
399  get_uniform_location(cube, model);
400 }
402 {
403  int n = 5;
404  for (int zi = 0; zi <= n; zi++)
405  for (int xi = 0; xi <= n; xi++)
406  {
407  float x = Centimeter(-100.0f) + 2.0f * Centimeter(100.0f * xi / n);
408  float z = Centimeter(-100.0f * zi);
409  int i = zi * n + xi;
410  mat4 mat_model = translate(x, 0.0f, z) *
411  scale(Centimeter(5.0f)) *
412  rotateY(0.3f * app->elapsed_time + i * 1.57f) *
413  rotateX(0.2f * app->elapsed_time + i * 3.2f);
414  uniformm4(cube, model, mat_model);
415  GL_CHECK(glDrawArrays(GL_TRIANGLES, 0, 36));
416  }
417  mat4 mat_model = translate(0.0f, Centimeter(70.0f), Centimeter(400.0f)) *
418  scale(Centimeter(5.0f)) *
419  rotateY(0.3f * app->elapsed_time) *
420  rotateX(0.05f * app->elapsed_time);
421  uniformm4(cube, model, mat_model);
422  GL_CHECK(glDrawArrays(GL_TRIANGLES, 0, 36));
423 }
425 {
426  GL_CHECK(glEnable(GL_DEPTH_TEST));
427  GL_CHECK(glDepthFunc(GL_LEQUAL));
428  GL_CHECK(glDepthMask(GL_TRUE));
429  GL_CHECK(glDepthRangef(0.0, 1.0));
430  GL_CHECK(glClearDepthf(1.0f));
431  GL_CHECK(glClearColor(0.15f, 0.17f, 0.2f, 1.0f));
433  // Cube shader
434  GL_CHECK(glUseProgram(app->program_cube));
435  GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, app->vbo_cube));
436  attribfv(cube, position, 3, 6, 0);
437  attribfv(cube, normal, 3, 6, 3);
438  float camera_z = Centimeter(500.0f);
439  float camera_y = Centimeter(70.0f);
440  mat4 mat_view[Num_Views];
441  mat_view[0] = translate(+Eye_IPD / 2.0f, -camera_y, -camera_z);
442  mat_view[1] = translate(-Eye_IPD / 2.0f, -camera_y, -camera_z);
443  mat_view[2] = translate(+Eye_IPD / 2.0f, -camera_y, -camera_z);
444  mat_view[3] = translate(-Eye_IPD / 2.0f, -camera_y, -camera_z);
445  // The scene is rendered twice for each eye position, once with a wide field of view, and
446  // once with a narrower field of view in order to render the midpoint of the screen with
447  // a higher resolution than the rest.
448  mat4 mat_projection[Num_Views];
449  mat_projection[0] = make_frustum_screen_viewer(
451  -(Screen_Size_X - Eye_IPD) / 2.0f,
452  +(Eye_IPD / 2.0f),
453  -Screen_Size_Y / 2.0f,
454  +Screen_Size_Y / 2.0f,
455  Z_Near, Z_Far);
456  mat_projection[1] = make_frustum_screen_viewer(
458  -(Eye_IPD / 2.0f),
459  +(Screen_Size_X - Eye_IPD) / 2.0f,
460  -Screen_Size_Y / 2.0f,
461  +Screen_Size_Y / 2.0f,
462  Z_Near, Z_Far);
463  float right_midpoint = -((Screen_Size_X/4.0f) - (Eye_IPD / 2.0f));
464  float left_midpoint = (Screen_Size_X/4.0f) - (Eye_IPD / 2.0f);
465  mat_projection[2] = make_frustum_screen_viewer(
467  right_midpoint - (Screen_Size_X/8.0f),
468  right_midpoint + (Screen_Size_X/8.0f),
469  -Screen_Size_Y / 4.0f,
470  +Screen_Size_Y / 4.0f,
471  Z_Near, Z_Far);
472  mat_projection[3] = make_frustum_screen_viewer(
474  left_midpoint - (Screen_Size_X/8.0f),
475  left_midpoint + (Screen_Size_X/8.0f),
476  -Screen_Size_Y / 4.0f,
477  +Screen_Size_Y / 4.0f,
478  Z_Near, Z_Far);
479  GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, app->fb.framebuffer));
480  GL_CHECK(glViewport(0, 0, app->fb.width, app->fb.height));
481  GL_CHECK(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
482  uniformm4array(cube, projection, mat_projection[0], Num_Views);
483  uniformm4array(cube, view, mat_view[0], Num_Views);
484  draw_scene(app);
486  // Distortion shader
487  GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
488  GL_CHECK(glDisable(GL_DEPTH_TEST));
489  GL_CHECK(glDepthMask(GL_FALSE));
490  GL_CHECK(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
491  GL_CHECK(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
492  GL_CHECK(glUseProgram(app->program_distort));
493  GL_CHECK(glActiveTexture(GL_TEXTURE0));
494  uniform1i(distort, framebuffer, 0);
495  // Left eye
496  GL_CHECK(glViewport(0, 0, View_Resolution_X, View_Resolution_Y));
497  GL_CHECK(glBindTexture(GL_TEXTURE_2D_ARRAY, app->fb.colorbuffer));
498  uniform1i(distort, layer_index, 0);
499  GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, app->warp_mesh[0]));
500  attribfv(distort, position, 2, 14, 0);
501  attribfv(distort, uv_red_low_res, 2, 14, 2);
502  attribfv(distort, uv_green_low_res, 2, 14, 4);
503  attribfv(distort, uv_blue_low_res, 2, 14, 6);
504  attribfv(distort, uv_red_high_res, 2, 14, 8);
505  attribfv(distort, uv_green_high_res, 2, 14, 10);
506  attribfv(distort, uv_blue_high_res, 2, 14, 12);
507  GL_CHECK(glDrawArrays(GL_TRIANGLES, 0, Warp_Mesh_Resolution_X * Warp_Mesh_Resolution_Y * 6));
508  // Right eye
510  uniform1i(distort, layer_index, 1);
511  GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, app->warp_mesh[1]));
512  attribfv(distort, position, 2, 14, 0);
513  attribfv(distort, uv_red_low_res, 2, 14, 2);
514  attribfv(distort, uv_green_low_res, 2, 14, 4);
515  attribfv(distort, uv_blue_low_res, 2, 14, 6);
516  attribfv(distort, uv_red_high_res, 2, 14, 8);
517  attribfv(distort, uv_green_high_res, 2, 14, 10);
518  attribfv(distort, uv_blue_high_res, 2, 14, 12);
519  GL_CHECK(glDrawArrays(GL_TRIANGLES, 0, Warp_Mesh_Resolution_X * Warp_Mesh_Resolution_Y * 6));
520 }
#define Warp_Mesh_Resolution_Y
Definition: armvr.cpp:50
void draw_scene(App *app)
Definition: armvr.cpp:401
#define Eye_IPD
Definition: armvr.h:66
#define Multisample_Samples
Definition: armvr.h:59
vec2 image_centre
Definition: armvr.h:129
#define uniform1i(prog, name, value)
Definition: armvr.h:215
#define LOGI(...)
Definition: armvr.h:87
static mat4 scale(float x, float y, float z)
Definition: matrix.h:237
DistortionCoefficients coefficients_green
Definition: armvr.h:117
#define uniformm4(prog, name, value)
Definition: armvr.h:216
int height
Definition: armvr.h:94
#define Eye_Display_Distance
Definition: armvr.h:74
#define get_attrib_location(prog, name)
Definition: armvr.h:193
GLuint framebuffer
Definition: armvr.h:95
#define GL_CHECK(x)
Definition: armvr.h:184
mat4 make_frustum(float left_fov, float right_fov, float bottom_fov, float top_fov, float z_near, float z_far)
Definition: armvr.cpp:251
GLuint colorbuffer
Definition: armvr.h:97
static mat4 rotateX(float rad)
Definition: matrix.h:199
static mat4 rotateY(float rad)
Definition: matrix.h:207
Definition: matrix.h:28
vec4 y
Definition: matrix.h:106
vec2 compute_distortion(float x, float y, vec2 distort_centre, DistortionCoefficients coefficients, float tex_coord_factor)
Definition: armvr.cpp:164
GLuint program_distort
Definition: armvr.h:155
GLuint make_warp_mesh(LensConfig config)
Definition: armvr.cpp:192
GLuint warp_mesh[Num_Eyes]
Definition: armvr.h:175
int window_width
Definition: armvr.h:150
static App app
Definition: main.cpp:30
#define attribfv(prog, name, n, stride, offset)
Definition: armvr.h:203
GLuint make_cube()
Definition: armvr.cpp:110
DistortionCoefficients coefficients_red
Definition: armvr.h:116
#define Num_Views
Definition: armvr.h:42
float fill_scale
Definition: armvr.h:135
typedef GLsizei
Definition: armvr.cpp:53
#define View_Aspect_Ratio
Definition: armvr.cpp:33
#define Screen_Size_X
Definition: armvr.h:47
float elapsed_time
Definition: armvr.h:153
LensConfig right
Definition: armvr.h:140
int window_height
Definition: armvr.h:151
GLuint vao
Definition: armvr.h:173
HMDConfig hmd
Definition: armvr.h:176
GLuint program_cube
Definition: armvr.h:166
void(GL_APIENTRY * PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVR)(GLenum, GLenum, GLuint, GLint, GLint, GLsizei)
Definition: armvr.cpp:52
#define Z_Near
Definition: armvr.cpp:40
float y
Definition: matrix.h:31
float w
Definition: matrix.h:80
mat4 make_frustum_screen_viewer(float eye_display_distance, float left, float right, float bottom, float top, float z_near, float z_far)
Definition: armvr.cpp:276
typedef GLuint
Definition: armvr.cpp:53
static mat4 translate(float x, float y, float z)
Definition: matrix.h:223
Framebuffer fb
Definition: armvr.h:177
#define Screen_Size_Y
Definition: armvr.h:48
Framebuffer make_eye_framebuffer(int width, int height, int num_views)
Definition: armvr.cpp:54
typedef void(GL_APIENTRY *PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVR)(GLenum
#define Eye_Fb_Resolution_X
Definition: armvr.h:54
vec4 w
Definition: matrix.h:106
GLuint vbo_cube
Definition: armvr.h:174
typedef GLenum
Definition: armvr.cpp:53
void app_initialize(App *app)
Definition: armvr.cpp:294
void app_update_and_render(App *app)
Definition: armvr.cpp:424
#define Warp_Mesh_Resolution_X
Definition: armvr.cpp:49
#define Lens_IPD
Definition: armvr.h:70
#define Z_Far
Definition: armvr.cpp:41
Definition: matrix.h:104
#define View_Resolution_X
Definition: armvr.cpp:25
#define get_uniform_location(prog, name)
Definition: armvr.h:198
float z
Definition: matrix.h:79
int width
Definition: armvr.h:93
Definition: armvr.h:148
#define uniformm4array(prog, name, value, arraySize)
Definition: armvr.h:217
vec4 z
Definition: matrix.h:106
GLuint depthbuffer
Definition: armvr.h:96
float x
Definition: matrix.h:30
LensConfig left
Definition: armvr.h:139
#define GL_TEXTURE_BORDER_COLOR_EXT
Definition: armvr.h:78
#define View_Resolution_Y
Definition: armvr.cpp:26
typedef GLint
Definition: armvr.cpp:53
#define Centimeter(x)
Definition: armvr.h:32
vec4 x
Definition: matrix.h:106
DistortionCoefficients coefficients_blue
Definition: armvr.h:118
#define Eye_Fb_Resolution_Y
Definition: armvr.h:55
float x
Definition: matrix.h:77
#define GL_CLAMP_TO_BORDER_EXT
Definition: armvr.h:82
float y
Definition: matrix.h:78
vec2 distort_centre
Definition: armvr.h:123
#define LOGE(...)
Definition: armvr.h:88