Lab 5: OBJ files

Goals

By the end of this lab, you will:

This lab is short and only consists of finding a 3d model to render because I want to give everyone a chance to catch up on the previous labs. Some information about describing 3d models is provided below for your information.

The next section also covers how to get set up to work on your labs locally (on your computer).

Using git locally (optional but highly recommended)

Codespaces work well, but I also want you to be familiar with how to develop graphics programs in a non-Codespaces environment (specifically, locally on your computer). You'll need to install the following tools (if not already installed):

Then open VS Code and install the following two extensions. Extensions can be installed by searching within the Extensions panel on the left (the Extensions icon looks like a game of Tetris):

To work on an assignment, you'll need to sign into GitHub within VS Code (though there are other ways to authenticate). Open a new window in VS Code (click File -> New Window). Then click on the Source Control panel, and click Clone Repository. Then click Clone from GitHub. Click Allow to allow VS Code to sign into GitHub. Your default browser should open with a new tab asking you to authorize the connection: click Continue. You should now be able to scroll through the repositories you have access to, which should include your repositories for our class.

After selecting the repository you want to work on, pick a destination (it might be a good idea to create a folder on your computer to save all your CS 461 work). Then you can use VS Code as you have been using Codespaces so far (e.g. click the Go Live button which will be available after installing the "Live Server" extension).

Why do we need to Go Live? In some labs, like Labs 1 and 2 and 3, you could just open the index.html page. However, for Labs 4 and beyond, we will often need to run a server, mostly because we need to read our mesh files.

OBJ file format

In class, we were rendering a giraffe that came from a giraffe.obj file. This was a Wavefront OBJ file which contains information about all the triangles (called a mesh) that represent the giraffe. We have treated triangles as being defined by three 3d points $\vec{a}$, $\vec{b}$ and $\vec{c}$, which we will continue to do in our ray tracers. However, meshes are usually represented using two tables: one for the vertex coordinates V (real values) and another for the triangle indices T (integer values), which reference the vertices defined in V. This is similar to how you would represent a graph as a collection of vertices and edges in which each edge references two vertices.

In an OBJ file, any line that starts with a v means it is a vertex and the order of the vertices in the file is the same order as they appear in the table V (with indexing starting at 1). Lines that start with f define the indices of the vertices representing a face. For example,

f 1 8 4

defines a triangle (since there are 3 vertex indices listed on this line) which references the first (1), eighth (8) and fourth (4) vertices stored in the V table.

There are other lines that may begin with vt or vn. This allows you to load additional tables and reference either the "vertex texture coordinates" (next week!) or "vertex normals".

Why would we want to load vertex normals? Well, we have talked about computing per-triangle normals, which we can use in our shading models. However, we can also define per-vertex normals and then use the resulting barycentric coordinates from the ray-triangle intersection to interpolate the per-vertex normals. This will produce a smoother-looking shading model. If vertex normals and/or texture coordinates are present in the OBJ file, you might see face descriptors like:

f 1/2/10 4/3/10 5/4/9

There are still three vertices here but the notation a/b/c means a is a vertex coordinate index, b is a reference to a texture coordinate and c is a reference to a vertex normal (all to the corresponding tables). For more information, please see the Wikipedia page on Wavefront OBJ files.

Reading OBJ files with webgl-obj-loader

As in the exercise from class, I would recommend using webgl-obj-loader to read OBJ files and then create all your Triangle objects to render (and then possibly create a BoundingVolumeHierarchy from this collection of triangles). Include the following line in your HTML page to make the webgl-obj-loader available:

<script src="https://cdn.jsdelivr.net/npm/webgl-obj-loader@2.0.8/dist/webgl-obj-loader.min.js"></script>

Then load your model (when the page loads) using:

const main = (meshes) => {
  const mesh = meshes.my_mesh_name; // because of the `my_mesh_name` key defined below

  console.log(mesh.vertices); // this is the V table
  console.log(mesh.indices); // this is the T table

  // set up model, BVH, and render...
};

window.onload = () => {
  OBJ.downloadMeshes(
    {
      my_mesh_name: "my_model_file.obj",
    },
    main // the `main` function defined above will run after loading
  );
};

Note that mesh.vertices is a one-dimensional array - we need to take a stride of 3 (since the model is in 3d) to access a particular vertex's coordinates. For example, the x, y, and z-coordinates of the fifth (index 4) vertex are:

const vtx = 4; // fifth vertex
const x4 = mesh.vertices[3 * vtx];
const y4 = mesh.vertices[3 * vtx + 1];
const z5 = mesh.vertices[3 * vtx + 2];

The same concept applies to extracting the indices of each triangle, where webgl-obj-loader gives us mesh.indices for these indices. Note that webgl-obj-loader gives us 0-based indices (i.e. a reference index of 1 in the OBJ file will have index 0 in the indices array). For example the three vertex indices of the eight triangle (index 7) are:

const tri = 7;
const t0 = mesh.indices[3 * tri];
const t1 = mesh.indices[3 * tri + 1];
const t2 = mesh.indices[3 * tri + 2];

This means the number of vertices is mesh.vertices.length / 3, and the number of triangles is mesh.indices.length / 3. I would recommend studying the Model constructor from the in-class exercise.

Resources for finding and editing 3d models.

Please find a model that you may wish to include in your Final Rendering. Here are some resources for finding 3d models:

Look for files in .obj format since the scripts we have been developing use the webgl-obj-loader.

If you model still has too many triangles and takes too long to render, I would suggest reducing the number of triangles through a process called simplication/decimation. This is a technique for collapsing triangles that have a minimal effect on the overall shape. You can try the MeshLab software (download here: https://www.meshlab.net/#download):

  1. Import your model (File -> Import Mesh).
  2. Click on Filters -> Remeshing, Simplification and Reconstruction -> Simplification: Quadric Edge Collapse Decimation.
  3. Select the number of triangles (faces) you want and click Apply.
  4. Export your model (File -> Export Mesh As, select Alias Wavefront Object (.obj) ). You can uncheck all the options or click None in the bottom left corner of the options window.

Actually, Step 2 is one of the algorithms we implement in Geometric Modeling (CSCI 422).

Submission

Please find a (free) model that interests you using one of the websites above. Then submit a link to the model in this Canvas quiz, which is how you will submit this week's lab. There are also some questions about some of the model specs (# triangles, # vertices) and to upload a picture (it's okay to upload a screenshot of the rendering on the websites above), or you can submit a screenshot of your decimated model from MeshLab (if applicable).

Submitting the Canvas quiz with all the requested information is sufficient for a C (Complete) on this lab.


© Philip Caplan, 2025