Open GL Super Bible
Listing 63 Code from POINTSZ that produces a spiral with gradually increasing point sizes // Define a constant for the value of PI #define GL_PI 3.1415f // Called to draw scene void RenderScene(void) { GLfloat x,y,z,angle; // Storage for coordinates and angles GLfloat sizes[2]; // Store supported point size range GLfloat step; // Store supported point size increments GLfloat curSize; // Store current point size … … // Get supported point size range and step size glGetFloatv(GL_POINT_SIZE_RANGE,sizes); glGetFloatv(GL_POINT_SIZE_GRANULARITY,&step); // Set the initial point size curSize = sizes[0]; // Set beginning z coordinate z = 50.0f; // Loop around in a circle three times for(angle = 0.0f; angle <= (2.0f*GL_PI)*3.0f; angle += 0.1f) { // Calculate x and y values on the circle x = 50.0f*sin(angle); y = 50.0f*cos(angle); // Specify the point size before the primitive is specified glPointSize(curSize); // Draw the point glBegin(GL_POINTS); glVertex3f(x, y, z); glEnd(); // Bump up the z value and the point size z += 0.5f; curSize += step; } … … } This example demonstrates a couple of important things. For starters, notice that glPointSize must be called outside the glBegin/glEnd statements. Not all OpenGL functions are valid between these function calls. Though glPointSize affects all points drawn after it, you don’t begin drawing points until you call glBegin(GL_POINTS). For a complete list of valid functions that you can call within a glBegin/glEnd sequence, see the Reference Section. The most obvious thing you probably noticed about the POINTSZ excerpt is that the larger point sizes are represented simply by larger squares. This is the default behavior, but it typically is undesirable for many applications. Also, you may be wondering why you can increase the point size by a value less than one. If a value of 1.0 represents one pixel, how do you draw less than a pixel or, say, 2.5 pixels? The answer is that the point size specified in glPointSize isn’t the exact point size in pixels, but the approximate diameter of a circle containing all the pixels that will be used to draw the point. You can get OpenGL to draw the points as better points (that is, small filled circles) by enabling point smoothing, with a call to glEnable(GL_POINT_SMOOTH); Other functions affect how points and lines are smoothed, but this falls under the larger topic of antialiasing (Chapter 16). Antialiasing is a technique used to smooth out jagged edges and round out corners. We mention it now only in case you want to play with this on your own, and to whet your appetite for the rest of the book! Drawing Lines in 3DThe GL_POINTS primitive we have been using thus far is pretty straightforward; for each vertex specified, it draws a point. The next logical step is to specify two vertices and draw a line between them. This is exactly what the next primitive, GL_LINES, does. The following short section of code draws a single line between two points (0,0,0) and (50, 50, 50): glBegin(GL_LINES); glVertex3f(0.0f, 0.0f, 0.0f); glVertex3f(50.0f, 50.0f, 50.0f); glEnd(); Note here that two vertices are used to specify a single primitive. For every two vertices specified, a single line is drawn. If you specify an odd number of vertices for GL_LINES, the last vertex is just ignored. Listing 64, from the LINES sample program on the CD, shows a more complex sample that draws a series of lines fanned around in a circle. The output from this program is shown in Figure 65.
Listing 64 Code from the sample program LINES that displays a series of lines fanned in a circle // Call only once for all remaining points glBegin(GL_LINES); // All lines lie in the xy plane. z = 0.0f; for(angle = 0.0f; angle <= GL_PI*3.0f; angle += 0.5f) { // Top half of the circle x = 50.0f*sin(angle); y = 50.0f*cos(angle); glVertex3f(x, y, z); // First end point of line // Bottom half of the circle x = 50.0f*sin(angle+3.1415f); y = 50.0f*cos(angle+3.1415f); glVertex3f(x, y, z); // Second end point of line } // Done drawing points glEnd(); Line Strips and LoopsThe next two OpenGL primitives build on GL_LINES by allowing you to specify a list of vertices through which a line is drawn. When you specify GL_LINE_STRIP, a line is drawn from one vertex to the next in a continuous segment. The following code draws two lines in the xy plane that are specified by three vertices. Figure 66 shows an example. glBegin(GL_LINE_STRIP); glVertex3f(0.0f, 0.0f, 0.0f); // V0 glVertex3f(50.0f, 50.0f, 0.0f); // V1 glVertex3f(50.0f, 100.0f, 0.0f); // V2 glEnd();
The last linebased primitive is the GL_LINE_LOOP. This primitive behaves just like a GL_LINE_STRIP, but one final line is drawn between the last vertex specified and the first one specified. This is an easy way to draw a closedline figure. Figure 67 shows a GL_LINE_LOOP drawn using the same vertices as for the GL_LINE_STRIP in Figure 66.
Approximating Curves with Straight LinesThe POINTS example program, shown earlier in Figure 63, showed you how to plot points along a springshaped path. You may have been tempted to push the points closer and closer together (by setting smaller values for the angle increment) to create a smooth springshaped curve instead of the broken points that only approximated the shape. This is a perfectly valid operation, but it can be quite slow for larger and more complex curves with thousands of points.
