📄 chapter01.html
字号:
<P>cube dodecahedron
<P>torus icosahedron
<P>cylinder teapot
<P>cone
<P>You can draw these objects as wireframes or as solid shaded objects
with surface normals defined. For example, the routines for a sphere and
a torus are as follows:
<P>void <B>auxWireSphere</B>(GLdouble <B>radius</B>);
<P>void <B>auxSolidSphere</B>(GLdouble <B>radius</B>);
<P>void <B>auxWireTorus</B>(GLdouble <B>innerRadius</B>, GLdouble <B>outerRadius</B>);
<P>void <B>auxSolidTorus</B>(GLdouble <B>innerRadius</B>, GLdouble <B>outerRadius</B>);
<P>All these models are drawn centered at the origin. When drawn with unit
scale factors, these models fit into a box with all coordinates from -1
to 1. Use the arguments for these routines to scale the objects.
<H4>
Managing a Background Process</H4>
You can specify a function that's to be executed if no other events are
pending - for example, when the event loop would otherwise be idle - with
<B>auxIdleFunc()</B>.
This routine takes a pointer to the function as its only argument. Pass
in zero to disable the execution of the function.
<H4>
Running the Program</H4>
Within your <B>main()</B> routine, call <B>auxMainLoop()</B> and pass it
the name of the routine that redraws the objects in your scene. Example
1-2 shows how you might use the auxiliary library to create the simple
program shown in Example 1-1 .
<P><B>Example 1-2 : </B>A Simple OpenGL Program Using the Auxiliary Library:
simple.c
<PRE>#include <GL/gl.h>
#include "aux.h"
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 500, 500);
auxInitWindow (argv[0]);
glClearColor (0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
glBegin(GL_POLYGON);
glVertex2f(-0.5, -0.5);
glVertex2f(-0.5, 0.5);
glVertex2f(0.5, 0.5);
glVertex2f(0.5, -0.5);
glEnd();
glFlush();
sleep(10);
}</PRE>
<HR>
<H2>
Animation</H2>
One of the most exciting things you can do on a graphics computer is draw
pictures that move. Whether you're an engineer trying to see all sides
of a mechanical part you're designing, a pilot learning to fly an airplane
using a simulation, or merely a computer-game aficionado, it's clear that
animation is an important part of computer graphics.
<P>In a movie theater, motion is achieved by taking a sequence of pictures
(24 per second), and then projecting them at 24 per second on the screen.
Each frame is moved into position behind the lens, the shutter is opened,
and the frame is displayed. The shutter is momentarily closed while the
film is advanced to the next frame, then that frame is displayed, and so
on. Although you're watching 24 different frames each second, your brain
blends them all into a smooth animation. (The old Charlie Chaplin movies
were shot at 16 frames per second and are noticeably jerky.) In fact, most
modern projectors display each picture twice at a rate of 48 per second
to reduce flickering. Computer-graphics screens typically refresh (redraw
the picture) approximately 60 to 76 times per second, and some even run
at about 120 refreshes per second. Clearly, 60 per second is smoother than
30, and 120 is marginally better than 60. Refresh rates faster than 120,
however, are beyond the point of diminishing returns, since the human eye
is only so good.
<P>The key idea that makes motion picture projection work is that when
it is displayed, each frame is complete. Suppose you try to do computer
animation of your million-frame movie with a program like this:
<PRE>open_window();
for (i = 0; i < 1000000; i++) {
clear_the_window();
draw_frame(i);
wait_until_a_24th_of_a_second_is_over();
}</PRE>
If you add the time it takes for your system to clear the screen and to
draw a typical frame, this program gives more and more disturbing results
depending on how close to 1/24 second it takes to clear and draw. Suppose
the drawing takes nearly a full 1/24 second. Items drawn first are visible
for the full 1/24 second and present a solid image on the screen; items
drawn toward the end are instantly cleared as the program starts on the
next frame, so they present at best a ghostlike image, since for most of
the 1/24 second your eye is viewing the cleared background instead of the
items that were unlucky enough to be drawn last. The problem is that this
program doesn't display completely drawn frames; instead, you watch the
drawing as it happens.
<P>An easy solution is to provide double-buffering - hardware or software
that supplies two complete color buffers. One is displayed while the other
is being drawn. When the drawing of a frame is complete, the two buffers
are swapped, so the one that was being viewed is now used for drawing,
and vice versa. It's like a movie projector with only two frames in a loop;
while one is being projected on the screen, an artist is desperately erasing
and redrawing the frame that's not visible. As long as the artist is quick
enough, the viewer notices no difference between this setup and one where
all the frames are already drawn and the projector is simply displaying
them one after the other. With double-buffering, every frame is shown only
when the drawing is complete; the viewer never sees a partially drawn frame.
<P>A modified version of the preceding program that does display smoothly
animated graphics might look like this:
<PRE>open_window_in_double_buffer_mode();
for (i = 0; i < 1000000; i++) {
clear_the_window();
draw_frame(i);
swap_the_buffers();
}</PRE>
In addition to simply swapping the viewable and drawable buffers, the <B>swap_the_buffers()</B>
routine waits until the current screen refresh period is over so that the
previous buffer is completely displayed. This routine also allows the new
buffer to be completely displayed, starting from the beginning. Assuming
that your system refreshes the display 60 times per second, this means
that the fastest frame rate you can achieve is 60 frames per second, and
if all your frames can be cleared and drawn in under 1/60 second, your
animation will run smoothly at that rate.
<P>What often happens on such a system is that the frame is too complicated
to draw in 1/60 second, so each frame is displayed more than once. If,
for example, it takes 1/45 second to draw a frame, you get 30 frames per
second, and the graphics are idle for 1/30-1/45=1/90 second per frame.
Although 1/90 second of wasted time might not sound bad, it's wasted each
1/30 second, so actually one-third of the time is wasted.
<P>In addition, the video refresh rate is constant, which can have some
unexpected performance consequences. For example, with the 1/60 second
per refresh monitor and a constant frame rate, you can run at 60 frames
per second, 30 frames per second, 20 per second, 15 per second, 12 per
second, and so on (60/1, 60/2, 60/3, 60/4, 60/5, ...). That means that
if you're writing an application and gradually adding features (say it's
a flight simulator, and you're adding ground scenery), at first each feature
you add has no effect on the overall performance - you still get 60 frames
per second. Then, all of a sudden, you add one new feature, and your performance
is cut in half because the system can't quite draw the whole thing in 1/60
of a second, so it misses the first possible buffer-swapping time. A similar
thing happens when the drawing time per frame is more than 1/30 second
- the performance drops from 30 to 20 frames per second, giving a 33 percent
performance hit.
<P>Another problem is that if the scene's complexity is close to any of
the magic times (1/60 second, 2/60 second, 3/60 second, and so on in this
example), then because of random variation, some frames go slightly over
the time and some slightly under, and the frame rate is irregular, which
can be visually disturbing. In this case, if you can't simplify the scene
so that all the frames are fast enough, it might be better to add an intentional
tiny delay to make sure they all miss, giving a constant, slower, frame
rate. If your frames have drastically different complexities, a more sophisticated
approach might be necessary.
<P>Interestingly, the structure of real animation programs does not differ
too much from this description. Usually, the entire buffer is redrawn from
scratch for each frame, as it is easier to do this than to figure out what
parts require redrawing. This is especially true with applications such
as three-dimensional flight simulators where a tiny change in the plane's
orientation changes the position of everything outside the window.
<P>In most animations, the objects in a scene are simply redrawn with different
transformations - the viewpoint of the viewer moves, or a car moves down
the road a bit, or an object is rotated slightly. If significant modifications
to a structure are being made for each frame where there's significant
recomputation, the attainable frame rate often slows down. Keep in mind,
however, that the idle time after the <B>swap_the_buffers()</B> routine
can often be used for such calculations.
<P>OpenGL doesn't have a <B>swap_the_buffers()</B> command because the
feature might not be available on all hardware and, in any case, it's highly
dependent on the window system. However, GLX provides such a command, for
use on machines that use the X Window System:
<PRE>void glXSwapBuffers(Display *<B>dpy</B>, Window <B>window</B>);</PRE>
Example 1-3 illustrates the use of <B>glXSwapBuffers()</B> in an example
that draws a square that rotates constantly, as shown in Figure 1-2 .
<P><IMG SRC="figures/doublebuf.gif" ALT="[IMAGE]" NOSAVE HEIGHT=190 WIDTH=662>
<P><B>Figure 1-2 : </B>A Double-Buffered Rotating Square
<BR>
<BR>
<P><B>Example 1-3 : </B>A Double-Buffered Program: double.c
<PRE>#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>
#include "aux.h"
static GLfloat spin = 0.0;
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glRotatef(spin, 0.0, 0.0, 1.0);
glRectf(-25.0, -25.0, 25.0, 25.0);
glPopMatrix();
glFlush();
glXSwapBuffers(auxXDisplay(), auxXWindow());
}
void spinDisplay(void)
{
spin = spin + 2.0;
if (spin > 360.0)
spin = spin - 360.0;
display();
}
void startIdleFunc(AUX_EVENTREC *event)
{
auxIdleFunc(spinDisplay);
}
void stopIdleFunc(AUX_EVENTREC *event)
{
auxIdleFunc(0);
}
void myinit(void)
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glColor3f(1.0, 1.0, 1.0);
glShadeModel(GL_FLAT);
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho (-50.0, 50.0, -50.0*(GLfloat)h/(GLfloat)w,
50.0*(GLfloat)h/(GLfloat)w, -1.0, 1.0);
else
glOrtho (-50.0*(GLfloat)w/(GLfloat)h,
50.0*(GLfloat)w/(GLfloat)h, -50.0, 50.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();
}
int main(int argc, char** argv)
{
auxInitDisplayMode(AUX_DOUBLE | AUX_RGBA);
auxInitPosition(0, 0, 500, 500);
auxInitWindow(argv[0]);
myinit();
auxReshapeFunc(myReshape);
auxIdleFunc(spinDisplay);
auxMouseFunc(AUX_LEFTBUTTON, AUX_MOUSEDOWN, startIdleFunc);
auxMouseFunc(AUX_MIDDLEBUTTON, AUX_MOUSEDOWN, stopIdleFunc);
auxMainLoop(display);
}</PRE>
<HR>
[Previous chapter] <A HREF="chapter02.html">[Next chapter]</A>
<HR>
See the <A HREF="about.html">About</A> page for copyright, authoring
and distribution information.
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -