Advanced Computer Graphics
• Exercise 1
Due: January 29
1. The Euler-Poincaré formula states that, for a polyhedral mesh topologically equivalent to a sphere, V - E + F = 2,
where V, E, and F are the numbers of vertices, edges, and faces, respectively. Use this to show that for a large triangular mesh the ratio V:F:E is approximately 1:2:3. (Hint: it might make things easier if you think in terms of half-edges.) Also show that the average number of triangles touching a vertex is 6.
- First I will show the relation that F:E is 2:3 and then I will apply the Euler-Poincaré formula to show that V:F is 1:2. For this first part, first note that every face has 3 edges. For each of these edges, there is another triangle on the other side of the edge that actually creates the edge. So, if we look at one face, and take the 3 faces generated by it, and then look at the edges of those faces we see that 3 other faces produce 2 times as many edges as before. Therefore we have the relation that 3F = 2E or F:E is 2:3. For the second part notice that we can use the fact that F/E = 2/3 to our advantage. In this case multpily the formula by 2 to get 2V - 2E + 2F = 4 and then substitute 2E = 3F to get 2V - F = 4. Now if we are interested in the approximation of this ratio we can assume that 4+F = F if we have many faces. This reduces to V = 1/2F or V/F = 1/2, so V:F is 1:2 and F:E is 2:3, so V:F:E is 1:2:3.
- For the second part, note that for every face there are 3 vertices that comprise that face. Since I derived that V:F is 1:2 we know that this means there are 6 faces that are generated. In order for the relation V:F = 1:2 for the whole mesh, it must be that each vertex touches 6 faces.
2. Compute the total size necessary to represent the following data structures for a 1,000-polygon mesh, assuming that point coordinates are represented with 3 4-byte floats and that all indices or pointers are represented with 4 bytes:
a) Separate triangles
b) Indexed face set
c) Half-edge (remember to include space for vertex coordinates!)
- a) For this type of dataset we would need to store every piece of information. Each triangle can be thought of as a face which is contructed from 3 vertices each. Each vertex requires 3*4 bytes worth of space for its coordinates, so each face requires 3*3*4 = 36 bytes for the vertices and 4 bytes for its index. For a 1,000 polygon (aka 1,000 face) mesh, we would need 1,000*40 = 40,000 bytes worth of memory.
- b) This is a bit better that (a) in its use of space. First, note that an indexed face set requires 3*4 = 12 bytes of space for every vertex in the mesh. To determine the number of vertices in a 1,000 polygon mesh, we can simply use the result of question 1. Since there are 1,000 faces, there must be 500 vertices. Each of these vertices must store its coordinates (3*4 bytes) and its index so that it can be referenced (4 bytes). Therefore the total required space for the vertices is 16*500 = 8,000 bytes. Each face now requires 3 pointers for each of the vertices that comprises it, so we need 1,000*3*4 = 12,000 bytes for all of the faces in the mesh. The total space is therefore 8,000+12,000 = 20,000 bytes in total.
This of course is based on the assumption that the mesh is topologically equivalent to a sphere. If this isn't the case and instead you have just a sheet mesh, then the number of vertices would actually be 3+1*999 = 1,002 because after the first triangle in the mesh you would need to add one vertex more to get a new triangle.
- c) First, just as in (b), we need to figure out the number of edes that would be in a 1,000 polygon mesh. Just as before, we use the results of part 1 to find the number of edges. If we have 1,000 faces, then we must have 1,500 edges. Each edge stores a few pieces of information: the vertex that starts the edge, the face to the left of the edge, the next edge originating clockwise from the current edge, and the edge traveling in the opposite direction. Each vertex also stores one of the edges connected to it, and each face stores one of the edges connected to it. We know there are500 vertices in the mesh from (b) and there are obviously 1,000 faces. Since we store half edges, we double the number of edges stored (3,000) and notice that each edge rquires 4+4+4+4 = 16 bytes of space. Each vertex requires 3*4 + 4 = 16 bytes of space and each face requires only 4 bytes of space. Adding these together: 3,000*16 + 500*16 + 1,000*4 = 60,000 bytes. Notice this is much more information than was required in both (a) and (b), but in this case we have retained more information about the structure of the mesh and can answer questions like give me all of the edges adjacent to this vertex.
3. You are implementing an edge collapse-based decimation algorithm, and are considering using either an indexed face set or a half-edge data structure. For these two possibilities, sketch how the following basic operations would be implemented. What is the relative performance of the two data structures? (Assume that the input is a closed orientable manifold triangular mesh.)
a) Given a candidate edge collapse between vertices Vi and Vj determine all faces that touch both of these vertices.
b) Remove face Fk from the mesh (and adjust the data structure to remain self-consistent).
- a)
Indexed Face Set
- For each vertex, return the index stored. Loop through every face and determine whether that face has the index in its list. Do this for both vertices and return the faces that were found. If there are n faces in the mesh, this would require O(n) lookups.
- b) Indexed Face Set
- Remove the face and save the vertices it points to. Compute a new vertex that is in the center of any two of the vertices of the removed face. For any face that was touching either vertex, replace that vertex with the new vertex. If any face has both vertices, remove it also. This would also take O(n) time to lookup the faces that were touching the vertices.
- a) Half-Edge
- Take each vertex in turn. Follow the pointer of the vertex to the edge that originates from it, and store the face that the edge points to (should be the left face). Follow the edge's pointer to the opposite pointing edge and store its left face. Follow this edge's pointer to the next edge and store its left face. Follow this next edge's pointer to the opposite pointing edge and store its left face. Repeat this process until you find a duplicate face. This requires O(1) time since we are just following pointers.
- b) Half-Edge
- I am going to try to be as general as possible for this routine. The main point is that this operation should be O(1) in time also because we really only need to follow pointers and then re-configure some of those pointers to point to new edges and faces. For the actual routine, imagine there is a series of 3 triangles in a row. Say we want to remove the middle triangle. We will do so by adjusting the pointers of the two outer triangles as to make a rectangle that covers the same area as the three triangles used to. First, we start with the face in question and follow its edge pointer and then its opposite edge pointer. We can then traverse all three triangles edges by following the next edge pointers thrice and then one opposite pointer and then three more next edges. After this, the outer rectangle will be defined by the vertices that came after the 3rd, 4th, 7th and 10th jumps. Now we just need to create an edge between the 3rd and 7th collected vertices and two new faces on either side of this edge. We can do this by simply allocating new memory and setting the appropriate pointers.

4. Prove that isocontours of the quadric error metric we studied in class are ellipsoids.
- The quadric error metric is
defined as vTQv where Q is ppT and p is a column vector containing the coefficients in the plane equation (ax+by+cz+d=0). This means that Q has the following structure:
- When we evaluate the error metric we find that:
- If we set this quantity vTQv = k a constant we notice immediately that we have recovered the general formula for ellipsoids.
© 2008 Sean M. Arietta
University of Virginia