Visualizing vertex positions and normalsΒΆ

This code example shows the following things:

  • How to iterate over all objects in the scene
  • How to iterate over mesh vertices and faces
  • How to access primitive variables such as normals
  • How to process the two storage types “varying” vs “user”/”uniform int XYZfaces[3]”
  • How to draw 3D marker and lines

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.

_images/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)

Previous topic

Creating a hierarchy and using expressions

Next topic

How to use the spacedevice module

This Page