# teaching machines

## Cube

May 11, 2021 by . Filed under public, slai-2021.

This post is part of a course on geometric modeling at the Summer Liberal Arts Institute for Computer Science held at Carleton College in 2021.

In this exercise, you will break into the third dimension and model a cube. We start on paper, progress to a disappointing rendering, and iterate toward a satisfactory rendering with 3D shading.

### Drawing

As always, we start our thinking on paper in order to get ideas out in front of us. Follow these steps to lay out the groundwork for our cube.

• Draw a cube on paper.
• Pretend that the origin (0, 0, 0) is right in the middle of the cube.
• Pretend that the nearest face of the cube is on the z = 1 plane and that the farthest face is on z = -1. In computer graphics, a common convention is to have the z-axis point out of the screen at the viewer. This may feel strange to you.
• Pretend that the right face of the cube is on the x = 1 plane and the left is on x = -1.
• Pretend that the top face of the cube is on the y = 1 plane and the bottom is on y = -1.
• Label each vertex with its xyz-coordinates.
• Label each vertex with the index that you want it to have in the positions array. Since there are eight vertices, the indices run from 0 through 7. I recommend that you follow the labeling scheme shown on this reference cube: Then you can use this reference to figure out the triangles later on.

Keep your drawing nearby and modify it as you find ways to improve upon your initial sketch.

### Render

Turn your drawing into an interactive rendering by completing the following steps:

• Define a function in shapes.js named generateCube. It will have the same general structure as generateSquareDonut.
• In the function, create a positions array that contains the xyz-coordinates of the eight vertices of the cube. Order the vertices according to the indices you assigned.
• Create a triangles array that stitches the array vertices together to form the faces of the cube. Each of the six faces is composed of two triangles, and each triangle is three indices. How many total indices are in the list?
• Return the two arrays in a single object.
• Call generateCube in render.js.
• Render the cube as points.
• Switch to rendering the cube as a solid mesh.

In your browser you should see a cube that you can rotate and zoom. Discerning the faces is difficult, because there is no shading. All the pixels of the cube are assigned the color that you set in the material.

### Lighting

To properly see 3D geometry, you need to add lighting and use a material that supports lighting. Follow these steps to shade the cube’s pixels based on a light source.

• In render.js, change the MeshBasicMaterial to MeshPhongMaterial, which is named after Bui Tuong Phong, the inventor of the shading algorithm you’re going to use.
• Add a new property to the material to set the shininess of the surface:
const material = new THREE.MeshPhongMaterial({
color: 'orange',
shininess: 90,
});

The higher the shininess value, the more concentrated the specular highlights will be. A mirror, for example, has a very high shininess value.
• Add a light source. THREE.js provides many different kinds of light sources. We start with the one that uses the fewest parameters: DirectionalLight. A directional light is used to model light that comes from very far away, much like sunlight. Anchor the light to the camera so that it doesn’t rotate with the scene:
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(2, 2, 1);

Since the light is anchored to the camera, the positioning is relative to the camera. This means that the light is 2 units to the right of the camera, 2 units above, and 1 unit behind.

When you reload the scene, you should see a black cube. The shading isn’t working yet.

### Normals

Besides adding a light source, you also need to provide information about the orientation of the surface around each vertex. In particular, you need to provide a normal for each vertex. A normal is a direction that is perpendicular to a surface. A normal that aligns with the direction to the light source means the surface is fully illuminated. As the surface tilts away, it receives less light. Follow these steps to add normals to your cube:

• Paste this line in the head element in index.html:
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/helpers/VertexNormalsHelper.js"></script>

• In render.js, add this line of code after you’ve fully configured geometry:
geometry.computeVertexNormals();

• When you reload, the cube appears shaded, but the shading doesn’t seem right. Display the normals to understand the problem:
const normals = new THREE.VertexNormalsHelper(mesh, 0.5, 0x00ff00, 1);

Place this code somewhere after you’ve created mesh. See how the normals point out from the corners of the cube. Normals are supposed to be perpendicular to the surface, but these normals aren’t perpendicular.
geometry = geometry.toNonIndexed();