Mesh Editor

Henry Xu



Overview

Over the course of this project, I explored geometric modelling in the context of computer graphics, starting with an introduction to Bezier curves and surfaces and finishing with a mesh editor capable of loop subdivision. I learned that with a proper data structure, seemingly daunting implementation tasks such as that of triangle meshes can be translated into reality fairly efficiently, allowing us to produce increasingly complex graphical objects. Overall, the project was an very insightful foray into a fundamental concept of computer graphics, and one I enjoyed immensely.

Section I: Bezier Curves and Surfaces

Part 1: Bezier curves with 1D de Casteljau subdivision

Given n+1 control points, we can define a n degree Bezier curve using 1D de Casteljau subdivision. The key idea underlying de Casteljau subdivision is that of recursive linear interpolation. Let x be the relative location we want to evaluate the Bezier curve at. If we think of each recursive step as a level, given some level l with k points, level l + 1 can be computed by linearly interpolating of every sequential pair of points at x, giving us k-1 new points that can then be used to compute the level l+2. The recursion ends when we reach a level with only one point, which we subsequently return. By varying x between 0 and 1, we can construct the full Bezier curve.

Screenshots:

Original Control Points.
Second Interpolation Level.
Third Interpolation Level.
Fourth Interpolation Level.
Fifth Interpolation Level.
Sixth and Final Interpolation Level.
Modified Control points in addition to change in t.

Part 2: Bezier surfaces with separable 1D de Casteljau subdivision

The 1D de Casteljau subdivision algorithm can be easily extended to 2 dimensions to create a surface. To evaluate the relative point (u,v) given an array of control points with dimensions n by m, the underlying idea is as follows:
Teapot using Bezier Surfaces.

Section II: Sampling

Part 3: Average normals for half-edge meshes

For a given vertex, we can calculate the unit normal as follows: Details regarding traversal and edge calculation:
OpenGL shading without smoothed normals.
OpenGL shading with smoothed normals.

Part 4: Half-edge flip

Given two adjacent triangles, the half-edge flip takes their shared edge and flips it to connect the two previously unconnected vertices. Using the half-edge data structure, the half-edge flip became a matter of drawing an accurate picture and reassigning pointers accordingly. A resource I was quite inspired by was Correctly Implementing Edge Flip/Split/Collapse. An implementation tip that I found very useful was the assigning of all references, regardless if they changed or not. A major debugging debacle was that of an accidental getHalfedge() call that inexplicably crashed the editor when the function was called. After checking my reassignments numerous times, I finally switched my focus to the seemingly innocuous boundary check that contained the offender.
Teapot with original mesh.
Teapot with flipped mesh.

Part 5: Half-edge split

Given an edge between 2 triangles, the half-edge split introduces two new edges, one to split each face--each new edge starts from the midpoint of the given edge and ends in the opposite corner of its respective triangle. Using the half-edge data structure, the half-edge flip once again became a matter of drawing an accurate picture and reassigning pointers accordingly. In this case, however, we also had to introduce 3 new edges, 2 new faces, 6 new halfedges, and 1 new vertex whose pointers all also had to be properly assigned. A glimpse of my scratch work (emphasis on scratch): A truly great debugging quest was undertaken--having not realized I accidentally created an extra face, I spent an inconceivable number of hours figuring out what reassignment had gone wrong before I realized the rogue extra line of code.
Teapot with original mesh.
Teapot with flipped and split mesh.

Part 6: Loop subdivision for mesh upsampling

When given some low-resolution polygon mesh, there are times when we would benefit from upsampling, e.g., for displays and simulation. We can accomplish this through Loop subdivision, whose two steps are as follows: The weighted averages are calculated as follow: "4-1 subdivision" can be achieved by splitting every old edge arbitrary and flipping any new edge that connects an old vertex to a new vertex, taking care to not accidentally flip any of the edges that comprise the original edge (since each original edge will now be represented by 2 edges).

A few implementation tricks I used were to compute new positions before doing any splitting, since the original connectivity is far easier to traverse than than the new upsampled connectivity. The traversal is not unlike what was done in Part 3, but instead of keeping track of faces, we kept track of vertices.

Original Torus.
Torus after one Loop Subdivision.
Torus after two Loop Subdivisions.
Torus after three Loop Subdivisions.


As the number of Loop subdivisions increases, the sharp corners and edges get rounded out. We can mitigate this effect slightly by pre-splitting edges as seen below. Notice the corners remaining after three Loop subdivisions.

Pre-Split Torus.
Pre-Split Torus after One Loop Subdivisions.
Pre-Split Torus after Two Loop Subdivisions.
Pre-Split Torus after Three Loop Subdivisions.
Pre-Split Torus after Three Loop Subdivisions from a Different Perspective.


In the case of the cube, notice a slight deformation as the number of Loop subdivisions increases. This effect result from the asymmetry of the mesh on the cube's faces--on some faces an edge goes from top left to bottom right, whereas on other faces an edge goes from from top right to bottom left. As subdivision occurs, these differences cause some corners of the cube become more subdivided than their surroundings, resulting in odd bumps on the ensuing surface.

Original Cube.
Cube after one Loop Subdivision.
Cube after two Loop Subdivisions.
Cube after three Loop Subdivisions.
Cube after four Loop Subdivisions.


We can increase symmetry of the mesh by once again pre-splitting the edges, specifically ones that cross faces. The result as we perform Loop subdivision is a far more symmetrical surface, as seen below.

Pre-Split Cube.
Pre-Split Cube after one Loop Subdivision.
Pre-Split Cube after two Loop Subdivisions.
Pre-Split Cube after three Loop Subdivisions.
Pre-Split Cube after four Loop Subdivisions.


The images for half-edge flips, half-edge splits, and "4-1 subdivision" were borrowed from the cs184 course website. Thank you for reading!