Where: CSSE 1.22
No appointment needed.
You can complete this lab under Linux or Mac depending on which lab you are in or your own machine. You may need to reboot to choose the operating system. If you use the Linux platform, usethe .cpp and .glsl files supplied under the LINUX_VERSIONS subdirectory.If you use the Mac platform, use the .cpp and .glsl files supplied underthe MAC_VERSIONS subdirectory.
lab1
folder to lab2
- e.g., via:
cd ~/cits3003/labs-examples
cp -r lab1 lab2
q3triangleScene.cpp
to q1square.cpp
and remove the other questions from lab2
(keep them in lab1
!)
mv q3triangleScene.cpp q1square.cpp
rm q1circle.cpp q2pointsScene.cpp
const int NumTriangles = 2;const int NumVertices = 3 * NumTriangles;vec3 points[NumVertices] = { vec3(-0.5, -0.5, 0.0), vec3(-0.5, 0.5, 0.0), vec3(0.5, -0.5, 0.0), vec3(0.5, 0.5, 0.0), vec3(0.5, -0.5, 0.0), vec3(-0.5, 0.5, 0.0)};
Here we use 3D coordinates just to avoid changing it later - for now all z-coordinates are 0.0 (which is what OpenGL defaults to anyway if you draw using vec2's). You'll need to change the second argument in the call to glVertexAttribPointer
from 2
to 3
. This is the number of components per vertex - see the for this function (for other OpenGL functions, see the on the left of this web page).
Use the code above to initialize the triangles and build the program via make
and run it. Compare with:
points
from above):
vec3 colors[NumVertices] = { vec3(0.0, 1.0, 0.0) /* Green, but choose any 6 colours */, ..., ..., vec3(/* ... */), ..., ...};
init
function from example4.cpp
, starting from the comment:
// Create a vertex array object
glEnable( GL_DEPTH_TEST );
init
function and the previous one is that it also sends the color
array to the OpenGL buffer. Then vshader24.glsl
uses this color information via the vColor
shader input variable.
What colours do you get in between the vertices? Experiment with different colours.
Instead we can just pass the angle of rotation to the vertex shader, and have it rotate all the vertex positions by this angle. In fact we can just pass the time (since the program started) to the shader and have it increase the angle over time.
q1square.cpp
to q2sqrotate.cpp
. vshader24.glsl
to vrotate2d.glsl
. Then add the line uniform float time; /* in milliseconds */
to the top of the shader (above main
)
main
function in this vertex shader so that the position is set instead via:float angle = 0.001*time; gl_Position = vec4(vPosition.x*cos(angle) - vPosition.y*sin(angle), vPosition.x*sin(angle) + vPosition.y*cos(angle), 0.0, 1.0);
[Why are there four components in gl_Position? Because OpenGL actually uses 4D homogeneous coordinates - we'll come to this in lectures soon. For now the last component should always be 1.0
.]
Here the angle is in radians, so the square rotates roughly every 6.28 seconds. Why sin
and cos
here? Well, basically because that's what sin
and cos
were invented for!
cos
tells you how much the original (x or y) coordinate affects the same coordinate when rotated.
sin
tells you how much the original (x or y) coordinate affects the other coordinate when rotated. (It's negative in the line for the x coordinate above because the y-axis when rotated clockwise moves towards the negative x-direction.)
See .
InitShader
to use your new vertex shader. GLint
global variable called timeParam
to store the location of the new shader variable time
. Set this global variable in the init
function (after the shaders have been loaded and "used") via:
timeParam = glGetUniformLocation(program, "time");
[This is a uniform variable which means that it doesn't change during the drawing of a primitive, hence no array/buffer is needed unlike vPosition
and vColor
.]
time
variable before the call to glDrawArrays
via:
glUniform1f( timeParam, glutGet(GLUT_ELAPSED_TIME) );
[glUniform1f
sets a uniform parameter containing a single float to a value. Here the value is that returned by glutGet(GLUT_ELAPSED_TIME)
which is the time (in milliseconds) since glutInit was called. See in the (now in the links to the left of this page). ]
void idle(void)
that just calls glutPostRedisplay()
. Then add a call to glutIdleFunc
in main
to set the idle function to this function. [Calling glutPostRedisplay
tells GLUT that the window needs to be redisplayed. Here we call it in the idle function because there is constant motion, so we want to redisplay whenever GLUT/OpenGL has nothing else to do and is idle. The actual redisplay will happen at some point after the idle function returns, when GLUT is ready to redraw the window.
More generally, if you only require redrawing when a mouse event causes an object to move, or similar, you should only call glutPostRedisplay()
when such a change occurs. Calling it multiple times is fine if multiple changes occur before a redraw happens - it just sets a variable that GLUT uses to remember that a redraw is required.]
GLUT_DOUBLE
to the glutInitDisplayMode
call (using bitwise-or, i.e., vertical bar), and replace glFlush()
with glutSwapBuffers()
. This causes double buffering, which prevents flickering. Then again, modern graphics hardware often automatically double buffers, so you may not see any difference, including when you're using the 2.01 lab machines.
Website Feedback:
du(dot)huynh(at)uwa(dot)edu(dot)au