Fixed up MeshData and GLMeshItem classes for surface display
This commit is contained in:
parent
f6da6e2fd0
commit
d2d812c86e
@ -1,3 +1,5 @@
|
||||
from pyqtgraph.Qt import QtGui
|
||||
|
||||
class MeshData(object):
|
||||
"""
|
||||
Class for storing 3D mesh data. May contain:
|
||||
@ -9,15 +11,16 @@ class MeshData(object):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.vertexes = []
|
||||
self.edges = None
|
||||
self.faces = []
|
||||
self.vertexFaces = None ## maps vertex ID to a list of face IDs
|
||||
self.vertexNormals = None
|
||||
self.faceNormals = None
|
||||
self.vertexColors = None
|
||||
self.edgeColors = None
|
||||
self.faceColors = None
|
||||
self._vertexes = []
|
||||
self._edges = None
|
||||
self._faces = []
|
||||
self._vertexFaces = None ## maps vertex ID to a list of face IDs
|
||||
self._vertexNormals = None
|
||||
self._faceNormals = None
|
||||
self._vertexColors = None
|
||||
self._edgeColors = None
|
||||
self._faceColors = None
|
||||
self._meshColor = (1, 1, 1, 0.1) # default color to use if no face/edge/vertex colors are given
|
||||
|
||||
def setFaces(self, faces, vertexes=None):
|
||||
"""
|
||||
@ -30,84 +33,111 @@ class MeshData(object):
|
||||
"""
|
||||
|
||||
if vertexes is None:
|
||||
self._setUnindexedFaces(self, faces)
|
||||
self._setUnindexedFaces(faces)
|
||||
else:
|
||||
self._setIndexedFaces(self, faces)
|
||||
self._setIndexedFaces(faces, vertexes)
|
||||
|
||||
|
||||
def _setUnindexedFaces(self, faces):
|
||||
verts = {}
|
||||
self.faces = []
|
||||
self.vertexes = []
|
||||
self.vertexFaces = []
|
||||
self.faceNormals = None
|
||||
self.vertexNormals = None
|
||||
self._faces = []
|
||||
self._vertexes = []
|
||||
self._vertexFaces = []
|
||||
self._faceNormals = None
|
||||
self._vertexNormals = None
|
||||
for face in faces:
|
||||
inds = []
|
||||
for pt in face:
|
||||
pt2 = tuple([int(x*1e14) for x in pt]) ## quantize to be sure that nearly-identical points will be merged
|
||||
pt2 = tuple([round(x*1e14) for x in pt]) ## quantize to be sure that nearly-identical points will be merged
|
||||
index = verts.get(pt2, None)
|
||||
if index is None:
|
||||
self.vertexes.append(tuple(pt))
|
||||
self.vertexFaces.append([])
|
||||
index = len(self.vertexes)-1
|
||||
self._vertexes.append(QtGui.QVector3D(*pt))
|
||||
self._vertexFaces.append([])
|
||||
index = len(self._vertexes)-1
|
||||
verts[pt2] = index
|
||||
self.vertexFaces[index].append(face)
|
||||
self._vertexFaces[index].append(len(self._faces))
|
||||
inds.append(index)
|
||||
self.faces.append(tuple(inds))
|
||||
self._faces.append(tuple(inds))
|
||||
|
||||
def _setIndexedFaces(self, faces, vertexes):
|
||||
self.vertexes = vertexes
|
||||
self.faces = faces
|
||||
self.edges = None
|
||||
self.vertexFaces = None
|
||||
self.faceNormals = None
|
||||
self.vertexNormals = None
|
||||
self._vertexes = [QtGui.QVector3D(*v) for v in vertexes]
|
||||
self._faces = faces
|
||||
self._edges = None
|
||||
self._vertexFaces = None
|
||||
self._faceNormals = None
|
||||
self._vertexNormals = None
|
||||
|
||||
def getVertexFaces(self):
|
||||
def vertexFaces(self):
|
||||
"""
|
||||
Return list mapping each vertex index to a list of face indexes that use the vertex.
|
||||
"""
|
||||
if self.vertexFaces is None:
|
||||
self.vertexFaces = [[]] * len(self.vertexes)
|
||||
for i, face in enumerate(self.faces):
|
||||
if self._vertexFaces is None:
|
||||
self._vertexFaces = [[]] * len(self._vertexes)
|
||||
for i, face in enumerate(self._faces):
|
||||
for ind in face:
|
||||
if len(self.vertexFaces[ind]) == 0:
|
||||
self.vertexFaces[ind] = [] ## need a unique/empty list to fill
|
||||
self.vertexFaces[ind].append(i)
|
||||
return self.vertexFaces
|
||||
if len(self._vertexFaces[ind]) == 0:
|
||||
self._vertexFaces[ind] = [] ## need a unique/empty list to fill
|
||||
self._vertexFaces[ind].append(i)
|
||||
return self._vertexFaces
|
||||
|
||||
def __iter__(self):
|
||||
"""Iterate over all faces, yielding a list of three tuples [(position, normal, color), ...] for each face."""
|
||||
vnorms = self.vertexNormals()
|
||||
vcolors = self.vertexColors()
|
||||
for i in range(len(self._faces)):
|
||||
face = []
|
||||
for j in [0,1,2]:
|
||||
vind = self._faces[i][j]
|
||||
pos = self._vertexes[vind]
|
||||
norm = vnorms[vind]
|
||||
if vcolors is None:
|
||||
color = self._meshColor
|
||||
else:
|
||||
color = vcolors[vind]
|
||||
face.append((pos, norm, color))
|
||||
yield face
|
||||
|
||||
|
||||
def getFaceNormals(self):
|
||||
def faceNormals(self):
|
||||
"""
|
||||
Computes and stores normal of each face.
|
||||
"""
|
||||
if self.faceNormals is None:
|
||||
self.faceNormals = []
|
||||
for i, face in enumerate(self.faces):
|
||||
if self._faceNormals is None:
|
||||
self._faceNormals = []
|
||||
for i, face in enumerate(self._faces):
|
||||
## compute face normal
|
||||
pts = [QtGui.QVector3D(*self.vertexes[vind]) for vind in face]
|
||||
norm = QtGui.QVector3D.crossProduct(pts[1]-pts[0], pts[2]-pts[0])
|
||||
self.faceNormals.append(norm)
|
||||
return self.faceNormals
|
||||
pts = [self._vertexes[vind] for vind in face]
|
||||
norm = QtGui.QVector3D.crossProduct(pts[1]-pts[0], pts[2]-pts[0]).normalized()
|
||||
self._faceNormals.append(norm)
|
||||
return self._faceNormals
|
||||
|
||||
def getVertexNormals(self):
|
||||
def vertexNormals(self):
|
||||
"""
|
||||
Assigns each vertex the average of its connected face normals.
|
||||
If face normals have not been computed yet, then generateFaceNormals will be called.
|
||||
"""
|
||||
if self.vertexNormals is None:
|
||||
faceNorms = self.getFaceNormals()
|
||||
vertFaces = self.getVertexFaces()
|
||||
self.vertexNormals = []
|
||||
for vindex in xrange(len(self.vertexes)):
|
||||
if self._vertexNormals is None:
|
||||
faceNorms = self.faceNormals()
|
||||
vertFaces = self.vertexFaces()
|
||||
self._vertexNormals = []
|
||||
for vindex in xrange(len(self._vertexes)):
|
||||
#print vertFaces[vindex]
|
||||
norms = [faceNorms[findex] for findex in vertFaces[vindex]]
|
||||
if len(norms) == 0:
|
||||
norm = QtGui.QVector3D()
|
||||
else:
|
||||
norm = reduce(QtGui.QVector3D.__add__, facenorms) / float(len(norms))
|
||||
self.vertexNormals.append(norm)
|
||||
return self.vertexNormals
|
||||
for fn in norms:
|
||||
norm += fn
|
||||
norm.normalize()
|
||||
self._vertexNormals.append(norm)
|
||||
return self._vertexNormals
|
||||
|
||||
def vertexColors(self):
|
||||
return self._vertexColors
|
||||
|
||||
def faceColors(self):
|
||||
return self._faceColors
|
||||
|
||||
def edgeColors(self):
|
||||
return self._edgeColors
|
||||
|
||||
def reverseNormals(self):
|
||||
"""
|
||||
|
@ -1,5 +1,6 @@
|
||||
from OpenGL.GL import *
|
||||
from .. GLGraphicsItem import GLGraphicsItem
|
||||
from .. MeshData import MeshData
|
||||
from pyqtgraph.Qt import QtGui
|
||||
import pyqtgraph as pg
|
||||
from .. import shaders
|
||||
@ -10,33 +11,20 @@ import numpy as np
|
||||
__all__ = ['GLMeshItem']
|
||||
|
||||
class GLMeshItem(GLGraphicsItem):
|
||||
def __init__(self, faces):
|
||||
self.faces = faces
|
||||
self.normals, self.faceNormals = pg.meshNormals(faces)
|
||||
"""
|
||||
Displays a 3D triangle mesh.
|
||||
|
||||
"""
|
||||
def __init__(self, faces, vertexes=None):
|
||||
|
||||
"""
|
||||
See MeshData for initialization arguments.
|
||||
"""
|
||||
self.data = MeshData()
|
||||
self.data.setFaces(faces, vertexes)
|
||||
GLGraphicsItem.__init__(self)
|
||||
|
||||
def initializeGL(self):
|
||||
|
||||
#balloonVertexShader = shaders.compileShader("""
|
||||
#varying vec3 normal;
|
||||
#void main() {
|
||||
#normal = normalize(gl_NormalMatrix * gl_Normal);
|
||||
#//vec4 color = normal;
|
||||
#//normal.w = min(color.w + 2.0 * color.w * pow(normal.x*normal.x + normal.y*normal.y, 2.0), 1.0);
|
||||
#gl_FrontColor = gl_Color;
|
||||
#gl_BackColor = gl_Color;
|
||||
#gl_Position = ftransform();
|
||||
#}""", GL_VERTEX_SHADER)
|
||||
#balloonFragmentShader = shaders.compileShader("""
|
||||
#varying vec3 normal;
|
||||
#void main() {
|
||||
#vec4 color = gl_Color;
|
||||
#color.w = min(color.w + 2.0 * color.w * pow(normal.x*normal.x + normal.y*normal.y, 5.0), 1.0);
|
||||
#gl_FragColor = color;
|
||||
#}""", GL_FRAGMENT_SHADER)
|
||||
#self.shader = shaders.compileProgram(balloonVertexShader, balloonFragmentShader)
|
||||
|
||||
self.shader = shaders.getShader('balloon')
|
||||
|
||||
l = glGenLists(1)
|
||||
@ -51,39 +39,33 @@ class GLMeshItem(GLGraphicsItem):
|
||||
glDisable( GL_DEPTH_TEST )
|
||||
glColor4f(1, 1, 1, .1)
|
||||
glBegin( GL_TRIANGLES )
|
||||
for i, f in enumerate(self.faces):
|
||||
pts = [QtGui.QVector3D(*x) for x in f]
|
||||
if pts[0] is None:
|
||||
print f
|
||||
continue
|
||||
#norm = QtGui.QVector3D.crossProduct(pts[1]-pts[0], pts[2]-pts[0])
|
||||
for j in [0,1,2]:
|
||||
norm = self.normals[self.faceNormals[i][j]]
|
||||
for face in self.data:
|
||||
for (pos, norm, color) in face:
|
||||
glColor4f(*color)
|
||||
glNormal3f(norm.x(), norm.y(), norm.z())
|
||||
glVertex3f(pos.x(), pos.y(), pos.z())
|
||||
glEnd()
|
||||
glEndList()
|
||||
|
||||
|
||||
#l = glGenLists(1)
|
||||
#self.meshList = l
|
||||
#glNewList(l, GL_COMPILE)
|
||||
#glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
||||
#glEnable( GL_BLEND )
|
||||
#glEnable( GL_ALPHA_TEST )
|
||||
##glAlphaFunc( GL_ALWAYS,0.5 )
|
||||
#glEnable( GL_POINT_SMOOTH )
|
||||
#glEnable( GL_DEPTH_TEST )
|
||||
#glColor4f(1, 1, 1, .3)
|
||||
#glBegin( GL_LINES )
|
||||
#for f in self.faces:
|
||||
#for i in [0,1,2]:
|
||||
#j = (i+1) % 3
|
||||
glVertex3f(*f[j])
|
||||
glEnd()
|
||||
glEndList()
|
||||
|
||||
|
||||
l = glGenLists(1)
|
||||
self.meshList = l
|
||||
glNewList(l, GL_COMPILE)
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
||||
glEnable( GL_BLEND )
|
||||
glEnable( GL_ALPHA_TEST )
|
||||
#glAlphaFunc( GL_ALWAYS,0.5 )
|
||||
glEnable( GL_POINT_SMOOTH )
|
||||
glEnable( GL_DEPTH_TEST )
|
||||
glColor4f(1, 1, 1, .3)
|
||||
glBegin( GL_LINES )
|
||||
for f in self.faces:
|
||||
for i in [0,1,2]:
|
||||
j = (i+1) % 3
|
||||
glVertex3f(*f[i])
|
||||
glVertex3f(*f[j])
|
||||
glEnd()
|
||||
glEndList()
|
||||
#glVertex3f(*f[i])
|
||||
#glVertex3f(*f[j])
|
||||
#glEnd()
|
||||
#glEndList()
|
||||
|
||||
|
||||
def paint(self):
|
||||
|
Loading…
Reference in New Issue
Block a user