Assignment 1: Build Your Virtual City (34 Points)
Chris Tralie
Due Friday 2/4/2022
Click here to view the art contest submissions!
Overview / Logistics
The purpose of this individual assignment is to enable you to brush up on your knowledge of methods and how they fit together, and to practice them in a new language: C++. It is also an opportunity to practice reading documentation for existing methods to learn how to use them, which is something you will often do in practice, since we rarely re-invent the wheel and often use code that other people write (often called a library).
This assignment will also get you to practice the edit -> compile -> run -> edit loop, since you will have to tweak your shapes many times to get a good result.
The specific task in this assignment is to write code to generate 3D worlds. It's much easier if you write methods whose sole job is to draw a particular city object, like a fire hydrant or stop light. Then, you can replicate these objects many times by calling the methods over and over again to create complicated parts of the your world (like city blocks). Putting complicated things completely in one chunk of code to be reused many times with minor variations is an example of encapsulation, which is a major theme of this class.
You can download the code for this assignment by using git in the terminal
git clone https://github.com/ursinus-cs174-s2022/HW1_VirtualCities.git
You will be writing code that writes json files with information about 3D scenes, which you can open in this 3D engine that I created for the web browser.
Learning Objectives
- Write methods to fit a specification
- Follow documentation to use pre-defined methods
- Use methods together in concert to accomplish a task
- Write a complete program with very little code in the
main
function - Work with 3D coordinates programmatically
- Use C++ makefiles and the terminal to build and run programs
What to submit
When you are finished, you should submit zip file of your HW1_VirtualCities
directory to canvas. This should contain all of your code, the .json
scene files for both the city scene and your art contest, and any animated GIFs you made for your art contest. Also submit a comment on canvas with answers to the following questions
- What title would you like to use for your art contest submissions, and what name/pseudonym you would like to use? (results will be displayed on the class web site).
- Any other concerns that you have. For instance, if you have a bug that you were unable to solve but you made progress, write that here. The more you articulate the problem the more partial credit you will receive (fine to leave this blank)
Background: 3D Coordinate Systems
A point in 3D space is represented with 3 coordinates: one in the x-axis, one in the y-axis, and one in the z-axis. There are a few different ways to define such a coordinate system, but we will stick to the OpenGL convention in this class. Below is a sketch of the positive coordinate axes for x, y, and z. A point (a, b, c) can be obtained by creating a rectangular prism with side length a along the x-axis, b along the y-axis, and c along the z-axis. The point then resides on the vertex of the cube furthest from the origin where the three axes meet (the red point).
Background: RGB Colors
In addition to perceiving space in 3 dimensions, humans interestingly also perceive color in 3 dimensions. One basis for color representation is the "RGB" or "Red, Green, Blue" axes. Each axis is represented with 8 bits, so possible values are from 0 (no color) to 255 (full saturation of that color). For instance, rgb(255, 0, 0) is red, and rgb(0, 0, 255) is blue.
The widget below allows you to play around with colors, which you may want to do for the art contest.
Background: 3D Scenes And Shapes
Click here to launch the scene viewer in your browser
In this assignment, you will be creating 3D worlds, also known as "scenes," that can be loaded into an engine I made for my computer graphics class known as ggslac. As in the HTML holidays lab, your C++ program will write code that this engine can interpret (though it is JSON code instead of HTML). You don't have to worry writing code strings yourself this time, though. Instead, I have provided a series of high level functions that you can use to draw shapes, and which will automatically convert to code on the backend that you can open in the engine, as shown below.
The full documentation for drawing shapes can be found at this link. Below are a few examples with links to the respective documentation. There are two versions of most methods: one for drawing an "axis-aligned" shape, and one for drawing a rotated version. You'll mostly be using the axis-aligned versions in the tasks.
3D Box
- Click here to view the documentation for drawing an axis-aligned box.
- Click here to view the documentation for drawing a rotated box.
Cylinder
- Click here to view the documentation for drawing an axis-aligned cylinder.
- Click here to view the documentation for drawing a rotated cylinder.
Cone
- Click here to view the documentation for drawing an axis-aligned cone.
- Click here to view the documentation for drawing a rotated cone.
Sphere
- Click here to view the documentation for drawing a sphere.
Ellipsoid
An ellipsoid can be viewed as a stretched out version of a sphere or a 3D generalization of an ellipse.
- Click here to view the documentation for drawing an axis-aligned ellipsoid.
- Click here to view the documentation for drawing a rotated ellipsoid.
Special Mesh
For the art contest, you have a variety of triangle meshes available, including my head ("proftralie") and 400 shapes from the Princeton shape benchmark. Click here to view the documentation for the addSpecialMesh
method. The available shapes are listed below (they are case sensitive and will not show up if you don't get them exactly right, so be careful with spelling!)
Airplane1-Airplane20, Ant1-Ant20, Armadillo1-Armadillo20, Bearing1-Bearing20, Bird1 - Bird20, Bust1-Bust20, Chair1-Chari20, cow, Cup1-Cup20, dinopet, Fish1-Fish20, Fourleg1-Fourleg20, genusthree, genustwo, Glasses1-Glasses20, Hand1-Hand20, hand-simple, homer, Human1-Human20, icosahedron, Mech1-Mech20, Octopus1-Octopus20, Plier1-Plier20, proftralie, StyrofoamHead, Table1-Table20, teapot, Teddy1-Teddy20, triangularPrism, Vase1-Vase20
Here's an example with three of the special meshes. You may need to scale them to get them to the size you want, since they have all been "normalized" to the same scale.Programming Tasks
You will start by making a series of methods that draw specific city objects. Since you'll want to draw many copies of these in different places, you must specify parameters to move the shapes around. For example, if I have a box that's normally centered at (1, 2, 5), I should be able to specify a difference of cx
and cz
to shift it in the X and Z directions, so that the new box would be centered at (1+cx, 2, 5+cz) You don't have to get the exact shapes that are shown in the pictures, but you should get reasonably close. I'll start by giving you a simple example below that draws a street sign.
Example: Sign
We can draw a simple sign with a thin cylinder for its poll and a thin box for the sign itself. Below is an example of how one might accomplish this with a method
Here's an example code snippet that calls this method to create two signs. For kicks, I also threw in Homer Simpson
NOTE: The syntax void drawSign(Scene3D& scene ...)
may seem a bit strange at this point in the course. We will talk about this more later, but scene
is an object of type Scene3D
, and the Scene3D&
prefix is indicating that we want to pass scene
by reference. This means that we're not creating a copy of the scene when we call the method, but we're actually referring to the same scene across methods. Then, we can call a method within the object with scene.method()
. Don't worry if this doesn't totally make sense yet...just follow drawSign
as an example when you're doing other methods, and you'll be fine.
Setup / Makefile (3 Points)
First, to get started, you should setup a file called myscene.cpp
that you will compile to generate your scene. You should keep the main file very small, as per the style guide. As an example, you can refer to the file simplescene.cpp
, which sets up the small example scene above with two signs and Homer Simpson. Finally, to make your job quicker as you go along, you should add an appropriate entry to your makefile.
Tree (5 Points)
Create a method that draws a simple "lollipop" tree, which consists of a brown (rgb 102, 51, 0) trunk of a specified height, and a green (rgb 0, 255, 0) ellipsoid for the "leaves." The height should be a parameter to the method so you can draw trees of varying heights.
Below is an example of an 8 meter tall tree next to a 6 meter tall tree (so calling the method twice).
Fire hydrant (5 Points)
Create a method that draws a red (rgb 255, 0, 0) fire hydrant that is roughly 1 meter tall. The fire hydrant should consist of a small cylinder at its base with a larger, thinner cylinder on top. It should also consist of a sphere on the top of the taller cylinder, and two boxes coming out right below the sphere.
Stop light (5 Points)
Create a method that draws a stop light. The main pole on the left should be 8 meters tall, and the horizontal pole at the top should be 8 meters wide. Attach a box to the horizontal poll that will hold the lights. The top light should be a red (rgb 255, 0, 0) sphere, the middle light should be a yellow (rgb 255, 255, 0) sphere, and the bottom one should be a green (rgb 0, 255, 0) sphere.
Below is an example stoplight with a fire hydrant next to it for scale.
Sedan (5 Points)
Create a method that draws a (very boxy) car, either facing east/west or north/south, with a particular color. It should have one box of that color that is 4.5 meters long, 1.7 meters wide, and 0.7 meters tall. On top of that, it should have a slightly offset box that is 3.5 meters long, 1.4 meters wide, and 0.8 meters tall. On the bottom box, there should be two grey cylinders of radius 0.5 and height 2 to represent the wheels. For the east/west car, you will have to rotate the cylinder around the x-axis by 90 degrees, and for the north/south car, you will have to rotate the cylinder around both the x-axis and the y-axis by 90 degrees.
Below is an example of a red east/west car and a yellow north/south car, with a fire hydrant and stop light for scale (that red car should probably get out of the way...)
City Block (5 Points)
Create a method that creates a city block by calling the other methods. It should have the following:
- At least two cars
- At least two trees of different heights
- At least one fire hydrant, stop light, and sign
- At least one building (which can simply be a large box)
Finally, setup the method so that it takes an offset, and use it to draw at least two copies of this city block to create an entire city.
Style (3 Points)
You will be graded on adherence to the style guide. Pay particular attention to your method documentation.
Art Contest (3 Points)
Create a c++ file artcontest.cpp
and a corresponding makefile entry to create an executable called artcontest
, which outputs a file artcontest.json
with any virtual world you want. Unleash your creativity! Your scene does not have to be a city. Indicate in your submission a title for your scene and what name or pseudonym you would like to use for the contest. The winner will receive 5 points of extra credit.
In addition to the scene, you may also want to submit a movie of it. The GIF below shows how to select two different cameras and automatically fly between them
The result is as follows