If you're new to Python
and VPython: Introduction

A VPython tutorial

Pictures of 3D objects

What's new in VPython 6

VPython web site
VPython license
Python web site
Math module (sqrt etc.)
Numpy module (arrays)


This is documentation for Classic VPython (VPython 6), which continues to be available but is no longer supported. See vpython.org for information on installing VPython 7 or using GlowScript VPython. Documentation is available at glowscript.org by clicking Help.

The "faces" primitive takes a list of triangles (position, color, and normal for each vertex). This is useful for writing routines in Python to import 3D models made with other 3D modeling tools. You would still need to do lots of calculations of normals and so on, but you would not need to do C coding to import an arbitrary model file.

The faces object is an array primitive (like curve, convex, etc), so you have to use a frame to move it around. It consists of a set of one-sided triangles with user-specified vertices, colors, and normals. The pos, color, and normal attributes look like this:

pos = [ t0v0, t0v1, t0v2,
        t1v0, t1v1, t1v2,
        t2v0, t2v1, t2v2, ... ]

where t0v0 is the position vector (x,y,z) of vertex 0 of triangle 0, t0v1 is vertex 1 of triangle 0, etc. Other faces attributes are red, green, blue, visible, material, frame, and display.

The pos, color, and normal attributes can be specified either as Python lists or as numpy arrays. In either case, these attributes are stored as numpy arrays, which makes possible fast manipulations of these attributes. For examples of the use of numpy arrays, see the documentation of the curve object, whose pos attribute is a numpy array.

Creating a faces object in terms of triangles and normals can be very tedious. A convenient way to create a faces object is to create an extrusion or text object and then use the create_faces() function, as described in the documentation for extrusion and text.

Each face is a one-sided surface. Which side is illuminated is determined by the "winding" order of the face. When you are looking at a face, it is illuminated if the order of the vertices in the pos list goes counter-clockwise. If you need the triangle to be visible from both sides, you must create another triangle with the opposite winding order. If you have made a one-sided faces object named myfaces, you can make all faces be two-sided with myfaces.make_twosided(). This function became available with VPython 5.3.

If you don't specify normals at the vertices, the face is illuminated only by "ambient" light. In order for the main lighting to affect the appearance, you must specify normals to the surface at the vertices. In the simplest case, a normal at a vertex is perpendicular to the face, and adjoining faces have a hard edge where they join. A soft edge can be produced by averaging the normals to the two faces at their common vertices. The brightness of a face is proportional to the cosine of the angle between the normal and the light. If you have created a faces object named myfaces without specifying normals, you can create normals perpendicular to all the faces with myfaces.make_normals().

After creating a faces object named myfaces, myfaces.smooth() will average similar normals at a vertex and make the object look smoother. The smoothing criterion is that normals will be averaged whose directions differ by an angle whose cosine is greater than or equal to 0.95, which means angles less than 18 degrees. You must make sure that all vertices have nonzero normals before using the smooth function; a simple scheme is to use myfaces.make_normals() to make normals perpendicular to all the faces and then use the smooth function to adjust them for improved appearance. You can specify the smoothing criterion. For example, myfaces.smooth(0.7) will average normals whose directions differ by an angle whose cosine is greater than or equal to 0.7 (angles less than 45 degrees).

If you specify different colors at the vertices of one triangular face, VPython interpolates across the face, in which case the face is not all one color. There is a similar interpolation for normals if there are different normals at the vertices, in which case the face is not all one brightness.

You can append additional vertices to an existing faces object with one of the following four forms (assuming the object is named f):

f.append(pos=(x,y,z), normal=(nx,ny,nz))
f.append(pos=(x,y,z), normal=(nx,ny,nz), color=(r,g,b))
f.append(pos=(x,y,z), normal=(nx,ny,nz),
     red=r, green=g, blue=b)

Another convenient way to construct a faces object is to create a list or numpy array of positions, then create the faces object with the pos attribute set to the list or array. Then use make_normals(), make_twosided(), and smooth() to complete the task.

The faces object is intended to help with writing model importers and other new primitives in Python, not for direct manipulation by normal programs. It is considerably lower-level than any of the other objects in VPython (although it is not necessarily any faster, at least right now). It is flexible enough to implement smooth or facet shading, per-vertex coloration, two-sided or one-sided lighting, etc, but all of these calculations must be made by the programmer (when setting up pos, color, normal), although much of this can be done using the make_normals, make_twosided, and smooth functions.

You can specify a material, but currently you can not specify opacity for faces.

See description of Additional Attributes available for all 3D display objects.

For examples of the use of the faces object, see the faces demo programs.