Texture Mapping 2¶
Today, we'll learn to how to control our textures.
Plan¶
- Announcements
- Exercise
- Texture Mapping recap
- Textured Barn assignment
Announcements¶
- oops Somehow Sakai dropped the "what are your questions?" from the quiz. Sorry about that.
- Grading Status
- Textured Barn is ready, but we will discuss
Texture Mapping¶
Exercise: Triptych¶
Last time, we ended with texture mapping onto a single plane,
texplane
. Let's kick that up a notch.
Download these and create a triptych of them:
Remember, you will need to:
scp
them from your laptop to your account on the servermv
them into your~/public_html/cs307/texplane
folder- edit the
main.js
to create two more planes. - use the
opendir
command to fix 403 Forbiddden errors - load the three files and build the triptych.
- Remember this:
TW.loadTextures([file1, file2, file3], callback);
The opendir command looks like:
opendir .
Don't forget the dot at the end!
That function is defined in tw-sp25.js
/* Loads all of an array of urls and invokes the callback with an array of
textures when all are finished loading. */
TW.loadTextures = async function(filenameArray, callback) {
if( ! filenameArray instanceof Array) {
throw new Error('first argument must be an array (of strings)');
}
const loader = new THREE.TextureLoader();
// Note that we use loadAsync() here, not load().
// loadAsync() returns a promise
const promises = filenameArray.map(a => loader.loadAsync(a));
const textures = await Promise.all(promises);
console.log('all textures loaded', textures);
callback(textures);
}
Overview¶
The reading covered
- texture coordinates
- texture repetition
- wrapping, and repeating
- combining with material & lighting
Textures Coordinates¶
- texture coordinates
- 2D with 0,0 in the upper left
- s or u goes left-to-right
- t or v goes top-to-bottom
- Using custom texture coordinates, you can use a piece out of an image, but this is somewhat rare.
- However, if texture is mapped onto many triangles, each triangle will typically be a piece of the image


Let's revisit threejs/demos/TextureMapping/box
- How could we get a box with three images whose upper right corner meet at one vertex?
We could edit the texture coordinates. Not easy.
We could have an alternative image that is flipped or rotated so that it works with the existing texture coordinates.
If you need finer control, you can modify the face texture coordinates in the geometry object, but it's not easy if the geometry is big and/or complicated.
Let's also revisit custom buffer geometry
Texture Repetition¶
Let's study threejs/demos/TextureMapping/flowerRepeat
repeat.set(s,t)
are the repetitions in the s and t directionswrapS
is what to do for values of s outside of [0,1]wrapT
is what to do for values of t outside of [0,1]- For example: is s=1.1
- the same as s=1 (clamp),
- the same as s=0.1 (repeat)
- the same as s=0.9 (mirror repeat)
- I've never seen a good use of
clamp
mirrorRepeat
is a nice way to avoid seams but plainrepeat
is also useful: think tiles or bricks
Essential Code:
loader.load("flower1.jpg",
function (texture) {
texture.repeat.set(2,2);
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.MirroredRepeatWrapping;
const mat = new THREE.MeshBasicMaterial({map: texture});
const mesh = new THREE.Mesh(planeGeom, mat);
mesh.position.set(+1,-1,0);
scene.add(mesh);
} );
Tutor¶
Textures combined with Material and Lighting¶
- The texture color components are multiplied by the color computed by material and lighting.
- If either is zero, the result is zero, so black is easily achieved
- Typically, the hue comes from the texture, rather than the material, so the material is gray
- The light need not be gray, but often is.
- The tutor above uses gray material and gray light
The Textured Barn¶
We'll spend a little time discussing the last "required figure" assignment.
Your starter code is basically just:
// This has 7 faces. See documentation in tw-sp.25
const barnGeometry = TW.barnGeometryWithMaterialGroups(30, 40, 50);
const barnMesh = TW.createMesh(barnGeometry);
threejs/demos/BasicModeling/barnNormal/
Here's a picture of some of the key texture coordinates:
- top edge is all t=0
- top left is (0,0) for all three triangles
- top right is (1,0) for both triangles
Here's the code from tw-sp25.js
/* I'm first going to re-arrange the code so that there are locations,
* normals, and texture coordinates. The vertices will be built out of
* those. Then, I'll create the faces, with grouping and material
* indexes. The result has these sides/material groups:
0 front quad
1 east or +x quad
2 west -x quad
3 east roof quad
4 west roof quad
5 bottom quad
6 front upper triangle
7 back upper triangle
*/
TW.barnGeometryWithMaterialGroups = function (width, height, depth) {
const w = width, h = height, d = -depth;
const m = width/2; // midpoint
const p = h + w/2; // 45 degree angle at the peak
const r2 = Math.sqrt(2)/2; // for normals on the roof
// 10 locations: five in the front and five in the back. Naming is
// a pair of letters: {w/e/m} for west (towards negative x) or east
// (towards positive x) or middle, and {u,d,p} for up, down, or peak
// then the same for the back
const wdf = [0, 0, 0];
const edf = [w, 0, 0];
const euf = [w, h, 0];
const mpf = [m, p, 0];
const wuf = [0, h, 0];
const wdb = [0, 0, d];
const wub = [0, h, d];
const mpb = [m, p, d];
const eub = [w, h, d];
const edb = [w, 0, d];
// We'll fill these arrays with our helpers
const vertices = [];
const indices = [];
// group code modeled on BoxGeometry
// https://github.com/mrdoob/three.js/blob/master/src/geometries/BoxGeometry.js
// Each group corresponds to a "face" (flat surface of the object), which consists of a set of triangles.
// We need to count the number of triangles in each group, and then do addGroup() at the end of a face.
// Each face/group will have its own normal and materialIndex
let bg = new THREE.BufferGeometry();
bg.type = 'BarnGeometry';
let groupStart = 0;
// let's use quad with the corners starting at the upper left of
// the texture and going counterclockwise
function quad(l1, l2, l3, l4, normal, materialIndex) {
let v0 = { pos: l1, norm: normal, uv: [0, 0] };
let v1 = { pos: l2, norm: normal, uv: [0, 1] };
let v2 = { pos: l3, norm: normal, uv: [1, 1] };
let v3 = { pos: l4, norm: normal, uv: [1, 0] };
let n = vertices.length; // index of v1
vertices.push(v0, v1, v2, v3);
// these are the two triangles
indices.push(n+0, n+1, n+2);
indices.push(n+0, n+2, n+3);
let numVertices = 6;
bg.addGroup(groupStart, numVertices, materialIndex);
groupStart += numVertices;
}
// This triangle is designed to sit on top of a quad whose top
// edges has the texture coordinates are t=0, and s goes from 0
// (at V0) to 1 (at V3). So, this triangle will repeat those for
// V0 and V1, and V2 will have t=1 and s=0.5
function tri(l1, l2, l3, normal, materialIndex) {
let v0 = { pos: l1, norm: normal, uv: [0, 0] };
let v1 = { pos: l2, norm: normal, uv: [1, 0] };
let v2 = { pos: l3, norm: normal, uv: [0.5, 1] };
let n = vertices.length; // index of v1
vertices.push(v0, v1, v2);
indices.push(n+0, n+1, n+2);
let numVertices = 3;
bg.addGroup(groupStart, numVertices, materialIndex);
groupStart += numVertices;
}
quad(wuf, wdf, edf, euf, [0,0,1], 0); // front quad
quad(euf, edf, edb, eub, [+1,0,0], 1); // east or +x side
quad(wub, wdb, wdf, wuf, [-1,0,0], 2); // west or -x side
quad(mpf, euf, eub, mpb, [+r2,r2,0], 3); // east roof
quad(mpb, wub, wuf, mpf, [-r2,r2,0], 4); // west roof
quad(edf, wdf, wdb, edb, [0,-1,0], 5); // bottom
quad(eub, edb, wdb, wub, [0,0,-1], 6); // back quad
tri(wuf, euf, mpf, [0,0,1], 7); // front side upper triangle
tri(eub, wub, mpb, [0,0,1], 8); // back side upper triangle
// Whew! Now, build the rest
TW.setBufferGeometryFromVertices(bg, vertices);
bg.setIndex(indices);
return bg;
}
We won't go through all of that, but we'll skim the triangles and quads.
No Second Exercise¶
But you might go back to your triptych and experiment with material and lighting and/or repetition.
You can also work on your textured barn.
Summary¶
- Texture coordinates are associated, in the geometry object, with every vertex and every facet of the geometry
- Texture coordinates determine what part of the image is mapped to that triangle
- Textures can be repeated (multiplied by a factor) so that a texture can be mapped multiple times on a surface
- The
repeatS
andrepeatT
property of the texture shows how to handle repetition:- clamp
- repeat
- mirror repeat
- Texture mapping can be combined with material and lighting
Next Time¶
Conclude texture mapping
- filters: linear versus nearest
- texture mapping onto tetrahedrons
- texture mapping on cylinders and spheres