0% found this document useful (0 votes)
6 views4 pages

Lab09

Lab 09 for COMP 1010 focuses on defining functions with parameters and results, specifically for drawing graphics like an octopus and a 3D grid of spheres. Students are encouraged to complete exercises at varying difficulty levels (Bronze, Silver, Gold) with specific coding tasks outlined for each. The lab also introduces concepts of perspective projection and 3D rotations controlled by mouse movements.

Uploaded by

vowivaj524
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views4 pages

Lab09

Lab 09 for COMP 1010 focuses on defining functions with parameters and results, specifically for drawing graphics like an octopus and a 3D grid of spheres. Students are encouraged to complete exercises at varying difficulty levels (Bronze, Silver, Gold) with specific coding tasks outlined for each. The lab also introduces concepts of perspective projection and 3D rotations controlled by mouse movements.

Uploaded by

vowivaj524
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 4

COMP 1010

Lab 09

MATERIAL COVERED
• Defining functions with parameters and results

Notes:
• Make sure your TA has recorded your mark before leaving.
• Remember that you only need to do one of the three levels (Bronze, Silver, or Gold) to obtain 2/2
on the lab, although you are encouraged to do as many as you can.
• In this lab, the Gold exercise cannot be done without first completing the Silver exercise. The
Bronze exercise is independent.
• The Silver and Gold exercises are not as difficult as they appear. The Silver exercise can be done
by adding only 9 lines of code. The Gold requires only 10-15 more.

In this exercise, you will draw an “octopus” graphic at the mouse


location, as shown to the right. [Optionally, you can make a “waving
octopus” – see the next page.]
Download the file Lab9BronzeTemplate.pde which contains the
global constants and variables mentioned below, and use that as the
starting point for your program.
Phase 1: Draw NUM_ARMS “arms”, each consisting of a line of
CIRCLES_PER_ARM small circles, with diameter CIRCLE_SIZE. The
values 8, 5, and 10 are used in the image on the right. Make the arms
stick straight out from the mouse position. The centre of each circle in
an arm should be a distance of CIRCLE_SPACING pixels from the centres of the adjacent circles in
the same arm (or from the mouse position, in the case of the closest circle). Do this by completing
the following two small functions, exactly as specified.
void drawCircle(float theta, float distance, float xc, float yc) This
function should draw one circle, with the current stroke and fill colours, and diameter
CIRCLE_SIZE. It should draw it at a distance of distance away from the point (xc,yc), in the
direction given by theta (an angle in radians, with 0 degrees being straight out to the right, and
moving clockwise from there). For example, drawCircle(PI/2, 100, 50, 50) should draw
a circle with its centre at (50,150) – straight down (an angle of 90 degrees or PI/2 radians) from
(50,50), at a distance of 100 pixels.
void drawOctopus(float x, float y) This function should use two nested for loops to
draw an “octopus” with its centre at (x,y), using the constants mentioned above. It should use your
your drawCircle function to draw all of the circles that make up the “octopus”. The arms should
be equally spaced – that is, they should stick out at evenly-spaced angles in a circle around (x,y).
Call drawOctopus from the draw() function to make it draw an octopus at the mouse location.
Phase 2 (optional, but fun): Make the arms wave. Use a slightly
different angle (theta) for each of the circles that make up an arm,
so that the arm curves, instead of sticking straight out. Change the
drawOctopus function to be void drawOctopus(float
warp, float x, float y). Add warp to the angle of the first
(closest) circle in an arm, 2*warp to the angle for the second one,
3*warp to the angle for the third one, etc. If warp=0 then the arms
will be straight, as before, but larger or smaller values for warp will
make the arms curve to the right or left. (They may no longer be
exactly distance apart, but that’s OK.)
Now change the draw() function to use a varying warp value from
one frame to the next. For the first frame, use a value of 0, as given in the template file. Every
frame, warpSpeed should be added to the amount of warp, until it reaches WARP_LIMIT. Then the
warp value should start to decrease, going back to 0 and continuing down to –WARP_LIMIT, at
which point it should start to increase again, repeating the cycle forever. Hint: Note that
warpSpeed is a variable, not a constant, so that its value can change from positive to negative and
back again.

3D! Computer screens are not capable of doing real 3D – they’re flat!
Anything “3D” you see on a computer screen is an illusion –
completely faked. There are a lot of great ways to fake 3D, and to trick
people’s eyes into seeing 3D. One of the most fundamental ways is by
simulating perspective:
• Objects that are further away appear to be smaller
• Objects that move further away appear to converge.
Look at the railroad image. Because of perspective, the tracks appear
to get closer together as they get further away. The point where they
appear to meet each other in the distance is the “vanishing point”.
Also, the trees in the distance are not much bigger in the picture than a
single railroad tie in the foreground. Our brains pick up on these cues
and we know that this is actually a 3D scene because we know that the
tree is really much bigger than the tie.
We will draw a 3D grid of “spheres” (circles when drawn in 2D), as shown in the image on the
next page. Start with the file Lab9SilverTemplate.pde, which will provide the necessary
constant mentioned below, as well as the setup and draw functions.
We have used “flat” 2D (x,y) coordinates a lot. To use 3D, we need to add a z
coordinate to get (x,y,z). Look at the diagram to the right. Our usual X axis goes to
the right across your screen, and the Y axis goes downward on your screen. The
new Z axis goes straight into your screen, away from you. These are virtual
coordinates – they’re not measured in pixels, and our screen does not really have a
z axis, so what we need to do is project our virtual 3D points (x,y,z) onto normal
2D canvas points (px,py). (“px” means “projected x” or maybe “pixels x”).
[Note: Processing has a built-in way to handle 3D points, but we won’t use that here. We’ll stick to
what we know, and do it ourselves. You can investigate Processing’s 3D capabilities on your own,
if you’re interested.]
The basic idea behind perspective projection is to simply divide the x and y coordinates by the z
coordinate to get px and py. That way, the larger the z coordinate is, the more px and py will
decrease, and appear to move toward the “vanishing point” (0,0) – as the railroad tracks did.
But if we just divide by z itself, our px and py coordinates
will get very small very quickly and you’ll only see a
cluster of dots at the center of the screen. Use the constant
PERSPECTIVE (set at 0.002) to control the amount of
perspective (how fast px and py converge as z gets larger).
Divide x and y by PERSPECTIVE*z instead of just z to get
px and py. Object sizes (such as the diameter of a circle or
sphere) also must be divided by PERSPECTIVE*z in the
same way, since objects also must appear smaller when
they are farther away.
Note that because PERSPECTIVE is a very small number
(0.002), any z value less than 500 will cause things to
grow, not shrink. Our illusion works best when we look at
objects far away “into the screen”, not directly in front of
our noses, and so we’ll usually want z values that are quite large compared to x and y.
Write a function void drawProjectedCircle(float x, float y, float z, float
diam) which draw a “sphere” (a small circle, really) with its centre at the 3D point (x,y,z), and a
diameter of diam. Use the projection method described above to modify x, y, and diam before
drawing the circle. Add an offset so that the “vanishing point” (0,0) is moved to the centre of the
canvas.
There is one potential problem here. If you happen to get z=0, you will divide by 0 and the result
will be Infinity! (At z=0 things are so close that they appear to be infinitely large – they’re right
in the middle of your eyeball! And z<0 is even worse – beyond infinity?) You need what is called
a “clipping plane” in graphics. Your drawProjectedCircle function shouldn’t attempt to draw
(or even do the calculations) for any circle unless z>0! Just ignore such circles. They're “behind
your head” and you can't see them.
Now write a function void drawDotGrid(int minValue, int maxValue, int spacing,
float diam), to draw a three-dimensional cube of spheres (circles) with diameter diam units.
Use three nested for loops to generate a cube of all possible (x,y,z) points in a grid. Every one of
the three coordinates should be a value between minValue and maxValue, spaced spacing units
apart. For example, drawDotGrid(-35,35,10,1) should use the values -35, -25, -15, -5, +5,
+15, +25, and +35 for x, y, and z, in all possible combinations (a total of 8*8*8 = 512 points). This
function should use drawProjectedCircle to do all of the drawing. Since we want large z
values, and we also want to be able to use the mouse to zoom in and out, simply add mouseX to
the z coordinates before you call drawProjectedCircle to draw the circles.
Once your Silver exercise is working, add 3D rotations to
it, controlled by the mouse!
First, add a constant “zoom factor” of 150 to all z co-
ordinates, instead of mouseX as was done in the Silver
program. We’ll need the mouse to do other things, and 150
will “push” the cube just far enough “into the screen” to
give it a nice size. You could experiment with other
values, too. (You were going to use a named constant,
right?)
To rotate a 2D point (x,y) an angle of θ radians around the
centre of rotation (0,0), giving a new point (rx,ry), the
math is not very complicated (rx is short for “rotated x”):
𝑟𝑥 = 𝑥 𝑐𝑜𝑠(𝜃) + 𝑦 𝑠𝑖𝑛(𝜃)
𝑟𝑦 = −𝑥 𝑠𝑖𝑛(𝜃) + 𝑦 𝑐𝑜𝑠(𝜃)
To rotate a 3D point (x,y,z) around the X axis (think of grabbing the X axis and spinning it), just
leave the x coordinate unchanged, and use the above formulae with y and z instead of x and y.
Similarly, to rotate the point around the Y axis, use the formulae with x and z, leaving y untouched.
Using the formulae exactly as they are above will spin around the Z axis.
Write a function void rotate(float theta, float a, float b) which will rotate a point
(a,b) around the point (0,0) by an angle of theta radians, using the formulae above, giving a new
point (newA,newB). This function could be used with x and y, or x and z, or y and z, so let’s just
call them a and b to make them generic. Now we run into a problem with returning results from
functions – only one value can be returned, and we need to return two (newA and newB). There is a
way to solve this, but it’s not covered in COMP 1010, so instead create two global variables newA
and newB and put the answers there. It’s not the “proper” way to do it, but it will work.
Now modify the drawDotGrid function to use the mouse to spin the cube. Before drawing each
circle, use your rotate function to spin it mouseX/100.0 radians around the Y axis, and then
(height-mouseY)/100.0 radians around the X axis. (If this seems backwards, just think about it
and visualize it – it’s correct.) The spinning must be done before you add the “zoom” factor of 150
to the z co-ordinate.
You should now be able to “grab” the cube and spin it with the mouse.

You might also like