diff --git a/examples/GLVolumeItem.py b/examples/GLVolumeItem.py
index 163f4b7abc422a27f65bed27af3f048c2e38abf3..3f5b5fb24a5b118e86c0dc9d076cab7faa5d2316 100644
--- a/examples/GLVolumeItem.py
+++ b/examples/GLVolumeItem.py
@@ -46,11 +46,17 @@ d2[..., 1] = negative * (255./negative.max())
 d2[..., 2] = d2[...,1]
 d2[..., 3] = d2[..., 0]*0.3 + d2[..., 1]*0.3
 d2[..., 3] = (d2[..., 3].astype(float) / 255.) **2 * 255
-    
+
+d2[:, 0, 0] = [255,0,0,100]
+d2[0, :, 0] = [0,255,0,100]
+d2[0, 0, :] = [0,0,255,100]
+
 v = gl.GLVolumeItem(d2)
 v.translate(-50,-50,-100)
 w.addItem(v)
 
+ax = gl.GLAxisItem()
+w.addItem(ax)
 
 ## Start Qt event loop unless running in interactive mode.
 if sys.flags.interactive != 1:
diff --git a/functions.py b/functions.py
index 345b39d7b78caa9a43f88460d47cf33a483cceba..9b41da4c8fcd3a3dd9ad9130cdf7267a16a95661 100644
--- a/functions.py
+++ b/functions.py
@@ -316,6 +316,13 @@ def intColor(index, hues=9, values=1, maxValue=255, minValue=150, maxHue=360, mi
     c.setAlpha(alpha)
     return c
 
+def glColor(*args, **kargs):
+    """
+    Convert a color to OpenGL color format (r,g,b,a) floats 0.0-1.0
+    Accepts same arguments as :func:`mkColor <pyqtgraph.mkColor>`.
+    """
+    c = mkColor(*args, **kargs)
+    return (c.red()/255., c.green()/255., c.blue()/255., c.alpha()/255.)
 
 def affineSlice(data, shape, origin, vectors, axes, **kargs):
     """
diff --git a/opengl/GLGraphicsItem.py b/opengl/GLGraphicsItem.py
index da6a37c6edf204abcef9702fa13038b201202738..96cc67637622231e562d7eb4f3906e722bbfc584 100644
--- a/opengl/GLGraphicsItem.py
+++ b/opengl/GLGraphicsItem.py
@@ -53,6 +53,10 @@ class GLGraphicsItem(QtCore.QObject):
         self.__transform = tr
         self.update()
         
+    def resetTransform(self):
+        self.__transform.setToIdentity()
+        self.update()
+        
     def applyTransform(self, tr, local):
         """
         Multiply this object's transform by *tr*. 
diff --git a/opengl/GLViewWidget.py b/opengl/GLViewWidget.py
index 15077b74da668ec0113f15dd9a83e1545673869d..6aeeabfefa81cd73e4dc0fd9b71660723dae8c5c 100644
--- a/opengl/GLViewWidget.py
+++ b/opengl/GLViewWidget.py
@@ -14,6 +14,8 @@ class GLViewWidget(QtOpenGL.QGLWidget):
     """
     def __init__(self, parent=None):
         QtOpenGL.QGLWidget.__init__(self, parent)
+        self.setFocusPolicy(QtCore.Qt.ClickFocus)
+        
         self.opts = {
             'center': Vector(0,0,0),  ## will always appear at the center of the widget
             'distance': 10.0,         ## distance of camera from center
@@ -23,6 +25,10 @@ class GLViewWidget(QtOpenGL.QGLWidget):
                                       ## (rotation around z-axis 0 points along x-axis)
         }
         self.items = []
+        self.noRepeatKeys = [QtCore.Qt.Key_Right, QtCore.Qt.Key_Left, QtCore.Qt.Key_Up, QtCore.Qt.Key_Down, QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown]
+        self.keysPressed = {}
+        self.keyTimer = QtCore.QTimer()
+        self.keyTimer.timeout.connect(self.evalKeyState)
 
     def addItem(self, item):
         self.items.append(item)
@@ -31,12 +37,12 @@ class GLViewWidget(QtOpenGL.QGLWidget):
             item.initializeGL()
         item._setView(self)
         #print "set view", item, self, item.view()
-        self.updateGL()
+        self.update()
         
     def removeItem(self, item):
         self.items.remove(item)
         item._setView(None)
-        self.updateGL()
+        self.update()
         
         
     def initializeGL(self):
@@ -45,7 +51,7 @@ class GLViewWidget(QtOpenGL.QGLWidget):
         
     def resizeGL(self, w, h):
         glViewport(0, 0, w, h)
-        #self.updateGL()
+        #self.update()
 
     def setProjection(self):
         ## Create the projection matrix
@@ -59,7 +65,7 @@ class GLViewWidget(QtOpenGL.QGLWidget):
         nearClip = dist * 0.001
         farClip = dist * 1000.
         
-        r = nearClip * np.tan(fov)
+        r = nearClip * np.tan(fov * 0.5 * np.pi / 180.)
         t = r * h / w
         glFrustum( -r, r, -t, t, nearClip, farClip)
         
@@ -70,7 +76,7 @@ class GLViewWidget(QtOpenGL.QGLWidget):
         glRotatef(self.opts['elevation']-90, 1, 0, 0)
         glRotatef(self.opts['azimuth']+90, 0, 0, -1)
         center = self.opts['center']
-        glTranslatef(center.x(), center.y(), center.z())
+        glTranslatef(-center.x(), -center.y(), -center.z())
         
         
     def paintGL(self):
@@ -90,7 +96,15 @@ class GLViewWidget(QtOpenGL.QGLWidget):
             if not i.visible():
                 continue
             if i is item:
-                i.paint()
+                try:
+                    glPushAttrib(GL_ALL_ATTRIB_BITS)
+                    i.paint()
+                except:
+                    import sys
+                    sys.excepthook(*sys.exc_info())
+                    print "Error while drawing item", i
+                finally:
+                    glPopAttrib(GL_ALL_ATTRIB_BITS)
             else:
                 glMatrixMode(GL_MODELVIEW)
                 glPushMatrix()
@@ -117,23 +131,110 @@ class GLViewWidget(QtOpenGL.QGLWidget):
         
         return pos
 
+    def orbit(self, azim, elev):
+        """Orbits the camera around the center position. *azim* and *elev* are given in degrees."""
+        self.opts['azimuth'] += azim
+        self.opts['elevation'] = np.clip(self.opts['elevation'] + elev, -90, 90)
+        self.update()
+        
+    def pan(self, dx, dy, dz, relative=False):
+        """
+        Moves the center (look-at) position while holding the camera in place. 
+        
+        If relative=True, then the coordinates are interpreted such that x
+        if in the global xy plane and points to the right side of the view, y is
+        in the global xy plane and orthogonal to x, and z points in the global z
+        direction. Distances are scaled roughly such that a value of 1.0 moves
+        by one pixel on screen.
+        
+        """
+        if not relative:
+            self.opts['center'] += QtGui.QVector3D(dx, dy, dz)
+        else:
+            cPos = self.cameraPosition()
+            cVec = self.opts['center'] - cPos
+            dist = cVec.length()  ## distance from camera to center
+            xDist = dist * 2. * np.tan(0.5 * self.opts['fov'] * np.pi / 180.)  ## approx. width of view at distance of center point
+            xScale = xDist / self.width()
+            zVec = QtGui.QVector3D(0,0,1)
+            xVec = QtGui.QVector3D.crossProduct(zVec, cVec).normalized()
+            yVec = QtGui.QVector3D.crossProduct(xVec, zVec).normalized()
+            self.opts['center'] = self.opts['center'] + xVec * xScale * dx + yVec * xScale * dy + zVec * xScale * dz
+        self.update()
+        
+    def pixelSize(self, pos):
+        """
+        Return the approximate size of a screen pixel at the location pos
+        
+        """
+        cam = self.cameraPosition()
+        dist = (pos-cam).length()
+        xDist = dist * 2. * np.tan(0.5 * self.opts['fov'] * np.pi / 180.)
+        return xDist / self.width()
+        
     def mousePressEvent(self, ev):
         self.mousePos = ev.pos()
         
     def mouseMoveEvent(self, ev):
         diff = ev.pos() - self.mousePos
         self.mousePos = ev.pos()
-        self.opts['azimuth'] -= diff.x()
-        self.opts['elevation'] = np.clip(self.opts['elevation'] + diff.y(), -90, 90)
-        #print self.opts['azimuth'], self.opts['elevation']
-        self.updateGL()
+        
+        if ev.buttons() == QtCore.Qt.LeftButton:
+            self.orbit(-diff.x(), diff.y())
+            #print self.opts['azimuth'], self.opts['elevation']
+        elif ev.buttons() == QtCore.Qt.MidButton:
+            if (ev.modifiers() & QtCore.Qt.ControlModifier):
+                self.pan(diff.x(), 0, diff.y(), relative=True)
+            else:
+                self.pan(diff.x(), diff.y(), 0, relative=True)
         
     def mouseReleaseEvent(self, ev):
         pass
         
     def wheelEvent(self, ev):
-        self.opts['distance'] *= 0.999**ev.delta()
-        self.updateGL()
-
+        if (ev.modifiers() & QtCore.Qt.ControlModifier):
+            self.opts['fov'] *= 0.999**ev.delta()
+        else:
+            self.opts['distance'] *= 0.999**ev.delta()
+        self.update()
 
+    def keyPressEvent(self, ev):
+        if ev.key() in self.noRepeatKeys:
+            ev.accept()
+            if ev.isAutoRepeat():
+                return
+            self.keysPressed[ev.key()] = 1
+            self.evalKeyState()
+      
+    def keyReleaseEvent(self, ev):
+        if ev.key() in self.noRepeatKeys:
+            ev.accept()
+            if ev.isAutoRepeat():
+                return
+            try:
+                del self.keysPressed[ev.key()]
+            except:
+                self.keysPressed = {}
+            self.evalKeyState()
+        
+    def evalKeyState(self):
+        speed = 2.0
+        if len(self.keysPressed) > 0:
+            for key in self.keysPressed:
+                if key == QtCore.Qt.Key_Right:
+                    self.orbit(azim=-speed, elev=0)
+                elif key == QtCore.Qt.Key_Left:
+                    self.orbit(azim=speed, elev=0)
+                elif key == QtCore.Qt.Key_Up:
+                    self.orbit(azim=0, elev=-speed)
+                elif key == QtCore.Qt.Key_Down:
+                    self.orbit(azim=0, elev=speed)
+                elif key == QtCore.Qt.Key_PageUp:
+                    pass
+                elif key == QtCore.Qt.Key_PageDown:
+                    pass
+                self.keyTimer.start(16)
+        else:
+            self.keyTimer.stop()
 
+        
\ No newline at end of file
diff --git a/opengl/items/GLVolumeItem.py b/opengl/items/GLVolumeItem.py
index 01d8ae48db001da47d0183e7fb4f83492dd2f398..0a3a421b69ac2a47e3f36030bb40e76c7ae87686 100644
--- a/opengl/items/GLVolumeItem.py
+++ b/opengl/items/GLVolumeItem.py
@@ -71,6 +71,7 @@ class GLVolumeItem(GLGraphicsItem):
         view = self.view()
         center = QtGui.QVector3D(*[x/2. for x in self.data.shape[:3]])
         cam = self.mapFromParent(view.cameraPosition()) - center
+        #print "center", center, "cam", view.cameraPosition(), self.mapFromParent(view.cameraPosition()), "diff", cam
         cam = np.array([cam.x(), cam.y(), cam.z()])
         ax = np.argmax(abs(cam))
         d = 1 if cam[ax] > 0 else -1