To build upon your knowledge of C++ and OpenGL by creating a half-edge data structure from interlinked pointers and then visualizing your mesh using OpenGL vertex buffers.
We will provide you with base code very similar to the code you received for the previous homework assignment. The only addition is that of an interactive camera; you can view the camera control scheme under the Help menu of the provided GUI. We will also provide OBJ files to read for section 4.5.
Click here to download the code. Click here to download the OBJ files.Maintain a log of all help you receive and resources you use. Make sure the date and time, the names of everyone you work with or get help from, and every URL you use, except as noted in the collaboration policy. Also briefly log your question, bug or the topic you were looking up/discussing. Ideally, you should also the answer to your question or solution to your bug. This will help you learn and provide a useful reference for future assignments and exams.
Before you begin the programming portion of this homework assignment, read and answer the following conceptual questions. Your answers should be written in your readme.txt file along with your documentation of your project.
This homework has several main components:
You will write three classes to form your half-edge data structure: Face, HalfEdge, and Vertex. You should follow the format of the half-edge data structure, as outlined below.
You will also create a Mesh class to store your Faces, HalfEdges, and Vertices. We recommend that you have your Mesh class inherit from Drawable so that you can easily draw it. You'll have to implement Drawable::create() so that it can handle setting up the VBOs for any arbitrary mesh. Your mesh should use the GL_TRIANGLES enum when being drawn, which means you will have to set up triangular indices for any convex half-edge polygon face's index buffer. If you set up your VBO data per-face, you'll probably have an easier time. It might also be helpful to know that you can pass a std::vector as an argument for glBufferData by calling its data() function. Note that in order to properly handle per-face coloring, you will have to use the bufCol variable in the Drawable class and modify the lambert shader we have given you to use fs_Col for fragment color rather than u_Color.
Create a function that builds a cube-shaped mesh using the half-edge data structure. The cube should span the range of [-0.5, 0.5] on each axis. The cube should be constructed from six squares, with no triangles in the HalfEdge structure. When the half-edge data changes (such as after a vertex is repositioned), the mesh should be drawn with these changes. If you're having trouble visualizing the half-edge structure of a cube, we suggest sketching it out beforehand. In previous years, students have even constructed paper cubes and drawn on them.
Write a simple Qt interface to exercise your implemented operations. Create three different list widgets with which to view and select your vertices, half-edges, and faces. We recommend using QListWidgets for this task. Allow the user to change face colors and vertex positions by inputting values into suitable widgets (e.g. double spin boxes). Make sure to send the updated vertex data to your GLSL shader.
When you've selected a face/half-edge/vertex in one of your lists, there should be visual indication of this selection in your GL window:
Note that whenever you alter an attribute of your scene, such as a vertex's position or which HalfEdge is selected, you will have to call QOpenGLWidget::update() from within MyGL in order to cause paintGL() to be called again.
Add the following key press functionality to your program in order to help visually debug your half-edge meshes. When the listed key is pressed, the indicated mesh component should be selected and highlighted:
You should call your puppet construction function from MyGL::initializeGL. You should not construct your scene graph in MyGL::paintGL.
Add file browsing functionality (e.g. QFileDialog) to your Qt GUI that allows the user to select an OBJ file to be read. Your program should generate a half-edge data structure from the input file and then render the resulting mesh using VBOs, wherein each Face is assigned a random color. You will only be required to handle closed and manifold meshes, but you should be able to handle faces with any number of edges (i.e. n-gons) without triangulating them within your half-edge mesh structure. You should NOT use tinyOBJ for this task. You may have your OBJ mesh, once built, replace any previously existing mesh such as the cube you built for the previous section or a previously loaded OBJ mesh. If you are unfamiliar with the OBJ file format, we recommend you read the
An important feature some people may forget is to set up is all of the SYM pointers for the HalfEdges. They are not needed to draw your meshes using VBOs, but they are vital to performing mesh operations such as adding a vertex to an edge (which is one of the operations you will have to implement in the next homework). Make sure you've properly created your SYM pointers (you can visually test them using the features you implemented in section 4.4).
Add two variables to lambert.frag.glsl:
Within MyGL::timerUpdate, increment this timeCount variable by 1 and then using glUniform1i, send this data to your shader. Within your fragment shader, if u_RenderMode is set to 1, use u_Time within some function that modifies the color of each fragment uniquely. For example, you could use GLSL's sine function in conjunction with u_Time and the built-in GLSL variable gl_FragCoord (the screen-space position of a fragment) to modify the red, green, and blue channels of a fragment. If u_RenderMode is set to 0, then just render using regular Lambertian shading. Add functionality so that whenever the user presses the R key on the keyboard, renderMode is swapped between 0 and 1 and then updated in the shader.
If you wish to see your animated fragment color, you will have to make timerUpdate() call QOpenGLWidget::update() whenever renderMode is set to 1.
If you implement any extra credit features, please note them in your readme.txt file. If applicable, also explain how to activate or use your additional feature(s).
Allow the user to select faces, half-edges, and vertices by clicking on the GL window. The component nearest to the camera should be the one selected.The more intersections you implement, the more points you'll be awarded. If you select a component through raycasting, the GUI list containing that component should also be updated to reflect your selection.
We recommend treating Vertices as small spheres, Faces as sets of triangles, and HalfEdges as cylinders. To test against HalfEdges, you might consider finding the nearest point between the ray and the edge and seeing if that point's distance from the HalfEdge is within some radius.
Allow the user to export a half-edge mesh as an OBJ file. The OBJ file should include vertex normals, but UVs are optional.
Add more interesting timer-driven features to your shader program. For instance, you could uniquely offset vertex positions based on a sine function. As long as the feature you add modifies each vertex or fragment differently from one another, you're good to go. The more interesting your feature or features are, the more points you'll be awarded.
Make sure your homework compiles in the Moore labs. We will deduct points from any homework that does not compile, and possibly give a 0 grade if the compile errors are numerous. After you have tested your program, zip the topmost folder of your project and submit the zip to the class web site. Remember to submit your help log and your readme. Additionally, make sure to remove any .git folders as well as any folders created when Qt Creator compiles your program (e.g. folders with a name like "build-460-Desktop-Debug").