Home

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)

 
Materials & Textures
material etc

You can specify a material such as wood for any object other than a points object:

sphere(color=color.orange, material=materials.wood)

The materials that are currently available include these:

materials.wood
materials.rough
materials.marble
materials.plastic
materials.earth
materials.diffuse
materials.emissive (looks like it glows)
materials.unshaded (unaffected by lighting)

New as of VPython 5.50:

materials.shiny
materials.chrome
materials.blazed
materials.silver
materials.BlueMarble (earth with clouds)
materials.bricks

The example program material_test.py displays all of these materials. The emissive material is particularly appropriate for simulating the appearance of a light glowing with the specified color. This apparent light has no lighting effect on other objects, but you may wish to place a local_light at the same location, as is done with the swinging light in the example program texture_and_lighting.py. The appearance of the unshaded material is unaffected by lighting and is useful when you want to display an object whose appearance is determined solely by its own attributes.

If you specify scene.material = materials.plastic, all objects created thereafter will by default be plastic unless a different material is specifically assigned.

Materials will work with graphics cards that support Pixel Shader 3.0 ("PS 3.0"). For details, see
http://en.wikipedia.org/wiki/Pixel_shader#Hardware. Some materials may work with graphics cards that support PS 2.0, but other materials may need to be manually disabled; see instructions in the site-settings.py module in the VPython package in your site-packages folder. If the graphics hardware does not support pixel shaders, the material property is ignored. If you think you should be able to use materials but have trouble with their display or performance, we highly recommend upgrading your video card drivers to the latest version.

Some materials such as wood are oriented to the specified axis. For example, a wood box with default axis = (1,0,0) shows tree rings on its yz surfaces and stripes on the other faces. Changing the axis changes which face you see the tree rings on.

Creating your own texture

You can create a texture object and then apply it to the surface of an object. A surface texture is an M by N array of slots containing 1, 2, 3, or 4 numerical values. M and N must be powers of 2 (1, 2, 4, 8, 16, 32, 64, 128, 256, 512, etc.). The numerical values can represent color, luminance (brightness or shades of gray), or opacity.

Here are the possibilities for each slot in the array:

1 value: luminance by default, or specify channels=["opacity"] to represent opacity

2 values: luminance and opacity

3 values: red,green,blue

4 values: red,green,blue,opacity

Here is an example program in which a 4 by 4 by 1 checkerboard texture is created and applied to a box:

from visual import *
checkerboard = ( (0,1,0,1),
                 (1,0,1,0),
                 (0,1,0,1),
                 (1,0,1,0) )
tex = materials.texture(data=checkerboard,
                     mapping="rectangular",
                     interpolate=False)
box(axis=(0,0,1), color=color.cyan, material=tex)

The example above uses a rectangular mapping, which places the texture on two opposing faces of a box, with stripes along the sides. By default, one of the faces is in the (1,0,0) direction, but this can be changed by specifying a different axis for the box, as was done in the example above. A sign mapping is similar to rectangular but is unaffected by the color of the object and appears on only one face of a box (determined by the axis of the box). A spherical mapping wraps around the entire object. In the example program texture_and_lighting.py you can find a creation of a beach ball using spherical mapping.

By default interpolate is True, but to get a sharply defined checkerboard in the example above, it was set to False.

You can save the texture data in a file for later use::

materials.saveTGA("checks", checkerboard)

This saves the checkboard pattern in a file "checks.tga", a targa file which many graphics applications can display. In later programs you can use this data without recreating it:

data = materials.loadTGA("checks")

More generally, any targa file whose width and height are both powers of 2 can be read as data using materials.loadTGA(filename). If the actual file name is "checks.tga" you can give the full file name or just "checks".

One way to create a pattern is to start by creating a numpy array of zeros, then assign values to individual slots:

pattern = zeros((4,8,3)) # 4 by 8 by 3 numpy array of 0's
pattern[0][0] = (1,.5,.7) # assign first rgb triple

Another example

Here is an example of placing a "sign" on one face of a box, consisting of a 2 by 2 by 3 grid of color components:

from visual import *
grid = ( (color.red, (1, 0.7 ,0)),
         ((0, 1, 0.3), color.magenta) )
tgrid = materials.texture(data=grid,
                          mapping="sign",
                          interpolate=False)
box(axis=(0,0,1), material=tgrid)

Making a texture from a photo

A texture can be created from a targa file, and various graphics applications can convert photos in jpeg or other formats to targa files. One tool for doing this is PIL, the Python Imaging Library, which can be downloaded and installed (you can find it with a web search). Here is an example of PIL code which converts a jpeg photo into a targa file which can be used to create a texture for displaying the image, as in the example program stonehenge.py.

from visual import *
import Image # Must install PIL
name = "flower"
width = 128 # must be power of 2
height = 128 # must be power of 2
im = Image.open(name+".jpg")
#print(im.size) # optionally, see size of image
# Optional cropping:
#im = im.crop((x1,y1,x2,y2)) # (0,0) is upper left
im = im.resize((width,height), Image.ANTIALIAS)
materials.saveTGA(name,im)

At a later time you can say data = materials.loadTGA(name) to retrieve the image data from the targa file.

As a convenience, a texture can also be created directly from the PIL image data, like this:

tex = materials.texture(data=im, mapping="sign")

Efficiency issues

Normally you create a data pattern containing values in the range from 0.0 to 1.0, the standard range of color components and opacity in VPython. However, the underlying graphics machinery works with values in the range of 0 to 255, which can be expressed in one 8-bit byte of computer memory. If you are dealing with large textures and time is critical, you should avoid conversions from the range 0-1 to the range 0-255 by constructing the texture data from a numpy array of unsigned 8-bit bytes. An unsigned byte is referred to as ubyte. Here is a simple example:

checkers = array( ( (0,255,0,255),
                    (255,0,255,0),
                    (0,255,0,255),
                    (255,0,255,0) ), ubyte)

The array function converts a sequence of values into a numpy array. In this case the values are 8-bit bytes.

Channels

Data "channels" are a part of the definition of a texture. For the most part, these channels are assigned automatically for you, like this:

1 value: channels=["luminance"] by default, channels=["opacity"] to represent opacity

2 values: channels=["luminance","opacity"]

3 values: channels=["red","green","blue"]

4 values: channels=["red","green","blue","opacity"]

Except for specifying that a pattern represents opacity rather than luminance (brightness, or shade of gray), it isn't necessary to specify channels when constructing a texture because the channel options shown above are currently the only valid sets of channels. However, it is expected that in the future there may be additional channels available, such as glossiness.

mipmap

When an object in the scene is small and far away, there is no need to display its texture in full detail. With the default mipmap=True, VPython prepares a set of smaller textures to use when appropriate. These additional textures take some time to prepare for later use, and required storage space is one-third larger, but they can speed up the rendering of a scene. It should rarely be the case that you would need to set mipmap=False.

Creating your own materials

Creating your own materials (in contrast to creating textures) is technically somewhat challenging. The program materials.py, a component of the Visual module, contains the shader models for wood and other materials, and it also contains instructions on how to build your own materials. Shader models are written in a C-like language, GLSL (OpenGL Shader Language).