diff --git a/CHANGELOG b/CHANGELOG
index f2c01af74714cad79923a0634afd9a2300e89144..024abc52910d58f94ab07929c9563ae7e0dbf8fd 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -34,6 +34,7 @@ pyqtgraph-0.9.9  [unreleased]
     - MultiPlotWidget now has setMinimumPlotHeight method and displays scroll bar
       when plots do not fit inside the widget.
     - Added BarGraphItem.shape() to allow better mouse interaction
+    - Added MeshData.cylinder
 
   Bugfixes:
     - PlotCurveItem now has correct clicking behavior--clicks within a few px
diff --git a/examples/GLMeshItem.py b/examples/GLMeshItem.py
index 5ef8eb51aad482f7b68704d9020c13a4cd68e1fa..f017f19bd84733590eecf84c5626a0b43ce9d689 100644
--- a/examples/GLMeshItem.py
+++ b/examples/GLMeshItem.py
@@ -67,7 +67,7 @@ w.addItem(m2)
 
 
 ## Example 3:
-## icosahedron
+## sphere
 
 md = gl.MeshData.sphere(rows=10, cols=20)
 #colors = np.random.random(size=(md.faceCount(), 4))
@@ -79,7 +79,7 @@ colors[:,1] = np.linspace(0, 1, colors.shape[0])
 md.setFaceColors(colors)
 m3 = gl.GLMeshItem(meshdata=md, smooth=False)#, shader='balloon')
 
-#m3.translate(-5, -5, 0)
+m3.translate(-5, -5, 0)
 w.addItem(m3)
 
 
@@ -91,49 +91,68 @@ m4 = gl.GLMeshItem(meshdata=md, smooth=False, drawFaces=False, drawEdges=True, e
 m4.translate(0,10,0)
 w.addItem(m4)
 
+# Example 5:
+# cylinder
+md = gl.MeshData.cylinder(rows=10, cols=20, radius=[1., 2.0], length=5.)
+md2 = gl.MeshData.cylinder(rows=10, cols=20, radius=[2., 0.5], length=10.)
+colors = np.ones((md.faceCount(), 4), dtype=float)
+colors[::2,0] = 0
+colors[:,1] = np.linspace(0, 1, colors.shape[0])
+md.setFaceColors(colors)
+m5 = gl.GLMeshItem(meshdata=md, smooth=True, drawEdges=True, edgeColor=(1,0,0,1), shader='balloon')
+colors = np.ones((md.faceCount(), 4), dtype=float)
+colors[::2,0] = 0
+colors[:,1] = np.linspace(0, 1, colors.shape[0])
+md2.setFaceColors(colors)
+m6 = gl.GLMeshItem(meshdata=md2, smooth=True, drawEdges=False, shader='balloon')
+m6.translate(0,0,7.5)
 
+m6.rotate(0., 0, 1, 1)
+#m5.translate(-3,3,0)
+w.addItem(m5)
+w.addItem(m6)
 
 
 
 
-#def psi(i, j, k, offset=(25, 25, 50)):
-    #x = i-offset[0]
-    #y = j-offset[1]
-    #z = k-offset[2]
-    #th = np.arctan2(z, (x**2+y**2)**0.5)
-    #phi = np.arctan2(y, x)
-    #r = (x**2 + y**2 + z **2)**0.5
-    #a0 = 1
-    ##ps = (1./81.) * (2./np.pi)**0.5 * (1./a0)**(3/2) * (6 - r/a0) * (r/a0) * np.exp(-r/(3*a0)) * np.cos(th)
-    #ps = (1./81.) * 1./(6.*np.pi)**0.5 * (1./a0)**(3/2) * (r/a0)**2 * np.exp(-r/(3*a0)) * (3 * np.cos(th)**2 - 1)
+def psi(i, j, k, offset=(25, 25, 50)):
+    x = i-offset[0]
+    y = j-offset[1]
+    z = k-offset[2]
+    th = np.arctan2(z, (x**2+y**2)**0.5)
+    phi = np.arctan2(y, x)
+    r = (x**2 + y**2 + z **2)**0.5
+    a0 = 1
+    #ps = (1./81.) * (2./np.pi)**0.5 * (1./a0)**(3/2) * (6 - r/a0) * (r/a0) * np.exp(-r/(3*a0)) * np.cos(th)
+    ps = (1./81.) * 1./(6.*np.pi)**0.5 * (1./a0)**(3/2) * (r/a0)**2 * np.exp(-r/(3*a0)) * (3 * np.cos(th)**2 - 1)
     
-    #return ps
+    return ps
     
-    ##return ((1./81.) * (1./np.pi)**0.5 * (1./a0)**(3/2) * (r/a0)**2 * (r/a0) * np.exp(-r/(3*a0)) * np.sin(th) * np.cos(th) * np.exp(2 * 1j * phi))**2 
-
-
-#print("Generating scalar field..")
-#data = np.abs(np.fromfunction(psi, (50,50,100)))
-
-
-##data = np.fromfunction(lambda i,j,k: np.sin(0.2*((i-25)**2+(j-15)**2+k**2)**0.5), (50,50,50)); 
-#print("Generating isosurface..")
-#verts = pg.isosurface(data, data.max()/4.)
-
-#md = gl.MeshData.MeshData(vertexes=verts)
-
-#colors = np.ones((md.vertexes(indexed='faces').shape[0], 4), dtype=float)
-#colors[:,3] = 0.3
-#colors[:,2] = np.linspace(0, 1, colors.shape[0])
-#m1 = gl.GLMeshItem(meshdata=md, color=colors, smooth=False)
-
-#w.addItem(m1)
-#m1.translate(-25, -25, -20)
-
-#m2 = gl.GLMeshItem(vertexes=verts, color=colors, smooth=True)
-
-#w.addItem(m2)
-#m2.translate(-25, -25, -50)
+    #return ((1./81.) * (1./np.pi)**0.5 * (1./a0)**(3/2) * (r/a0)**2 * (r/a0) * np.exp(-r/(3*a0)) * np.sin(th) * np.cos(th) * np.exp(2 * 1j * phi))**2 
+
+
+print("Generating scalar field..")
+data = np.abs(np.fromfunction(psi, (50,50,100)))
+
+
+#data = np.fromfunction(lambda i,j,k: np.sin(0.2*((i-25)**2+(j-15)**2+k**2)**0.5), (50,50,50)); 
+# print("Generating isosurface..")
+# verts = pg.isosurface(data, data.max()/4.)
+# print dir(gl.MeshData)
+# md = gl.GLMeshItem(vertexes=verts)
+# 
+# colors = np.ones((md.vertexes(indexed='faces').shape[0], 4), dtype=float)
+# colors[:,3] = 0.3
+# colors[:,2] = np.linspace(0, 1, colors.shape[0])
+# m1 = gl.GLMeshItem(meshdata=md, color=colors, smooth=False)
+# 
+# w.addItem(m1)
+# m1.translate(-25, -25, -20)
+# 
+# m2 = gl.GLMeshItem(vertexes=verts, color=colors, smooth=True)
+# 
+# w.addItem(m2)
+# m2.translate(-25, -25, -50)
     
 
 
diff --git a/pyqtgraph/opengl/MeshData.py b/pyqtgraph/opengl/MeshData.py
index e6888c16b811e606cd32338eb9dd7fe28549b23c..ae0fa4ca9cfe17915eff0f765cfcd8f43e767069 100644
--- a/pyqtgraph/opengl/MeshData.py
+++ b/pyqtgraph/opengl/MeshData.py
@@ -1,5 +1,5 @@
-from ..Qt import QtGui
-from .. import functions as fn
+from pyqtgraph.Qt import QtGui
+import pyqtgraph.functions as fn
 import numpy as np
 
 class MeshData(object):
@@ -518,4 +518,36 @@ class MeshData(object):
         
         return MeshData(vertexes=verts, faces=faces)
         
+    @staticmethod
+    def cylinder(rows, cols, radius=[1.0, 1.0], length=1.0, offset=False, ends=False):
+        """
+        Return a MeshData instance with vertexes and faces computed
+        for a cylindrical surface.
+        The cylinder may be tapered with different radii at each end (truncated cone)
+        ends are open if ends = False
+        No closed ends implemented yet...
+        The easiest way may be to add a vertex at the top and bottom in the center of the face?
+        """
+        verts = np.empty((rows+1, cols, 3), dtype=float)
+        if isinstance(radius, int):
+            radius = [radius, radius] # convert to list
+        ## compute vertexes
+        th = ((np.arange(cols) * 2 * np.pi / cols).reshape(1, cols)) # angle around
+        r = (np.linspace(radius[0],radius[1],num=rows+1, endpoint=True)).reshape(rows+1, 1) # radius as a function of z
+        verts[...,2] = np.linspace(-length/2.0, length/2.0, num=rows+1, endpoint=True).reshape(rows+1, 1) # z
+        if offset:
+            th = th + ((np.pi / cols) * np.arange(rows+1).reshape(rows+1,1))  ## rotate each row by 1/2 column
+        verts[...,0] = r * np.cos(th) # x = r cos(th)
+        verts[...,1] = r * np.sin(th) # y = r sin(th)
+        verts = verts.reshape((rows+1)*cols, 3) # just reshape: no redundant vertices...
+        ## compute faces
+        faces = np.empty((rows*cols*2, 3), dtype=np.uint)
+        rowtemplate1 = ((np.arange(cols).reshape(cols, 1) + np.array([[0, 1, 0]])) % cols) + np.array([[0, 0, cols]])
+        rowtemplate2 = ((np.arange(cols).reshape(cols, 1) + np.array([[0, 1, 1]])) % cols) + np.array([[cols, 0, cols]])
+        for row in range(rows):
+            start = row * cols * 2 
+            faces[start:start+cols] = rowtemplate1 + row * cols
+            faces[start+cols:start+(cols*2)] = rowtemplate2 + row * cols
+        
+        return MeshData(vertexes=verts, faces=faces)
         
\ No newline at end of file