Difference between revisions of "Project3F16"

From Immersive Visualization Lab Wiki
Jump to: navigation, search
Line 1: Line 1:
 
=Project 3: Scene Graph=
 
=Project 3: Scene Graph=
  
In this project you will need to implement a scene graph
+
In this project you will need to implement a scene graph to render an army of robots.
 
   
 
   
 
The total score for this project is 100 points. Additionally, you can obtain up to 10 points of extra credit.
 
The total score for this project is 100 points. Additionally, you can obtain up to 10 points of extra credit.
Line 9: Line 9:
 
Start with code that uses your trackball code, and modify it to control the camera instead. (If you didn't get that to work the keyboard controls will suffice.)
 
Start with code that uses your trackball code, and modify it to control the camera instead. (If you didn't get that to work the keyboard controls will suffice.)
  
Create a sky box for your scene. A sky box is a large, square box which is drawn around your entire scene. The inside walls of the box have pictures of a sky and a horizon. Sky boxes are typically cubic, which means that they consist of six square textures for the six sides of a cube. [http://learnopengl.com/#!Advanced-OpenGL/Cubemaps Here] is a great tutorial for sky boxes in modern OpenGL.
+
Create a sky box for your scene with the robots. A sky box is a large, square box which is drawn around your entire scene. The inside walls of the box have pictures of a sky and a horizon. Sky boxes are typically cubic, which means that they consist of six square textures for the six sides of a cube. [http://learnopengl.com/#!Advanced-OpenGL/Cubemaps Here] is a great tutorial for sky boxes in modern OpenGL.
  
 
[http://www.f-lohmueller.de/pov_tut/skyboxer/skyboxer_3.htm Here is is a nice collection of textures for sky boxes], and [http://www.custommapmakers.org/skyboxes.php here is an even bigger one].  
 
[http://www.f-lohmueller.de/pov_tut/skyboxer/skyboxer_3.htm Here is is a nice collection of textures for sky boxes], and [http://www.custommapmakers.org/skyboxes.php here is an even bigger one].  
Line 49: Line 49:
 
* 5 points for correct rendering of edges and corners (seamless edges)
 
* 5 points for correct rendering of edges and corners (seamless edges)
  
<hr>
+
==2. Scene Graph Engine (20 Points)==
  
More to come shortly...
+
To create the parts of the robot (torso, arms, legs), we need to first implement a scene graph structure for our rendering engine. Use the following hierarchy:
  
<!--
+
[[Image:project4F14-scenegraph-half.jpg]]
==2. Scene Graph Engine (15 Points)==
+
 
+
Implement a scene graph structure to simplify rendering of the ride. Use the following hierarchy:
+
 
+
[[Image:project3S16-scenegraph.jpg|500px]]
+
  
 
The classes should have at least the following functionality:
 
The classes should have at least the following functionality:
  
* Class <tt>Node</tt> should be abstract and serve as the common base class. It should implement an abstract draw method: <tt>virtual void draw() = 0</tt>, and also an abstract <tt>virtual void update(glm::mat4 C) = 0</tt> method. (2 points)
+
* Class <tt>Node</tt> should be abstract and serve as the common base class. It should implement an abstract draw method: <tt>virtual void draw(Matrix4 C) = 0</tt>, and also an abstract <tt>virtual void update() = 0</tt> method to separate bounding sphere updates from rendering.
* <tt>Group</tt> should store a list of pointers to child nodes (std::list<Node*>) and provide functionality to add and remove child nodes (addChild(), removeChild()). Its draw method needs to traverse the list of children and call each child node's draw function. (2 points)
+
* <tt>Group</tt> should store a list of pointers to child nodes (std::list<Node*>) and provide functionality to add and remove child nodes (addChild(), removeChild()). Its draw method needs to traverse the list of children and call each child node's draw function.
* <tt>Geode</tt> should be an abstract class. It should update the rendering matrix, and have a draw function to draw its geometry. (2 points)
+
* <tt>Geode</tt> should be an abstract class. It should set OpenGL's ModelView matrix to the current C matrix, and have an abstract render function to render its geometry.
* <tt>MatrixTransform</tt> should store a 4x4 transformation matrix M which is multiplied with matrix C, which is passed to the draw method. (3 points)
+
* <tt>MatrixTransform</tt> should store a 4x4 transformation matrix M which is multiplied with matrix C, which is passed to the draw method.
* <tt>Cylinder</tt> should draw a cylinder, which you can load from [http://ivl.calit2.net/wiki/images/9/92/Cylinder.zip this OBJ file]. (3 points)
+
* <tt>Sphere</tt> should have a draw function which draws a sphere. You can use <tt>[https://www.opengl.org/documentation/specs/glut/spec3/node81.html glutSolidSphere]</tt> for that, or use your own tessellation algorithm.
* <tt>Pod</tt> should draw the [http://ivl.calit2.net/wiki/images/a/a2/Pod.zip OBJ model of a pod]. (3 points)
+
* <tt>Cube</tt> should have a draw function which draws a cube. You can use <tt>[https://www.opengl.org/documentation/specs/glut/spec3/node82.html glutSolidCube]</tt> for that, or use your own implementation of a cube.
  
'''Notes:'''
+
==3. Walking Robot (30 Points)==
* Make sure your Cylinder and Pod classes only load the OBJ models from disk once.
+
  
==3. Building the Wedding Cake Ride (20 Points)==
+
Now we are going to finish our robot's geometry. First get your rendering engine ready to recursively traverse the scene graph for rendering by creating a root node of type Group and calling its draw() function with the identity matrix as its parameter.
  
First get your software ready to recursively traverse the scene graph for rendering by creating a root node of type Group and calling its draw() function with the identity matrix as its parameter.
+
Besides the head, the robot should have a torso, arms and legs. This means that it has to consist of at least '''6''' instances of <tt>Geode</tt>-derivatives. You can use the sphere and cube classes for the body parts, and add more shapes as you like (e.g., using any of [https://www.opengl.org/resources/libraries/glut/spec3/node80.html GLUT's pre-defined shapes]). Each <tt>Geode</tt>-derivative should have a <tt>MatrixTransform</tt> before it to position the body part(s) below it in the scene graph. You might want some of your basic shapes, such as spheres and cubes, elongated, rotated, or otherwise deformed, which you should do with separate <tt>MatrixTransform</tt> nodes for (non-uniform) scales, and/or rotations. It is very common to concatenate multiple <tt>MatrixTransform</tt> nodes in a scene graph, each of which doing a separate affine transformation (e.g., one for position, one for scale, one to rotate - each separate MatrixTransforms).
  
Then create the Wedding Cake ride. The ride should have three levels, each with three big arms to hold another three arms with pods at the end, for a total of 27 pods. Use your Cylinder class for the vertical center post, and smaller instances of the Cylinder class for the horizontal arms, and smaller yet Cylinders to hold the pods.
+
Animate the robot to make it look like it is walking: move arms and legs back and forth by rotating around hip and shoulder joints. You can do this by re-calculating rotation matrices every frame by increasing or decreasing the respective angle by a small amount, up to a limit point at which you reverse the direction.
  
In this part of the project you do not need to animate the ride. We'll do that next.
+
==5. Robot Army (15 Points)==
  
'''Grading:'''
+
Test your implementation by constructing a scene which consists of a large amount of robots, at least 100. The robots can all be identical clones, or you can vary their geometry.
* 5 points for vertical main post.
+
* 5 points for the horizontal arms that attach to the main post.
+
* 5 points for the shorter horizontal arms that hold the pods.
+
* 5 points for the pods.
+
  
==4. Animating the Ride (30 Points)==
+
* Distribute the robots on a 2D grid (i.e., place them on a plane with uniform spacing). For 100 robots, use a 10x10 grid.
  
Animate the Wedding Cake ride by modifying the following things (5 points each):
+
* Enable the animation for your robots so that they look like they are walking.
  
* Rotate the entire ride about its center post.
+
* Enable your rotation, pan and scale routines (keyboard or mouse) to allow the user to rotate the grid of 3D objects and zoom in or out.
* Rotate each set of three pods about its center.
+
* Rotate each pod about itself.
+
* Make the main, vertical post extend and contract.
+
* Make the posts that extend horizontally from the center extend their length, independently from each other.
+
* Make the horizontal arms that hold the pods change their lengths, independently from each other.
+
  
'''Notes:'''
+
This image illustrates the grid layout of the robots:
* For the purpose of extending and contracting the arms, don't use scale nodes because they would scale everything below them not only the cylinders. Instead, you could draw two cylinders for each arm, in the same place, and shift them apart to extend the length of the arm.
+
* You don't have to sway the arms or posts individually like the later part in the video.
+
  
==5. Bear Camera (15 Points)==
+
[[Image:robots.png]]
  
Use your Bear data set from the previous project to place the bear in one of the pods. You'll have to downscale it by adding a MatrixTransform node with a scale operation in front of it, and you'll also have to shift it so that it sits in the right place, and you may have to rotate it as well. Fiddle with it so the bear sits comfortably in the pod.
+
==6. Extra Credit (10 Points)==
  
[[File:Bearpod.png|200px]]
+
Implement object level culling, to allow the existence of thousands of instances of your robot, without having to render them all at once.
  
Once Bear is in place, create a camera class for the scene graph and place a camera right in front of the Bear's face, to simulate what he sees(i.e. a POV camera). Add keyboard support('c') to switch between the outside view and the Bear's view. To calculate the camera matrix you will have to find the camera node and traverse the scene graph from this node up to the top, before you start the scene graph traversal to render the geometry.
+
Calculate a bounding sphere (Vector3 for its center point, and a radius) for each of your robots, which contains all parts of the robot. Allow the display of the bounding spheres by rendering them as wireframe spheres with <tt>[https://www.opengl.org/documentation/specs/glut/spec3/node81.html glutWireSphere]</tt>. Enable a keyboard key to toggle the bounding spheres on and off.
  
'''Grading:'''
+
'''Note:''' You do not need to find the tightest possible bounding spheres - that can be rather difficult. Just make them as tight as you reasonably can.
* 5 points for placing the bear in the pod.
+
* 10 points for the camera view from the Bear's perspective.
+
  
==6. Extra Credit: Split Screen (10 Points)==
+
Add view frustum culling using the bounding spheres of the objects. If the bounding sphere of an object is completely outside of the view frustum, the object should be culled (not rendered). Your culling algorithm should make use of a utility function to test whether a bounding sphere intersects with a given plane (the planes of the view frustum), or whether the sphere is entirely on one side of the plane.
  
There are three extra credit options. You can do up to two of them, each of them gets you 5 extra points.
+
Enable a keyboard key to turn culling on and off.
  
# Implement a split screen view which shows both the scene camera, as well as the view from the bear, side by side.
+
Increase the amount of robots by orders of magnitude, by creating a larger array of them. A good portion of the array should be off screen for the culling to be effective. Display the rendering time per frame in your text window, and show that by turning culling on your rendering time decreases.
# Create special event lighting for the Wedding Cake ride. Use at least three spot lights in different colors that are located on the ground and moving to illuminate the ride from different directions, by each following a different pod.
+
# Make the motion of the ride more like in the video: bend the cylinders, extend them out more than just one cylinder length, etc.
+
-->
+

Revision as of 00:28, 22 October 2016

Contents

Project 3: Scene Graph

In this project you will need to implement a scene graph to render an army of robots.

The total score for this project is 100 points. Additionally, you can obtain up to 10 points of extra credit.

1. Sky Box (20 Points)

Start with code that uses your trackball code, and modify it to control the camera instead. (If you didn't get that to work the keyboard controls will suffice.)

Create a sky box for your scene with the robots. A sky box is a large, square box which is drawn around your entire scene. The inside walls of the box have pictures of a sky and a horizon. Sky boxes are typically cubic, which means that they consist of six square textures for the six sides of a cube. Here is a great tutorial for sky boxes in modern OpenGL.

Here is is a nice collection of textures for sky boxes, and here is an even bigger one.

Draw a cubic sky box and make it big enough to hold an entire theme park.

Make sure single-sided rendering (triangle culling) is enabled with these lines somewhere in your code to ensure that you will never see the outside of the box:

glEnable(GL_CULL_FACE); 
glCullFace(GL_BACK); 

Use the following settings for your texture after your first glBindTexture(GL_TEXTURE_CUBE_MAP, id) for correct lighting and filtering settings:

  // Make sure no bytes are padded:
  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

  // Select GL_MODULATE to mix texture with polygon color for shading:
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

  // Use bilinear interpolation:
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

  // Use clamp to edge to hide skybox edges:
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

To familiarize yourself with texture mapping in OpenGL, we provide sample code, which loads a PPM file and uses it as a texture for a quad. If you decide to use one of the above referenced sky box images, you will have to convert them from JPEG to PPM format. The free image processing tool IrfanView for Windows will do this for you. Alternatively, you can use a third party library such as SOIL to natively load JPEG images.

Grading:

  • 5 points for functional camera controls with keyboard or mouse
  • 5 points for the sky box without textures
  • 5 points for the textures
  • 5 points for correct rendering of edges and corners (seamless edges)

2. Scene Graph Engine (20 Points)

To create the parts of the robot (torso, arms, legs), we need to first implement a scene graph structure for our rendering engine. Use the following hierarchy:

Project4F14-scenegraph-half.jpg

The classes should have at least the following functionality:

  • Class Node should be abstract and serve as the common base class. It should implement an abstract draw method: virtual void draw(Matrix4 C) = 0, and also an abstract virtual void update() = 0 method to separate bounding sphere updates from rendering.
  • Group should store a list of pointers to child nodes (std::list<Node*>) and provide functionality to add and remove child nodes (addChild(), removeChild()). Its draw method needs to traverse the list of children and call each child node's draw function.
  • Geode should be an abstract class. It should set OpenGL's ModelView matrix to the current C matrix, and have an abstract render function to render its geometry.
  • MatrixTransform should store a 4x4 transformation matrix M which is multiplied with matrix C, which is passed to the draw method.
  • Sphere should have a draw function which draws a sphere. You can use glutSolidSphere for that, or use your own tessellation algorithm.
  • Cube should have a draw function which draws a cube. You can use glutSolidCube for that, or use your own implementation of a cube.

3. Walking Robot (30 Points)

Now we are going to finish our robot's geometry. First get your rendering engine ready to recursively traverse the scene graph for rendering by creating a root node of type Group and calling its draw() function with the identity matrix as its parameter.

Besides the head, the robot should have a torso, arms and legs. This means that it has to consist of at least 6 instances of Geode-derivatives. You can use the sphere and cube classes for the body parts, and add more shapes as you like (e.g., using any of GLUT's pre-defined shapes). Each Geode-derivative should have a MatrixTransform before it to position the body part(s) below it in the scene graph. You might want some of your basic shapes, such as spheres and cubes, elongated, rotated, or otherwise deformed, which you should do with separate MatrixTransform nodes for (non-uniform) scales, and/or rotations. It is very common to concatenate multiple MatrixTransform nodes in a scene graph, each of which doing a separate affine transformation (e.g., one for position, one for scale, one to rotate - each separate MatrixTransforms).

Animate the robot to make it look like it is walking: move arms and legs back and forth by rotating around hip and shoulder joints. You can do this by re-calculating rotation matrices every frame by increasing or decreasing the respective angle by a small amount, up to a limit point at which you reverse the direction.

5. Robot Army (15 Points)

Test your implementation by constructing a scene which consists of a large amount of robots, at least 100. The robots can all be identical clones, or you can vary their geometry.

  • Distribute the robots on a 2D grid (i.e., place them on a plane with uniform spacing). For 100 robots, use a 10x10 grid.
  • Enable the animation for your robots so that they look like they are walking.
  • Enable your rotation, pan and scale routines (keyboard or mouse) to allow the user to rotate the grid of 3D objects and zoom in or out.

This image illustrates the grid layout of the robots:

Robots.png

6. Extra Credit (10 Points)

Implement object level culling, to allow the existence of thousands of instances of your robot, without having to render them all at once.

Calculate a bounding sphere (Vector3 for its center point, and a radius) for each of your robots, which contains all parts of the robot. Allow the display of the bounding spheres by rendering them as wireframe spheres with glutWireSphere. Enable a keyboard key to toggle the bounding spheres on and off.

Note: You do not need to find the tightest possible bounding spheres - that can be rather difficult. Just make them as tight as you reasonably can.

Add view frustum culling using the bounding spheres of the objects. If the bounding sphere of an object is completely outside of the view frustum, the object should be culled (not rendered). Your culling algorithm should make use of a utility function to test whether a bounding sphere intersects with a given plane (the planes of the view frustum), or whether the sphere is entirely on one side of the plane.

Enable a keyboard key to turn culling on and off.

Increase the amount of robots by orders of magnitude, by creating a larger array of them. A good portion of the array should be off screen for the culling to be effective. Display the rendering time per frame in your text window, and show that by turning culling on your rendering time decreases.