Course Links

Resources

External

In this lab we will practice texture mapping in WebGL. Texture mapping using existing images is an efficient way to make our scenes more realistic. Homework 8 will build on the concepts from this lab.

Note: If you work offline on this lab (not using repl.it) then please read the page on configuraton for local texture files.

Open the code

Fork a copy of the starter code. When you open this file in a web browser and click the link for part 1, you should see a blue rotating cube:

cube

This cube has a Phong material, which is made up of several components, including a "shininess" which can often make objects look more "3D". Notice the direction of the lighting, the size/position of the cube, and the animation aspect to make the cube rotate. The code for this part is in cube.html.

For this lab we will use several texture images, which have already been added to the list of files on the left-hand side of the workspace. In the future, to load additional textures you can simply drag files into this part of the window.

Use one texture

In the first step, we will use one image to texture the cube. Use the code below to change the blue cube to a wooden cube:

var loader = new THREE.TextureLoader();

var woodTexture = loader.load("wood.jpg");
var woodMaterial = new THREE.MeshPhongMaterial( { map: woodTexture } );

// replace cube creation with:
cube = new THREE.Mesh(geometry, woodMaterial);

You might get a warning that the texture is not a "power of 2", meaning that the number of pixels is not a power of 2, which is desirable for texture mapping. We'll ignore this for now; the image should still work.

If the shape shows up as all black, then the texture file hasn't loaded properly. Check the file name for typos, and if you are not working on repl.it read about how to set up a local configuration for texture.

Texture on each face

Next we will create a material for each of the 6 images, and map one to each face. Use the same style of code above for the grass, apple, etc. Then create a list of all these materials:

var materials = [woodMaterial, appleMaterial, wallpaperMaterial, 
      skyMaterial, grassMaterial, stoneMaterial];

// replace cube creation with:
cube = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(materials));

You should get something that looks like this:

cube

Part 2: UV mapping

The remainder of this lab uses the file pyramid.html. To begin, this file contains code for a pyramid geometry similar to that we created in a previous lab. Even though there is a texture applied to the faces, it doesn't show up in the rendering. Because we created this geometry ourselves, it doesn't come with built-in UV coordinates at all the vertices to specify how to map a texture onto each face. We'll have to add that ourselves, and that is your next task.

The goal is to get the apple texture mapped onto each face of the pyramid. Think how this will work, maybe something like the image below. Could you do it in a different way?

cube

We will associate each face with a set of UV coordinates in the texture image. First we must define an array of UV coordinate points we can refer to. (This is a little like the way we create a list of 3D vectors to use as vertices for a geometry, except that the vectors are 2D in this case.) You don't have to come up with all the vectors at once -- you can work one face at a time, adding vectors here as needed when you do the next step below. Similar faces can reuse the same vectors -- for example, all the pyramid sides can use the same three UV coordinate vectors for their corners.

// set up several uv coordinates to repeatedly use below
var uvcoords = [
    // add as many lines as you need here:
    new THREE.Vector2(0, 0),
    new THREE.Vector2(1, 0),
    new THREE.Vector2(0.5, 1),
    new THREE.Vector2(?, ?),
    ...
];

Next you need to define the array of UV coordinate vectors for each face of the pyramid (6 in all, since the square bottom is split into two triangular faces.) For each face, supply an array of three vectors chosen from the UV coordinate vectors you defined in the previous step. (This step is a little like the way we list the vertices for the faces of a geometry, but the syntax differs.) Note that you can repeat the same sequence of UV points for the first four faces, representing the sides of the pyramid. For the bottom you'll have to come up with something else.

// define UV coordinates for corners of each face
pyramidGeom.faceVertexUvs[0] = [
    // write one line for each of the 6 faces:
    [uvcoords[0], uvcoords[1], uvcoords[2]],  // first face UVs
    [uvcoords[?], uvcoords[?], uvcoords[?]],  // second face, etc.
    ...
];

Once you've got something showing on each face, see if you can you adjust the UV coordinates to make it so that the apple is fully visible on every face. (Hint: you may need to think outside the box.) Can you make the bottom of the pyramid look like a complete apple? You will need to match up the UV coordinates of the two faces that make up the bottom.

3D Texture

Once you have determined the UV coordinates for the color texture, adding 3D texture as a bump map is relatively simple. The lab includes a bump map for the apple image that will create an embossed effect, in the file apbump.png. You can add this to the apple material with one line of code:

appleMaterial.bumpMap = loader.load("apbump.png");

This should give an embossed effect. If the embossing seems too dramatic, you can tone it down. Set the bumpScale of the appleMaterial to 0.2.

Finish Up

You do not have to turn this lab in, but make sure everyone has a copy by the end of the lab. Homework 8 will continue the concepts in this lab.

Concept credit: modified from this blog post by Greg Stier.