Vizard 7 » Tutorials & Examples » Appearance & texturing » Applying textures » Tutorial: Applying textures
7.5

Tutorial: Applying textures

This tutorial introduces Vizard's OpenGL based texturing system.  The features here are accessible at the OpenGL API level so books and web sites covering OpenGL texturing will be excellent supplements to the information here.

 

If you are already familiar with texturing in OpenGL and are just looking for Vizard's texturing methods, you may be better served by the texture section in the Vizard Reference.  

Applying Textures to 3D Geometry

Key Concepts
Explanation

Textures are images that are "wrapped" on 3D model geometry.  Textures add detail to models without additional polygons, so they are an integral part of realistic looking models.  Also, textures are used to display 2D media, such as paintings and video, within the virtual world.  

 

Say we have a .jpg file of my last tropical vacation and we want to display it in the virtual world.  This is done by loading the .jpg file as a texture into memory and applying it to some 3D geometry.  Without applying, or wrapping, the texture on geometry, the texture will never be seen.  Texture's need a surface to live on.  

# Load texture
pic = viz.addTexture('lake3.jpg')

# Create surface to wrap the texture on
quad = viz.addTexQuad()
quad.setPosition([-.75, 2, 3]) #put quad in view

# Wrap texture on quad
quad.texture(pic)

Notice how the picture fills the entire quad surface.  What if we wanted the picture to only fill a certain amount of the quad?  If we did this, what would the rest of the quad look like?  Read on to explore these mysteries and more!

Texture Coordinates

Key Concepts
Explanation

To control how textures are wrapped on models, models define texture coordinates for their geometry that tells Vizard which part of the texture should go on which part of the geometry.  All 2D textures have a coordinate system with two axes: the S axis which runs along the width of the image, and the T axis which runs along the height.    The texture's coordinates always range from 0 to 1.0 with (0, 0) at the bottom left.  This two value, 0 to 1.0 system gives the geometry an easy way to reference the area of the image they want applied to their surface.  Geometry defines the part of the texture it wants to use with its own S and T texture coordinates.  In 3D modeling programs, the two texture axes are known as S and T.  Modeling software calls the process of wrapping geometry in textures S-T mapping.

Modifying Texture Coordinates

Key Concepts
Explanation

With our TexQuad we created above, its default texture coordinate's placed had (S=0, T=0) at the bottom left of our texquad and (S=1, T=1) at the top right.  This made a direct mapping between the texture's coordinates and the texquad's texture coordinates so the image completely filled the texquad.  We will now change the texture coordinates of the texquad to shrink the texture down so it does not extend to the edges of the texquad.  To do this, nodes have a texmat method.  <node3d>.texmat(transform) multiplies the model's texture coordinates by the given transform.  Thus if we want to shrink the texture on the texquad we would scale up the texquad's texture coordinates.

# Create new texquad
quad2 = viz.addTexQuad()
quad2.setPosition([.75, 2, 3])
quad2.texture(pic)

import vizmat
matrix = vizmat.Transform()
# Scale down texture by scaling up the texquad's texture coordinates
matrix.setScale([1.5,1.5,1])
quad2.texmat(matrix)

Now we have a smaller picture in the lower left quadrant of our new texquad.  The quad's new texture coordinates go from (0, 0) to (1.5, 1.5) and the image is only clearly displayed in the (0, 0) to (1.0, 1.0) texture coordinate range.  Don't worry about the stretched edges, we'll deal with them later.  Right now I am more concerned about centering the picture in the middle of the quad.  This easily done by adding a position offset to the texture coordinates via the same matrix we used to scale them.  

import vizmat
matrix = vizmat.Transform()
# Scale down texture by scaling up the texquad's texture coordinates
matrix.setScale([1.5,1.5,1])
# Move the (0,0) texture coordinate up and to the right by subtracting
matrix.setTrans([-.25,-.25,1])
quad2.texmat(matrix)
 

Conceptually, you can think that subtracting .25 from each texture point moved the (0,0) point up and to the right because all the points that were previously 0 to .25 are now negative.  So (0, 0) - (.25, .25) = (-.25, -.25) and (.25, .25) - (.25, .25) = (0, 0).    

 

Got that? Good. Now lets fix them stretch marks.  

Wrap Modes

Key Concepts
Explanation

A texture's wrap mode tells Vizard what to draw on texture coordinates that are outside of the 0 to 1.0 range.  The default wrap mode, and the mode currently used by our quads is CLAMP.  The CLAMP wrapping mode takes the color of the pixel at the edge of the texture 0 to 1.0 range and fills in the rest of the geometry on that texture coordinate with the color.  This creates the smearing effect you see here.  

 

To avoid the smearing on the top and bottom of the texture, lets set the T axis clamp mode to CLAMP_TO_BORDER.  This causes the border color of the texture to be used outside of the 0 to 1.0 range on the T axis.  Unless defined differently in a modeling program, the border color is black in Vizard.  

# Load texture
pic = viz.addTexture('lake3.jpg')
pic.wrap(viz.WRAP_T, viz.CLAMP_TO_BORDER)

This causes the top and bottom of our texquad to be black.  Notice how it only occurred for the T axis coordinates which are beyond 0 and 1 and the sides are still smeared with color.  We will now set the wrap mode of the S axis to MIRROR.  Hopefully this will make a nice fake of a wider angle picture.

# Load texture
pic = viz.addTexture('lake3.jpg')
pic.wrap(viz.WRAP_T, viz.CLAMP_TO_BORDER)
pic.wrap(viz.WRAP_S, viz.MIRROR)

Not perfect, but it will do.  With the MIRROR clamp mode, texture coordinates outside of 0 to 1.0 repeat the texture in reverse, so coordinate 1.2 uses the texture pixel at .8 and -.2 uses the texture pixel at .2.  

 

Now lets make a wall to hang these pictures on.  

# Make background wall
WALL_SCALE = [10, 3, 1]

wall = viz.addTexQuad()
wall.setPosition( [0, 2, 3] )
wall.zoffset(1) #avoid zfighing, make wall appear behind pictures
wall.setScale( WALL_SCALE )

# Apply nice repeating brick texture
matrix = vizmat.Transform()
matrix.setScale( WALL_SCALE )
wall.texmat( matrix )
bricks = viz.addTexture('brick.jpg')
bricks.wrap(viz.WRAP_T, viz.REPEAT)
bricks.wrap(viz.WRAP_S, viz.REPEAT)
wall.texture(bricks)

Here we scaled the texquad's texture coordinates by the same amount that we scaled its size so that we don't have super-sized bricks.  Then we set the wrap mode to REPEAT to draw the texture over and over outside of the 0 to 1.0 texture coordinate range.

 

For additional examples, check out:

tex_lighting