Visualizing vertex positions and normals

Author: Matthias Baas (mbaas@users.sourceforge.net)
Date: 2004/12/20

This code example shows the following things:

The following script loads a scene and shows the vertices and normals of every mesh in the scene. The vertices are displayed as blue markers and the normals as lines.

shownormals_screenshot.jpg

Here is the script and a demo file (bunny.3ds) containing the Stanford Bunny.

######################################################################
# Visualizing the vertices and normals of a triangle mesh
#
# This script loads a scene and shows the vertices and normals of
# every mesh in the scene.
#
# Invoke the script via the viewer tool:
# $ viewer.py shownormals.py
######################################################################


def showVertices(mesh):
    
"""Draw markers at the vertex positions of a triangle mesh.
    """


    
# Vertices are stored in the local coordinate system of the geometry.
    
# But as we need the coordinates relative to the world coordinate
    
# system we have to obtain the transformation L that transforms from
    
# local to world coordinates.
    
L = mesh.worldtransform

    
# Iterate over the vertices and draw a marker at the global vertex
    
# position L*v.
    
for v in mesh.verts:
        
drawMarker(L*v, size=0.07, color=(0,0,1))


def showNormals(mesh):
    
"""Draw the normals as lines.

    A normal is drawn at every vertex position. The normals may either be
    specified as "varying normal N" or as "user normal N"/"uniform int Nfaces[3]".
    The actual drawing code is in showVaryingNormals() and showUserNormals().
    """


    
# Check if there are normals available in this mesh
    
desc = mesh.findVariable("N")
    
if desc==None:
        
print 'Mesh "%s" has no normals set.'%mesh.name
        
return

    
# Unpack the variable descriptor
    
name, storage_class, type, mult = desc

    
# Are the normals stored as "varying normal N"?
    
if storage_class==VARYING and type==NORMAL and mult==1:
        
showVaryingNormals(mesh)

    
# Or are they stored as "user normal N"?
    
elif storage_class==USER and type==NORMAL and mult==1:
        
# Check if the normal faces are available
        
desc = mesh.findVariable("Nfaces")
        
if desc==None:
            
print 'Mesh "%s" has no normal faces set.'%mesh.name
        
else:
            
name, storage_class, type, mult = desc
            
if storage_class==UNIFORM and type==INT and mult==3:
                
# "N" and "Nfaces" is available and of the right type...
                
showUserNormals(mesh)
            
else:
                
print 'Mesh "%s": Invalid declaration of "Nfaces"'%mesh.name

    
else:
        
print 'Mesh "%s": Invalid declaration of variable "N".'%mesh.name


def showVaryingNormals(mesh):
    
"""Draw normals given as "varying normal N".
    """

    
# Get the world transform to transform the local vertices and normals
    
# into the world coordinate system
    
L = mesh.worldtransform
    
L0 = L*vec3(0)
    
# Obtain the slot carrying the normals
    
N = mesh.geom.slot("N")
    
# Iterate over the faces and draw the vertices and normals
    
for i,j,k in mesh.faces:
        
a = L*mesh.verts[i]
        
b = L*mesh.verts[j]
        
c = L*mesh.verts[k]
        
na = L*N[i]-L0
        
nb = L*N[j]-L0
        
nc = L*N[k]-L0
        
drawLine(a, a+na)
        
drawLine(b, b+nb)
        
drawLine(c, c+nc)


def showUserNormals(mesh):
    
"""Draw normals given as "user normal N"/"uniform int Nfaces[3]".
    """

    
# Get the world transform to transform the local vertices and normals
    
# into the world coordinate system
    
L = mesh.worldtransform
    
L0 = L*vec3(0)
    
# Obtain the slot carrying the normals and the normal faces
    
N = mesh.geom.slot("N")
    
Nfaces = mesh.geom.slot("Nfaces")
    
# Iterate over the faces and normal faces...
    
for face, Nface in zip(mesh.faces, Nfaces):
        
i,j,k = face
        
ni,nj,nk = Nface
        
a = L*mesh.verts[i]
        
b = L*mesh.verts[j]
        
c = L*mesh.verts[k]
        
na = L*N[ni]-L0
        
nb = L*N[nj]-L0
        
nc = L*N[nk]-L0
        
drawLine(a, a+na)
        
drawLine(b, b+nb)
        
drawLine(c, c+nc)

######################################################################

# Load a scene file
load("bunny.3ds")

# Show its contents
listWorld()

# Draw the vertices & normals of every triangle mesh in the scene
for obj in scene.walkWorld():
    
# Check if the object is a triangle mesh
    
if isinstance(obj.geom, TriMeshGeom):
        
# Uncomment the following line to convert the normals from
        
# "user normal" to "varying normal"
#        obj.geom = convMeshAttr(obj.geom, "N")
        
print 'Creating vertex markers for "%s"...'%obj.name
        
showVertices(obj)
        
print 'Creating normal lines for "%s"...'%obj.name
        
showNormals(obj)

Back to the tutorial index