Due Wednesday 2/12 at 11:59 pm. You must work individually.
Learn and apply hierarchical 3D transformations using the matrix stack.
Write a program that allows you to create a robot that you can manipulate with the keyboard. You are free to create your own robotic character, but there should be at least 10 components in the robot, and the hierarchy should not be flat. For example, in the figures below, we have the following hierarchy:
When a parent component is transformed, all of its descendants should be transformed appropriately. The keyboard control should be as follows:
By pressing the period and comma keys, you should be able to select different components in the hierarchy. You must draw the selected component so that it is distinguishable from unselected components. The x/X, y/Y, and z/Z keys should change the rotation angle of the selected component. In the left figure above, the torso is the selected component, and in the right figure, one of the lower legs is the selected component. Here, the selected component is drawn darker than the unselected components, but you can color it the way you want or draw it slightly bigger.
Start from your Lab 0 code base.
A2
project folder and copy the L00
files and folders into it.CMakeLists.txt
to change the project name (line 4).glfwSetCharCallback()
function.Create a class that represents a component. This class should contain the necessary member variables so that you can make a tree data structure out of these components. The root of the tree should represent the torso, which means that transforming the torso transforms everything else.
In addition to the member variables required for the tree hierarchy, the class should also have the following:
vec3
representing the translation of the component’s joint with respect to the parent component’s joint.vec3
representing the current joint angles about the X, Y, and Z axes of the component’s joint. (You may want to start with Z-rotations only.)vec3
representing the translation of the component’s mesh with respect to its joint.vec3
representing the X, Y, and Z scaling factors for the mesh.The drawing code should be recursive - in other words, in the render()
function in main.cpp
, there should be a single draw call on the root component, and all the other components should be drawn recursively from the root. In the main render()
function, you should create an instance of the matrix stack class and pass it to the root component’s drawing function. Make sure to pass the matrix stack by reference or as a (smart) pointer.
The component’s rendering method should simply take the current state of the component and draw it. You should not create the robot hierarchy in this method. In other words, the scene setup must be done in main’s init()
rather than in main’s render()
. Whenever the keyboard is pressed, the char_callback()
function is called. Update the robot’s joint angles inside this function.
For this assignment, the 3D rotation of the joint should be represented simply as a concatenation of three separate rotation matrices about the x-, y-, and z-axes: Rx * Ry * Rz
. The position of the joint should not be at the center of the box. For example, the elbow joint should be positioned between the upper and lower arms.
You must draw the selected component differently from unselected components. For example, in the images above, the selected component is darker than the other components. You can either change the color (like above) or change the size.
vCol
, which is the vertex color. You will have to modify this line so that the output color becomes different. You will need to pass in a uniform variable so that you can tell if the component you are currently drawing is selected or not.The traversal of the tree with the period and comma keys should be in depth-first or breadth-first order. Do not hardcode this traversal order - your code should be set up so that it works with any tree.
Set the Program class to be verbose by calling the setVerbose()
function. If there is a GLSL compilation error, then you will see the error in the console. For example, if the varying variables of the vertex shader and the fragment shaders do not match up, it will tell you so. Make sure to set verbose to be false after debugging.
Use GLSL::checkError(GET_FILE_LINE);
to find which OpenGL call caused an error. This function will assert if there were any OpenGL errors before getting to this line. You can use this to winnow down which OpenGL function is causing an error. For example, if you put this line at the top, the middle, and the bottom of your function, and if the assertion happens in the middle, you know that the error must be happening in the top half of your function. Once find exactly which OpenGL call is causing the error, you can Google the OpenGL function to figure out what caused the error. For example, maybe one of the arguments should not have been zero or null.
The GLSL compiler will silently optimize away any variables that are not used in the shader. If you try to access these variables at runtime, the program will crash, since these variables no longer exist in the shader. In this lab, when you move the computation of the normal to the GPU, the aNor
variable no longer needs to be passed to the GPU, since it is computed in the shader. Therefore, you will have to comment out any reference to aNor
from your C++ runtime code. Or, you can trick the GLSL compiler from optimizing away aNor
by using it and disgarding it as follows:
vec3 nor = aNor.xyz;
nor.x = ...;
nor.y = ...;
nor.z = ...;
glfwGetTime()
. Animated joints do not need to be controlled with the keyboard.Program
and Shape
classes.Total: 105 points
Failing to follow these points may decrease your “general execution” score. On Linux/Mac, make sure that your code compiles and runs by typing:
> mkdir build
> cd build
> cmake ..
> make
> ./A2 ../resources
If you’re on Windows, make sure that you can build your code using the same procedure as in Lab 0.
src/
, resources/
, CMakeLists.txt
, and your readme file. The resources folder should contain the obj files.(*.~)
, or object files (*.o)
.USERNAME.zip
(e.g., sueda.zip
). The zip file should extract everything into a folder named USERNAME/
(e.g. sueda/
).
src/
, resources/
, CMakeLists.txt
, and your README file to the current directory..zip
format (not .gz
, .7z
, .rar
, etc.).