CS 488/688: Introduction to Computer Graphics

Spring 2022 Assignment 1: OpenGL


Summary

In this assignment you will learn the basics of programming real-time 3D graphics using OpenGL. You will create geometric primitives, draw them to the screen, and modify the contents of the 3D environment in response to user interaction. In particular, you will draw a maze from cubes. (There is no texturing, no shading, no redstone, no creepers, no minotaurs, etc.)

The Maze environment

The most obvious feature of the Maze is the grid, which lies on the ground (i.e., the plane y = 0) and defines the legal squares upon which blocks of the maze will sit. Each grid cell is a unit square, and the grid itself is an N×N arrangement of legal cells for some constant N. In the environment, we actually draw a grid of size (N+2)×(N+2), surrounding the main grid with an extra ring of cells.

You are provided with a routine to generate the maze. The maze consists of a grid of values; a grid cell has a value of 1 if there should be a block in the cell, and 0 of there should not be a block. The base of the block should fill the grid cell; i.e., if two adjacent grid cells both have blocks in them, then there should be no space between the blocks. The result is a 4 point connected arrangement of blocks that form a maze. The outer boundary of the maze has two openings (an entrance and an exit). You will be able to grow and shrink the height of the walls.

The blocks you use to draw the cells of the maze should have one colour, which you'll be able to change with the colour editor. You should also draw a polygon for the floor, which will lie on the grid; you will also be able to edit the colour of this floor. The floor colour should be different than the colour of the maze blocks. The floor should only cover on the NxN portion of the grid. The outer perimeter of the grid will always be visible.

In addition to drawing the maze, you will be able to move a spherical avatar through the maze. You can start by making the avatar a block that is the same size as the maze blocks, or a bit smaller. But eventually you will need to create a sphere shaped avatar for full marks. Regardless, the avatar should be a different colour than colours of the maze blocks (although the avatar may be of a single colour). You are free to model an avatar more complex than a sphere if you want. Your initial implementation could start by reusing the cube, but you need to algorithmically generate the triangles of a sphere for full credit.

For the most part, you will use the keyboard to control the modelling environment, as explained below. In addition, you can manipulate the view in a few simple ways via the mouse: you can rotate the grid around its centre to look at the design from all angles, and scale it up or down.

User interaction

The initial state should not display any maze, and should show the avatar at (0,0).

Your implementation of Maze should support (at least) the following commands and interactions:

Skeleton code

If you haven't already, follow the instructions in Assignment 0 for downloading the framework and skeleton code. You'll find the skeleton code for this assignment in the A1/ directory. It should compile and run out of the box using the same premake4/make commands used for Assignment 0. You'll see the the skeleton program sets up the control panel, including a Quit button and single example of a colour slider and radio button. It also draws a ground grid for you. Notice that the grid is of size 18×18. The live area of the grid is 16×16, as defined by the constant DIM in A1.cpp; the program automatically adds the extra ring of cells around the maze (i.e., the ground grid extends one beyond the walls of the maze). The program defines reasonable initial values for the projection, view and model matrices, and passes them into the vertex shader for you.
maze.cpp contains a class for generating a maze.

Here is a suggested sequence of steps to get you started with this assignment. (But feel free to work on the assignment in any order you want!)

  1. First and foremost, get a cube on the screen. This is probably the hardest part of the assignment! Define the geometry of a unit cube, and get it into OpenGL by creating appropriate attribute arrays and vertex buffers. You must use modern OpenGL commands here and throughout the assignment. That is, eventually you'll draw cubes using a function like glDrawArrays() or glDrawElements(), and you should never call functions like glVertex().
  2. See if you can create walls that are more than one block high.
  3. If you can do that, hook up the space and backspace keys to groaw and shrink the walls.
  4. Now define and locate the avatar, and add in the functionality for moving the avatar with the arrow keys.
  5. Add in the colour editor.
  6. Add in mouse rotation. This is most easily accomplished by modifying the model-to-world transformation while holding the camera fixed. As is typical in interactive programs, it'll help to keep track of the previous x position of the mouse, so that you can rotate by an amount proportional to the difference in x every time you receive a mouse event. (Note that after rotating, the arrow keys might become quite unintuitive, since the grid is rotated relative to the directions of the keys. You don't have to worry about that for this assignment.)
  7. Hook up a simple timer that calls down to the maze's render method and re-renders. You should now be able to implement persistence.
  8. Add scaling by responding to scroll events. There are probably several ways to do this. One would be to scale the world itself by manipulating the model-to-world transformation. Another is to move the camera closer to or farther from the centre of the grid. Either technique is fine, as long as the scaling is bounded within reasonable limits.
  9. Finally, add in the Reset button and its hotkey, setting all the values manipulated above back to the defaults.

Deliverables

The submission process for this assignment is basically the same as the one for Assignment 0. Prepare a ZIP file of the A1/ directory, omitting unnecessary files (executables, build files, etc.). Upload the ZIP file to LEARN.

As with Assignment 0, you must submit two other files in your A1/ directory: the README and a screenshot. If you omit either of the first two files, you will receive a deduction. See Assignment 0 for instructions about how to prepare these files.

Other thoughts

As OpenGL has evolved, the API has actually gotten a bit more streamlined. The part of OpenGL you talk to from inside a C++ application tends to focus on telling the GPU about the pieces of data that power your program, and maybe setting a couple of system-wide parameters; most of the actual "graphics" has been pushed into the shaders.

If it helps, here is the complete set of OpenGL API calls we used in the model solution. This is for information only: you should feel free to use a subset of these functions, and to include others not on the list. But you should not use deprecated OpenGL calls from the compatibility profile: no glBegin(), glVertex(), or glEnd()!

Ideas for extensions

The Maze environment is a great starting point for expansion in new directions. We'd be excited to see what additional features you can add to the base interface, if you've got the time. We may award a bonus point or two for especially ambitious extensions. Here are some random ideas for extensions:

If you do extend the base interface, be sure to document your extensions in your README file. Keep in mind that you must still satisfy the core objectives listed here. If your changes are so radical that your modified program is incompatible with the original specification, you must include a "compatibility mode" that makes the interface behave like the requirements here. (Or consider creating an entirely separate executable.)

Step 5: Objective list

Every assignment includes a list of objectives. Your mark in the assignment will be based primarily on the achievement of these objectives, with possible deductions outside the list if necessary.

Assignment 1 objectives