| CS 381 Fall 2012 > Lecture Notes for Thursday, September 13, 2012 |
Interpolation is determining values between known values. This is in contrast to extrapolation.
Linear interpolation (also called lirping or lerping) finds values using a process that is mathematically equivalent to finding a point on a line segment.
Given \(t\) in the interval \([0,1]\), we can easily find the corresponding \(u\) in the interval \([0,b]\):
\[ u=t\,b. \]
Similarly, if we know \(u\), then we can find \(t\):
\[ t=u/b. \]
Now suppose that the second interval does not have \(0\) as one of its endpoints. Given \(t\) in the interval \([0,1]\), we find \(u\) in the interval \([a,b]\) by linear interpolation using the following formula:
\[ u=a+t\,(b-a). \]
If \(t=0\), then \(u=a\). If \(t=1\), then \(u=b\). If \(t=0.5\), then \(u\) lies halfway between \(a\) and \(b\). And so on.
We can reverse the above by solving the equation for \(t\). Given \(u\), we find \(t\).
\[ t=\frac{u-a}{b-a}. \]
Lastly, we can do linear interpolation involving
two arbitrary intervals
by combining the ideas above.
Given a number \(u\) in \([a,b]\)
we want to linearly interpolate to find a number \(v\)
in \([c,d]\).
There are several ways to do this computation;
all produce the same result.
One way is to apply both of the above formulas,
using \(t\) in \([0,1]\) as an intermediate step.
We would have
\[ t = \frac{u-a}{b-a}; \] \[ v = c+t\,(d-c). \]
The above is identical to the problem of finding a number \(v\)
so that the point \((u,v)\)
lies on the line segment with endpoints
\((a,c)\) and \((b,d)\).
A pointing device is a device that generates a user-controlled, varying 2-D position, which is conceptually mapped to a screen position. Such a device generally also gives us the states of one or more buttons. Of course, there are many kinds of physical pointing devices; but we can treat them identially in our code, and so we usually call them all “the mouse”.
The mouse is shared between all running graphical applications. It is important to consider when our application might be said to “own” the mouse, that is, when should it respond to the mouse, as opposed to letting some other application do so. There are various conventions for this. The one we will follow is that, when no mouse button is down, then we own the mouse if its position is in our window. When a mouse button is down, then we own the mouse if the mouse position was in our window when the button was pressed.
The software interface to a mouse might provide information in two different ways:
GLUT communicates both button-state changes and mouse movements via events—handled via callback functions, as usual. Unlike the keyboard, pressing and releasing a mouse button are two separate events; a button press followed by a release will result in two function calls.
We use four GLUT callbacks when we deal with the mouse.
Note that the rules for calling motion and passiveMotion functions follow our convention above. These are called when the mouse moves, and this movement is relevant to our window. If a button is down, then the motion function is called; otherwise, the passiveMotion function is called.
Register a reshape function using glutReshapeFunc.
Prototype a reshape function as follows.
void myReshape(int w, int h);
Parameters w, h
indicate the new width and height of the drawing area of the window,
in pixels.
A reshape function typically does two things:
The reshape function might also save some of the above information in global variables, so that other callbacks can use it.
Set up the viewport using glViewport.
This takes four parameters: the x and y
of the lower-left-hand corner,
and the width and height, all in pixels.
To set the viewport to the entire drawing area of the window, do this:
glViewport(0, 0, w, h);
Here is code to set up a projection.
glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(wxmin, wxmax, wymin, wymax); glMatrixMode(GL_MODELVIEW);
We first set the matrix mode so that transformation commands
affect the projection transformation.
Then we call glLoadIdentity,
as usual with transformations.
GLU Function gluOrtho2D is a wrapper around
the OpenGL command glOrtho.
This is another transformation command,
just like glTranslate*, etc.
But it is more suited to making projections than to placing objects
in the scene.
Think of this as setting up a coordinate system for the viewport.
The last line is not absolutely necessary; however, I strongly recommend that you do it. It is convenient to be able to assume that we are in model/view mode, except for brief intervals, after which we always go back.
As we develop more sophisticated tools for putting together a GUI, the behavior of a program when a window is resized, becomes more important. And now that know how to write reshape functions, we can make windows behave more nicely.
One common idea for handling resizing is to anchor the display at the upper-left corner of the drawing region. When the window is resized, graphical output is drawn at the same size and aspect ratio, with the same point in the world at the upper-left corner of the window. Some variation of this technique is used in many document-editing programs: word processors, etc.
An idea that works well for games and other interactive animations is to choose a certain portion of the world (say –1 to 1 in both x and y), and ensure that this region is always visible, centered in the window, and drawn with the correct aspect ratio, in a size as large as possible.
Regardless of which idea you use, it is a good idea for your reshape function to save the coordinates used for the projection in global variables, so that other functions can use them.
See
mouse.cpp
for an example of a GLUT reshape function.
Register a mouse function using glutMouseFunc.
Prototype a mouse function as follows.
void myMouse(int button, int state, int x, int y);
Parameter button indicates which button was pressed
or released.
It is one of
GLUT_LEFT_BUTTON,
GLUT_MIDDLE_BUTTON,
GLUT_RIGHT_BUTTON.
Be careful;
there is also a constant GLUT_LEFT,
which is unrelated to the mouse.
In the mouse function, do not forget the “_BUTTON”.
Parameter state indicates the new state of the button.
It is one of GLUT_DOWN, GLUT_UP.
Parameters x, y
indicate the mouse position at the time of the button event,
in pixels from the upper-left corner of the drawing area of the window.
Note that, while OpenGL likes to measure from the bottom-left corner,
GLUT likes to measure from the top-left corner.
These two functions are very similar.
Register a motion function using glutMotionFunc.
Prototype a motion function as follows.
void myMotion(int x, int y);
Register a passiveMotion function using glutPassiveMotionFunc.
Prototype a passiveMotion function as follows.
void myPassiveMotion(int x, int y);
In both case, x, y indicate the new
mouse position, in the same format as the mouse function.
GLUT gives us the mouse position in pixels from the upper-left-hand corner of the drawing area of the window. If we are to use the mouse position in our application, we usually need to convert it to camera coordinates.
Say our viewport width and height are w, h,
respectively,
and we have set up a projection as follows.
gluOrtho2D(wxmin, wxmax, wymin, wymax);
The horizontal mouse position received from GLUT is generally
in the interval
\([0, w]\).
We wish to convert it to
\([\)wxmin\(,\,\)wxmax\(]\).
This is a straightforward linear interpolation.
The vertical mouse position received from GLUT is generally
in the interval
\([0, h]\).
However, remember that GLUT counts from the top of the drawing area,
while OpenGL counts from the bottom.
So the scale to convert to
starts at
wymax, and ends at wymin,
not the other way around.
Lastly, recall that, when a mouse button is down, our application may actually own the mouse even when its position lies outside the window. So the horizontal and vertical mouse positions may not actually lie in the intervals \([0, w]\) and \([0, h]\). But the computation used for the linear interpolation will still work.
See
mouse.cpp
for an example of a GLUT program that uses the mouse.
ggchappell@alaska.edu