title: Reading depth buffer with PyOpenGL
body: <p>Basically, I'm trying to extract a depth map (by this I mean a matrix with z corresponding to z-coordinates for vertices in <code>GL.glVertex3dv(vertex)</code> call - obviously, interpolated for plane pixels) after rendering a model (script is loading the model from file with path specified as the first command line argument). </p>
  
  <p>There are several questions which come to mind:</p>
  
  <ul>
  <li><p>why <code>glReadPixels</code> call returns a numpy array with shape <code>(width, shape)</code>, instead of <code>(height, width)</code>? </p></li>
  <li><p>why it returns some trash, not connected to the rendered model?</p></li>
  <li><p>is there an easy way to get z-coordinates on OpenGL legacy code with PyOpenGL framework?</p></li>
  <li><p>is it correct that maximum I can get here is some array with range <code>[0; 1]</code>, basically is some fraction between zNear and zFar (and normalized by glReadPixels, for whatever reason)?</p></li>
  </ul>
  
  <p>The code itself:</p>
  
  <pre><code>import sys
  import argparse
  import pyassimp
  from pyassimp.postprocess import aiProcess_JoinIdenticalVertices, aiProcess_Triangulate
  import numpy as np
  import matplotlib.pyplot as plt
  from collections import namedtuple
  from OpenGL import GL, GLUT
  
  Mesh = namedtuple('Mesh', ('vertices', 'faces'))
  
  def load_mesh(filename):
      scene = pyassimp.load(filename, processing=aiProcess_JoinIdenticalVertices | aiProcess_Triangulate)
      mesh = scene.mMeshes[0].contents
  
      def get_vector_array(vector):
          return [vector.x, vector.y, vector.z]
  
      def get_face_array(face):
          return [face.mIndices[i] for i in xrange(face.mNumIndices)]
  
      vertices = np.array([get_vector_array(mesh.mVertices[i]) for i in xrange(mesh.mNumVertices)])
      faces = np.array([get_face_array(mesh.mFaces[i]) for i in xrange(mesh.mNumFaces)])
  
      pyassimp.release(scene)
  
      return Mesh(vertices, faces)
  
  
  def load_ortho():
      GL.glMatrixMode(GL.GL_PROJECTION)
      GL.glLoadIdentity()
      GL.glOrtho(-1, 1, -1, 1, -1, 1)
      GL.glMatrixMode(GL.GL_MODELVIEW)
      GL.glLoadIdentity()
  
  
  mesh = None
  width, height = 1920, 1080
  
  def draw_mesh():
      global mesh, width, height
      GL.glClearColor(0, 0, 0, 0)
      GL.glClearDepth(0.5)
      GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
      GL.glDepthMask(GL.GL_TRUE)
      load_ortho()
      for face in mesh.faces:
          GL.glBegin(GL.GL_POLYGON)
          for vertex in mesh.vertices[face]:
              GL.glVertex3dv(vertex)
          GL.glEnd()
      GLUT.glutSwapBuffers()
      d = GL.glReadPixels(0, 0, width, height, GL.GL_DEPTH_COMPONENT, GL.GL_FLOAT)
      plt.imshow(d)
      plt.show()
  
  
  def reshape(w, h):
      GL.glViewport(0, 0, w, h)
      GLUT.glutDisplayFunc(draw_mesh)
      GLUT.glutPostRedisplay()
  
  
  def init(width, height):
      GLUT.glutInit(sys.argv)
      GLUT.glutInitDisplayMode(GLUT.GLUT_RGBA | GLUT.GLUT_DOUBLE)
      GLUT.glutInitWindowSize(width, height)
      GLUT.glutInitWindowPosition(0, 0)
      GLUT.glutCreateWindow("test")
      # GLUT.glutDisplayFunc(draw_mesh)
      # GLUT.glutIdleFunc(draw_mesh)
      GLUT.glutReshapeFunc(reshape)
      GLUT.glutIdleFunc(GLUT.glutPostRedisplay)
  
      def keyPressed(self, *args):
          if args[0] == '\033':
              sys.exit()
      GLUT.glutKeyboardFunc(keyPressed)
  
  
  if __name__ == '__main__':
      parser = argparse.ArgumentParser("Test on extracting depth while rendering a model with PyOpenGL")
      parser.add_argument("model", type=str)
      args = parser.parse_args()
      global mesh
      mesh = load_mesh(args.model)
  
      init(width, height)
      draw_mesh()
  </code></pre>
  
  <p>The model file I personally used for testing: <a href="https://graphics.stanford.edu/~mdfisher/Data/Meshes/bunny.obj" rel="nofollow noreferrer">bunny.obj</a>
  The snippet's result is <a href="https://i.stack.imgur.com/OCd5C.png" rel="nofollow noreferrer">here</a></p>